From: Apollon Oikonomopoulos <[email protected]> Modify LUMigrateInstance and TLMigrateInstance to allow instance migrations for instances with DTS_EXT_MIRROR disk templates.
Migrations of shared storage instances require either a target node, or an iallocator to determine the target node. Signed-off-by: Apollon Oikonomopoulos <[email protected]> --- lib/backend.py | 10 +++++ lib/cmdlib.py | 118 ++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 103 insertions(+), 25 deletions(-) diff --git a/lib/backend.py b/lib/backend.py index cc6542d..4eda921 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -1224,10 +1224,20 @@ def AcceptInstance(instance, info, target): @param target: target host (usually ip), on this node """ + if instance.disk_template in constants.DTS_EXT_MIRROR: + # Create the symlinks, as the disks are not active + # in any way + try: + _GatherAndLinkBlockDevs(instance) + except errors.BlockDeviceError, err: + _Fail("Block device error: %s", err, exc=True) + hyper = hypervisor.GetHypervisor(instance.hypervisor) try: hyper.AcceptInstance(instance, info, target) except errors.HypervisorError, err: + if instance.disk_template in constants.DTS_EXT_MIRROR: + _RemoveBlockDevLinks(instance.name, instance.disks) _Fail("Failed to accept instance: %s", err, exc=True) diff --git a/lib/cmdlib.py b/lib/cmdlib.py index c39b30d..1d645fb 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -5179,11 +5179,15 @@ class LUMigrateInstance(LogicalUnit): def ExpandNames(self): self._ExpandAndLockInstance() + if self.op.target_node is not None: + self.op.target_node = _ExpandNodeName(self.cfg, self.op.target_node) + self.needed_locks[locking.LEVEL_NODE] = [] self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE self._migrater = TLMigrateInstance(self, self.op.instance_name, - self.op.live, self.op.cleanup) + self.op.live, self.op.cleanup, + self.op.iallocator, self.op.target_node) self.tasklets = [self._migrater] def DeclareLocks(self, level): @@ -5198,16 +5202,21 @@ class LUMigrateInstance(LogicalUnit): """ instance = self._migrater.instance source_node = instance.primary_node - target_node = instance.secondary_nodes[0] + target_node = self._migrater.target_node env = _BuildInstanceHookEnvByObject(self, instance) env["MIGRATE_LIVE"] = self.op.live env["MIGRATE_CLEANUP"] = self.op.cleanup env.update({ "OLD_PRIMARY": source_node, - "OLD_SECONDARY": target_node, "NEW_PRIMARY": target_node, - "NEW_SECONDARY": source_node, }) + + if instance.disk_template in constants.DTS_NET_MIRROR: + env["OLD_SECONDARY"] = target_node + env["NEW_SECONDARY"] = source_node + else: + env["OLD_SECONDARY"] = env["NEW_SECONDARY"] = None + nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes) nl_post = list(nl) nl_post.append(source_node) @@ -5449,7 +5458,8 @@ class LUMigrateNode(LogicalUnit): class TLMigrateInstance(Tasklet): - def __init__(self, lu, instance_name, live, cleanup): + def __init__(self, lu, instance_name, live, + cleanup, iallocator=None, target_node=None): """Initializes this class. """ @@ -5459,6 +5469,8 @@ class TLMigrateInstance(Tasklet): self.instance_name = instance_name self.live = live self.cleanup = cleanup + self.iallocator = iallocator + self.target_node = target_node def CheckPrereq(self): """Check prerequisites. @@ -5469,19 +5481,37 @@ class TLMigrateInstance(Tasklet): instance_name = _ExpandInstanceName(self.lu.cfg, self.instance_name) instance = self.cfg.GetInstanceInfo(instance_name) assert instance is not None + self.instance = instance - if instance.disk_template != constants.DT_DRBD8: - raise errors.OpPrereqError("Instance's disk layout is not" - " drbd8, cannot migrate.", errors.ECODE_STATE) + if instance.disk_template not in constants.DTS_MIRRORED: + raise errors.OpPrereqError("Instance's disk layout '%s' does not allow" + " migrations" % instance.disk_template, + errors.ECODE_STATE) - secondary_nodes = instance.secondary_nodes - if not secondary_nodes: - raise errors.ConfigurationError("No secondary node but using" - " drbd8 disk template") + if instance.disk_template in constants.DTS_EXT_MIRROR: + if [self.iallocator, self.target_node].count(None) != 1: + raise errors.OpPrereqError("Please specify either a target node using" + " -n or an iallocator using -I for disk" + " template %s" % instance.disk_template, + errors.ECODE_INVAL) + + if self.iallocator: + self._RunAllocator() + + # self.target_node is already populated, either directly or by the + # iallocator run + target_node = self.target_node + + else: + secondary_nodes = instance.secondary_nodes + if not secondary_nodes: + raise errors.ConfigurationError("No secondary node but using" + " %s disk template" % + instance.disk_template) + target_node = secondary_nodes[0] i_be = self.cfg.GetClusterInfo().FillBE(instance) - target_node = secondary_nodes[0] # check memory requirements on the secondary node _CheckNodeFreeMemory(self.lu, target_node, "migrating instance %s" % instance.name, i_be[constants.BE_MEMORY], @@ -5497,7 +5527,35 @@ class TLMigrateInstance(Tasklet): result.Raise("Can't migrate, please use failover", prereq=True, ecode=errors.ECODE_STATE) - self.instance = instance + + def _RunAllocator(self): + """Run the allocator based on input opcode. + + """ + ial = IAllocator(self.cfg, self.rpc, + mode=constants.IALLOCATOR_MODE_RELOC, + name=self.instance_name, + # TODO See why hail breaks with a single node below + relocate_from=[self.instance.primary_node, + self.instance.primary_node], + ) + + ial.Run(self.iallocator) + + if not ial.success: + raise errors.OpPrereqError("Can't compute nodes using" + " iallocator '%s': %s" % + (self.iallocator, ial.info), + errors.ECODE_NORES) + if len(ial.result) != ial.required_nodes: + raise errors.OpPrereqError("iallocator '%s' returned invalid number" + " of nodes (%s), required %s" % + (self.iallocator, len(ial.result), + ial.required_nodes), errors.ECODE_FAULT) + self.target_node = ial.result[0] + self.lu.LogInfo("Selected nodes for instance %s via iallocator %s: %s", + self.instance_name, self.iallocator, + utils.CommaJoin(ial.result)) def _WaitUntilSync(self): """Poll with custom rpc for disk sync. @@ -5632,6 +5690,9 @@ class TLMigrateInstance(Tasklet): """ target_node = self.target_node + if self.instance.disk_template in constants.DTS_EXT_MIRROR: + return + try: self._EnsureSecondary(target_node) self._GoStandalone() @@ -5696,11 +5757,12 @@ class TLMigrateInstance(Tasklet): self.migration_info = migration_info = result.payload - # Then switch the disks to master/master mode - self._EnsureSecondary(target_node) - self._GoStandalone() - self._GoReconnect(True) - self._WaitUntilSync() + if self.instance.disk_template not in constants.DTS_EXT_MIRROR: + # Then switch the disks to master/master mode + self._EnsureSecondary(target_node) + self._GoStandalone() + self._GoReconnect(True) + self._WaitUntilSync() self.feedback_fn("* preparing %s to accept the instance" % target_node) result = self.rpc.call_accept_instance(target_node, @@ -5749,11 +5811,12 @@ class TLMigrateInstance(Tasklet): raise errors.OpExecError("Could not finalize instance migration: %s" % msg) - self._EnsureSecondary(source_node) - self._WaitUntilSync() - self._GoStandalone() - self._GoReconnect(False) - self._WaitUntilSync() + if self.instance.disk_template not in constants.DTS_EXT_MIRROR: + self._EnsureSecondary(source_node) + self._WaitUntilSync() + self._GoStandalone() + self._GoReconnect(False) + self._WaitUntilSync() self.feedback_fn("* done") @@ -5766,7 +5829,12 @@ class TLMigrateInstance(Tasklet): self.feedback_fn = feedback_fn self.source_node = self.instance.primary_node - self.target_node = self.instance.secondary_nodes[0] + + if self.instance.disk_template in constants.DTS_NET_MIRROR: + self.target_node = self.instance.secondary_nodes[0] + # Otheriwse self.target_node has been populated either + # directly, or through an iallocator. + self.all_nodes = [self.source_node, self.target_node] self.nodes_ip = { self.source_node: self.cfg.GetNodeInfo(self.source_node).secondary_ip, -- 1.7.1
