Commit b6e82a65 authored by Iustin Pop's avatar Iustin Pop
Browse files

Implement replace secondary via the iallocator

This patch implements secondary replace via the iallocator. The new
opcode parameter 'iallocator' behaves like this: if passed, it will
always compute and assign a new secondary, behaving in effect as if the
secondary node has been passed. It conflicts with actually giving the
secondary too.

[Note: not tested with remote_raid1, but the code should behave the
same, we only touch CheckPrereq and we assign a node.]

The patch also adds burnin support for the replace secondary operation;
with this in place, burnin can fully work with auto-assigned nodes.

Reviewed-by: ultrotter
parent 5e767b34
......@@ -3571,6 +3571,29 @@ class LUReplaceDisks(LogicalUnit):
HTYPE = constants.HTYPE_INSTANCE
_OP_REQP = ["instance_name", "mode", "disks"]
def _RunAllocator(self):
"""Compute a new secondary node using an IAllocator.
"""
ial = IAllocator(self.cfg, self.sstore,
mode=constants.IALLOCATOR_MODE_RELOC,
name=self.op.instance_name,
relocate_from=[self.sec_node])
ial.Run(self.op.iallocator)
if not ial.success:
raise errors.OpPrereqError("Can't compute nodes using"
" iallocator '%s': %s" % (self.op.iallocator,
ial.info))
if len(ial.nodes) != ial.required_nodes:
raise errors.OpPrereqError("iallocator '%s' returned invalid number"
" of nodes (%s), required %s" %
(len(ial.nodes), ial.required_nodes))
self.op.remote_node = ial.nodes[0]
logger.ToStdout("Selected new secondary for the instance: %s" %
self.op.remote_node)
def BuildHooksEnv(self):
"""Build hooks env.
......@@ -3597,6 +3620,9 @@ class LUReplaceDisks(LogicalUnit):
This checks that the instance is in the cluster.
"""
if not hasattr(self.op, "remote_node"):
self.op.remote_node = None
instance = self.cfg.GetInstanceInfo(
self.cfg.ExpandInstanceName(self.op.instance_name))
if instance is None:
......@@ -3616,7 +3642,14 @@ class LUReplaceDisks(LogicalUnit):
self.sec_node = instance.secondary_nodes[0]
remote_node = getattr(self.op, "remote_node", None)
ia_name = getattr(self.op, "iallocator", None)
if ia_name is not None:
if self.op.remote_node is not None:
raise errors.OpPrereqError("Give either the iallocator or the new"
" secondary, not both")
self.op.remote_node = self._RunAllocator()
remote_node = self.op.remote_node
if remote_node is not None:
remote_node = self.cfg.ExpandNodeName(remote_node)
if remote_node is None:
......
......@@ -328,7 +328,7 @@ class OpRebootInstance(OpCode):
class OpReplaceDisks(OpCode):
"""Replace the disks of an instance."""
OP_ID = "OP_INSTANCE_REPLACE_DISKS"
__slots__ = ["instance_name", "remote_node", "mode", "disks"]
__slots__ = ["instance_name", "remote_node", "mode", "disks", "iallocator"]
class OpFailoverInstance(OpCode):
......
......@@ -448,6 +448,7 @@ def ReplaceDisks(opts, args):
"""
instance_name = args[0]
new_2ndary = opts.new_secondary
iallocator = opts.iallocator
if opts.disks is None:
disks = ["sda", "sdb"]
else:
......@@ -456,14 +457,16 @@ def ReplaceDisks(opts, args):
mode = constants.REPLACE_DISK_ALL
elif opts.on_primary: # only on primary:
mode = constants.REPLACE_DISK_PRI
if new_2ndary is not None:
if new_2ndary is not None or iallocator is not None:
raise errors.OpPrereqError("Can't change secondary node on primary disk"
" replacement")
elif opts.on_secondary is not None: # only on secondary
elif opts.on_secondary is not None or iallocator is not None:
# only on secondary
mode = constants.REPLACE_DISK_SEC
op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
remote_node=new_2ndary, mode=mode)
remote_node=new_2ndary, mode=mode,
iallocator=iallocator)
SubmitOpCode(op)
return 0
......@@ -841,6 +844,12 @@ commands = {
help=("Comma-separated list of disks"
" to replace (e.g. sda) (optional,"
" defaults to all disks")),
make_option("--iallocator", metavar="<NAME>",
help="Select new secondary for the instance"
" automatically using the"
" <NAME> iallocator plugin (enables"
" secondary node replacement)",
default=None, type="string"),
],
"[-s|-p|-n NODE] <instance>",
"Replaces all disks for the instance"),
......
......@@ -257,9 +257,12 @@ class Burner(object):
mytor = izip(islice(cycle(self.nodes), 2, None),
self.instances)
for tnode, instance in mytor:
if self.opts.iallocator:
tnode = None
op = opcodes.OpReplaceDisks(instance_name=instance,
mode=mode,
remote_node=tnode,
iallocator=self.opts.iallocator,
disks=["sda", "sdb"])
Log("- Replace secondary (%s) for instance %s" % (mode, instance))
self.ExecOp(op)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment