Remove useless code in backend for network hooks
[ganeti-local] / tools / move-instance
index dda8798..24bb496 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2010 Google Inc.
+# Copyright (C) 2010, 2011, 2012 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 
 """
 
-# pylint: disable-msg=C0103
+# pylint: disable=C0103
 # C0103: Invalid name move-instance
 
 import os
@@ -36,11 +36,13 @@ from ganeti import cli
 from ganeti import constants
 from ganeti import utils
 from ganeti import workerpool
+from ganeti import objects
 from ganeti import compat
 from ganeti import rapi
 
-import ganeti.rapi.client # pylint: disable-msg=W0611
+import ganeti.rapi.client # pylint: disable=W0611
 import ganeti.rapi.client_utils
+from ganeti.rapi.client import UsesRapiClient
 
 
 SRC_RAPI_PORT_OPT = \
@@ -269,7 +271,8 @@ class InstanceMove(object):
 
   """
   def __init__(self, src_instance_name, dest_instance_name,
-               dest_pnode, dest_snode, dest_iallocator):
+               dest_pnode, dest_snode, dest_iallocator,
+               hvparams, beparams, osparams, nics):
     """Initializes this class.
 
     @type src_instance_name: string
@@ -282,6 +285,14 @@ class InstanceMove(object):
     @param dest_snode: Name of secondary node on destination cluster
     @type dest_iallocator: string or None
     @param dest_iallocator: Name of iallocator to use
+    @type hvparams: dict or None
+    @param hvparams: Hypervisor parameters to override
+    @type beparams: dict or None
+    @param beparams: Backend parameters to override
+    @type osparams: dict or None
+    @param osparams: OS parameters to override
+    @type nics: dict or None
+    @param nics: NICs to override
 
     """
     self.src_instance_name = src_instance_name
@@ -289,6 +300,10 @@ class InstanceMove(object):
     self.dest_pnode = dest_pnode
     self.dest_snode = dest_snode
     self.dest_iallocator = dest_iallocator
+    self.hvparams = hvparams
+    self.beparams = beparams
+    self.osparams = osparams
+    self.nics = nics
 
     self.error_message = None
 
@@ -414,7 +429,9 @@ class MoveDestExecutor(object):
     job_id = self._CreateInstance(dest_client, mrt.move.dest_instance_name,
                                   mrt.move.dest_pnode, mrt.move.dest_snode,
                                   mrt.move.dest_iallocator,
-                                  mrt.src_instinfo, mrt.src_expinfo)
+                                  mrt.src_instinfo, mrt.src_expinfo,
+                                  mrt.move.hvparams, mrt.move.beparams,
+                                  mrt.move.beparams, mrt.move.nics)
     mrt.PollJob(dest_client, job_id,
                 remote_import_fn=compat.partial(self._SetImportInfo, mrt))
 
@@ -437,7 +454,9 @@ class MoveDestExecutor(object):
       mrt.dest_to_source.release()
 
   @staticmethod
-  def _CreateInstance(cl, name, snode, pnode, iallocator, instance, expinfo):
+  def _CreateInstance(cl, name, pnode, snode, iallocator, instance, expinfo,
+                      override_hvparams, override_beparams, override_osparams,
+                      override_nics):
     """Starts the instance creation in remote import mode.
 
     @type cl: L{rapi.client.GanetiRapiClient}
@@ -454,22 +473,39 @@ class MoveDestExecutor(object):
     @param instance: Instance details from source cluster
     @type expinfo: dict
     @param expinfo: Prepared export information from source cluster
+    @type override_hvparams: dict or None
+    @param override_hvparams: Hypervisor parameters to override
+    @type override_beparams: dict or None
+    @param override_beparams: Backend parameters to override
+    @type override_osparams: dict or None
+    @param override_osparams: OS parameters to override
+    @type override_nics: dict or None
+    @param override_nics: NICs to override
     @return: Job ID
 
     """
     disk_template = instance["disk_template"]
 
     disks = [{
-      "size": i["size"],
-      "mode": i["mode"],
+      constants.IDISK_SIZE: i["size"],
+      constants.IDISK_MODE: i["mode"],
       } for i in instance["disks"]]
 
     nics = [{
-      "ip": ip,
-      "mac": mac,
-      "mode": mode,
-      "link": link,
-      } for ip, mac, mode, link in instance["nics"]]
+      constants.INIC_IP: ip,
+      constants.INIC_MAC: mac,
+      constants.INIC_MODE: mode,
+      constants.INIC_LINK: link,
+      constants.INIC_NETWORK: network
+      } for ip, mac, mode, link, network, _ in instance["nics"]]
+
+    if len(override_nics) > len(nics):
+      raise Error("Can not create new NICs")
+
+    if override_nics:
+      assert len(override_nics) <= len(nics)
+      for idx, (nic, override) in enumerate(zip(nics, override_nics)):
+        nics[idx] = objects.FillDict(nic, override)
 
     # TODO: Should this be the actual up/down status? (run_state)
     start = (instance["config_state"] == "up")
@@ -477,6 +513,18 @@ class MoveDestExecutor(object):
     assert len(disks) == len(instance["disks"])
     assert len(nics) == len(instance["nics"])
 
+    inst_beparams = instance["be_instance"]
+    if not inst_beparams:
+      inst_beparams = {}
+
+    inst_hvparams = instance["hv_instance"]
+    if not inst_hvparams:
+      inst_hvparams = {}
+
+    inst_osparams = instance["os_instance"]
+    if not inst_osparams:
+      inst_osparams = {}
+
     return cl.CreateInstance(constants.INSTANCE_REMOTE_IMPORT,
                              name, disk_template, disks, nics,
                              os=instance["os"],
@@ -489,8 +537,12 @@ class MoveDestExecutor(object):
                              source_handshake=expinfo["handshake"],
                              source_x509_ca=expinfo["x509_ca"],
                              source_instance_name=instance["name"],
-                             beparams=instance["be_instance"],
-                             hvparams=instance["hv_instance"])
+                             beparams=objects.FillDict(inst_beparams,
+                                                       override_beparams),
+                             hvparams=objects.FillDict(inst_hvparams,
+                                                       override_hvparams),
+                             osparams=objects.FillDict(inst_osparams,
+                                                       override_osparams))
 
 
 class MoveSourceExecutor(object):
@@ -612,7 +664,7 @@ class MoveSourceExecutor(object):
 
 
 class MoveSourceWorker(workerpool.BaseWorker):
-  def RunTask(self, rapi_factory, move): # pylint: disable-msg=W0221
+  def RunTask(self, rapi_factory, move): # pylint: disable=W0221
     """Executes an instance move.
 
     @type rapi_factory: L{RapiClientFactory}
@@ -646,7 +698,7 @@ class MoveSourceWorker(workerpool.BaseWorker):
                               (mrt.src_error_message, mrt.dest_error_message))
       else:
         move.error_message = None
-    except Exception, err: # pylint: disable-msg=W0703
+    except Exception, err: # pylint: disable=W0703
       logging.exception("Caught unhandled exception")
       move.error_message = str(err)
 
@@ -667,33 +719,6 @@ def CheckRapiSetup(rapi_factory):
   logging.info("Destination cluster RAPI version: %s", dest_client.GetVersion())
 
 
-def SetupLogging(options):
-  """Setting up logging infrastructure.
-
-  @param options: Parsed command line options
-
-  """
-  fmt = "%(asctime)s: %(threadName)s "
-  if options.debug or options.verbose:
-    fmt += "%(levelname)s "
-  fmt += "%(message)s"
-
-  formatter = logging.Formatter(fmt)
-
-  stderr_handler = logging.StreamHandler()
-  stderr_handler.setFormatter(formatter)
-  if options.debug:
-    stderr_handler.setLevel(logging.NOTSET)
-  elif options.verbose:
-    stderr_handler.setLevel(logging.INFO)
-  else:
-    stderr_handler.setLevel(logging.ERROR)
-
-  root_logger = logging.getLogger("")
-  root_logger.setLevel(logging.NOTSET)
-  root_logger.addHandler(stderr_handler)
-
-
 def ParseOptions():
   """Parses options passed to program.
 
@@ -707,6 +732,10 @@ def ParseOptions():
   parser.add_option(cli.DEBUG_OPT)
   parser.add_option(cli.VERBOSE_OPT)
   parser.add_option(cli.IALLOCATOR_OPT)
+  parser.add_option(cli.BACKEND_OPT)
+  parser.add_option(cli.HVOPTS_OPT)
+  parser.add_option(cli.OSPARAMS_OPT)
+  parser.add_option(cli.NET_OPT)
   parser.add_option(SRC_RAPI_PORT_OPT)
   parser.add_option(SRC_CA_FILE_OPT)
   parser.add_option(SRC_USERNAME_OPT)
@@ -756,13 +785,24 @@ def CheckOptions(parser, options, args):
             options.dest_primary_node or
             options.dest_secondary_node):
       parser.error("An iallocator or the destination node is required")
+
+    if options.hvparams:
+      utils.ForceDictType(options.hvparams, constants.HVS_PARAMETER_TYPES)
+
+    if options.beparams:
+      utils.ForceDictType(options.beparams, constants.BES_PARAMETER_TYPES)
+
+    if options.nics:
+      options.nics = cli.ParseNicOption(options.nics)
   else:
     # Moving more than one instance
     if (options.dest_instance_name or options.dest_primary_node or
-        options.dest_secondary_node):
-      parser.error("The options --dest-instance-name, --dest-primary-node and"
-                   " --dest-secondary-node can only be used when moving exactly"
-                   " one instance")
+        options.dest_secondary_node or options.hvparams or
+        options.beparams or options.osparams or options.nics):
+      parser.error("The options --dest-instance-name, --dest-primary-node,"
+                   " --dest-secondary-node, --hypervisor-parameters,"
+                   " --backend-parameters, --os-parameters and --net can"
+                   " only be used when moving exactly one instance")
 
     if not options.iallocator:
       parser.error("An iallocator must be specified for moving more than one"
@@ -771,14 +811,14 @@ def CheckOptions(parser, options, args):
   return (src_cluster_name, dest_cluster_name, instance_names)
 
 
-@rapi.client.UsesRapiClient
+@UsesRapiClient
 def main():
   """Main routine.
 
   """
   (parser, options, args) = ParseOptions()
 
-  SetupLogging(options)
+  utils.SetupToolLogging(options.debug, options.verbose, threadname=True)
 
   (src_cluster_name, dest_cluster_name, instance_names) = \
     CheckOptions(parser, options, args)
@@ -796,6 +836,9 @@ def main():
   assert len(instance_names) == 1 or options.iallocator
   assert (len(instance_names) > 1 or options.iallocator or
           options.dest_primary_node or options.dest_secondary_node)
+  assert (len(instance_names) == 1 or
+          not (options.hvparams or options.beparams or options.osparams or
+               options.nics))
 
   # Prepare list of instance moves
   moves = []
@@ -810,7 +853,9 @@ def main():
     moves.append(InstanceMove(src_instance_name, dest_instance_name,
                               options.dest_primary_node,
                               options.dest_secondary_node,
-                              options.iallocator))
+                              options.iallocator, options.hvparams,
+                              options.beparams, options.osparams,
+                              options.nics))
 
   assert len(moves) == len(instance_names)