cmdlib: Add new opcode to migrate node
authorMichael Hanselmann <hansmi@google.com>
Thu, 30 Jul 2009 15:52:49 +0000 (17:52 +0200)
committerMichael Hanselmann <hansmi@google.com>
Fri, 31 Jul 2009 11:30:48 +0000 (13:30 +0200)
It migrates all primary instances from the node to their secondaries.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>

lib/cmdlib.py
lib/mcpu.py
lib/opcodes.py

index a45c268..0ecaa0c 100644 (file)
@@ -709,6 +709,19 @@ def _CheckInstanceBridgesExist(lu, instance, node=None):
   _CheckNicsBridgesExist(lu, instance.nics, node)
 
 
+def _GetNodePrimaryInstances(cfg, node_name):
+  """Returns primary instances on a node.
+
+  """
+  instances = []
+
+  for (_, inst) in cfg.GetAllInstancesInfo().iteritems():
+    if node_name == inst.primary_node:
+      instances.append(inst)
+
+  return instances
+
+
 def _GetNodeSecondaryInstances(cfg, node_name):
   """Returns secondary instances on a node.
 
@@ -3941,6 +3954,60 @@ class LUMigrateInstance(LogicalUnit):
     return env, nl, nl
 
 
+class LUMigrateNode(LogicalUnit):
+  """Migrate all instances from a node.
+
+  """
+  HPATH = "node-migrate"
+  HTYPE = constants.HTYPE_NODE
+  _OP_REQP = ["node_name", "live"]
+  REQ_BGL = False
+
+  def ExpandNames(self):
+    self.op.node_name = self.cfg.ExpandNodeName(self.op.node_name)
+    if self.op.node_name is None:
+      raise errors.OpPrereqError("Node '%s' not known" % self.op.node_name)
+
+    self.needed_locks = {
+      locking.LEVEL_NODE: [self.op.node_name],
+      }
+
+    self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_APPEND
+
+    # Create tasklets for migrating instances for all instances on this node
+    names = []
+    tasklets = []
+
+    for inst in _GetNodePrimaryInstances(self.cfg, self.op.node_name):
+      logging.debug("Migrating instance %s", inst.name)
+      names.append(inst.name)
+
+      tasklets.append(TLMigrateInstance(self, inst.name, self.op.live, False))
+
+    self.tasklets = tasklets
+
+    # Declare instance locks
+    self.needed_locks[locking.LEVEL_INSTANCE] = names
+
+  def DeclareLocks(self, level):
+    if level == locking.LEVEL_NODE:
+      self._LockInstancesNodes()
+
+  def BuildHooksEnv(self):
+    """Build hooks env.
+
+    This runs on the master, the primary and all the secondaries.
+
+    """
+    env = {
+      "NODE_NAME": self.op.node_name,
+      }
+
+    nl = [self.cfg.GetMasterNode()]
+
+    return (env, nl, nl)
+
+
 class TLMigrateInstance(Tasklet):
   def __init__(self, lu, instance_name, live, cleanup):
     """Initializes this class.
@@ -4253,6 +4320,8 @@ class TLMigrateInstance(Tasklet):
     """Perform the migration.
 
     """
+    feedback_fn("Migrating instance %s" % self.instance.name)
+
     self.feedback_fn = feedback_fn
 
     self.source_node = self.instance.primary_node
index 27e5ca3..ef23091 100644 (file)
@@ -58,6 +58,7 @@ class Processor(object):
     opcodes.OpSetNodeParams: cmdlib.LUSetNodeParams,
     opcodes.OpPowercycleNode: cmdlib.LUPowercycleNode,
     opcodes.OpEvacuateNode: cmdlib.LUEvacuateNode,
+    opcodes.OpMigrateNode: cmdlib.LUMigrateNode,
     # instance lu
     opcodes.OpCreateInstance: cmdlib.LUCreateInstance,
     opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance,
index e49d0be..f39d9cb 100644 (file)
@@ -360,6 +360,16 @@ class OpEvacuateNode(OpCode):
     ]
 
 
+class OpMigrateNode(OpCode):
+  """Migrate all instances from a node."""
+  OP_ID = "OP_NODE_MIGRATE"
+  OP_DSC_FIELD = "node_name"
+  __slots__ = OpCode.__slots__ + [
+    "node_name",
+    "live",
+    ]
+
+
 # instance opcodes
 
 class OpCreateInstance(OpCode):