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

Implement instance recreate-disks



This can be used for a 'plain' type instance when the underlying storage
went away, to recreate the storage (and reinstall) instead of removing
the instance and readding it.
Signed-off-by: default avatarIustin Pop <iustin@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parent 2945fd2d
......@@ -3626,6 +3626,89 @@ class LUReinstallInstance(LogicalUnit):
_ShutdownInstanceDisks(self, inst)
class LURecreateInstanceDisks(LogicalUnit):
"""Recreate an instance's missing disks.
"""
HPATH = "instance-recreate-disks"
HTYPE = constants.HTYPE_INSTANCE
_OP_REQP = ["instance_name", "disks"]
REQ_BGL = False
def CheckArguments(self):
"""Check the arguments.
"""
if not isinstance(self.op.disks, list):
raise errors.OpPrereqError("Invalid disks parameter")
for item in self.op.disks:
if (not isinstance(item, int) or
item < 0):
raise errors.OpPrereqError("Invalid disk specification '%s'" %
str(item))
def ExpandNames(self):
self._ExpandAndLockInstance()
def BuildHooksEnv(self):
"""Build hooks env.
This runs on master, primary and secondary nodes of the instance.
"""
env = _BuildInstanceHookEnvByObject(self, self.instance)
nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
return env, nl, nl
def CheckPrereq(self):
"""Check prerequisites.
This checks that the instance is in the cluster and is not running.
"""
instance = self.cfg.GetInstanceInfo(self.op.instance_name)
assert instance is not None, \
"Cannot retrieve locked instance %s" % self.op.instance_name
_CheckNodeOnline(self, instance.primary_node)
if instance.disk_template == constants.DT_DISKLESS:
raise errors.OpPrereqError("Instance '%s' has no disks" %
self.op.instance_name)
if instance.admin_up:
raise errors.OpPrereqError("Instance '%s' is marked to be up" %
self.op.instance_name)
remote_info = self.rpc.call_instance_info(instance.primary_node,
instance.name,
instance.hypervisor)
remote_info.Raise("Error checking node %s" % instance.primary_node,
prereq=True)
if remote_info.payload:
raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
(self.op.instance_name,
instance.primary_node))
if not self.op.disks:
self.op.disks = range(len(instance.disks))
else:
for idx in self.op.disks:
if idx >= len(instance.disks):
raise errors.OpPrereqError("Invalid disk index passed '%s'" % idx)
self.instance = instance
def Exec(self, feedback_fn):
"""Recreate the disks.
"""
to_skip = []
for idx, disk in enumerate(self.instance.disks):
if idx not in self.op.disks: # disk idx has not been passed in
to_skip.append(idx)
continue
_CreateDisks(self, self.instance, to_skip=to_skip)
class LURenameInstance(LogicalUnit):
"""Rename an instance.
......@@ -4818,7 +4901,7 @@ def _GetInstanceInfoText(instance):
return "originstname+%s" % instance.name
def _CreateDisks(lu, instance):
def _CreateDisks(lu, instance, to_skip=None):
"""Create all disks for an instance.
This abstracts away some work from AddInstance.
......@@ -4827,6 +4910,8 @@ def _CreateDisks(lu, instance):
@param lu: the logical unit on whose behalf we execute
@type instance: L{objects.Instance}
@param instance: the instance whose disks we should create
@type to_skip: list
@param to_skip: list of indices to skip
@rtype: boolean
@return: the success of the creation
......@@ -4843,7 +4928,9 @@ def _CreateDisks(lu, instance):
# Note: this needs to be kept in sync with adding of disks in
# LUSetInstanceParams
for device in instance.disks:
for idx, device in enumerate(instance.disks):
if to_skip and idx in to_skip:
continue
logging.info("Creating volume %s for instance %s",
device.iv_name, instance.name)
#HARDCODE
......
......@@ -74,6 +74,7 @@ class Processor(object):
opcodes.OpRebootInstance: cmdlib.LURebootInstance,
opcodes.OpDeactivateInstanceDisks: cmdlib.LUDeactivateInstanceDisks,
opcodes.OpReplaceDisks: cmdlib.LUReplaceDisks,
opcodes.OpRecreateInstanceDisks: cmdlib.LURecreateInstanceDisks,
opcodes.OpFailoverInstance: cmdlib.LUFailoverInstance,
opcodes.OpMigrateInstance: cmdlib.LUMigrateInstance,
opcodes.OpConnectConsole: cmdlib.LUConnectConsole,
......
......@@ -540,6 +540,13 @@ class OpDeactivateInstanceDisks(OpCode):
__slots__ = OpCode.__slots__ + ["instance_name"]
class OpRecreateInstanceDisks(OpCode):
"""Deactivate an instance's disks."""
OP_ID = "OP_INSTANCE_RECREATE_DISKS"
OP_DSC_FIELD = "instance_name"
__slots__ = OpCode.__slots__ + ["instance_name", "disks"]
class OpQueryInstances(OpCode):
"""Compute the list of instances."""
OP_ID = "OP_INSTANCE_QUERY"
......
......@@ -1893,6 +1893,31 @@ node1.example.com:disk/1:/dev/drbd1
</para>
</refsect3>
<refsect3>
<title>RECREATE-DISKS</title>
<cmdsynopsis>
<command>recreate-disks</command>
<arg>--submit</arg>
<arg>--disks=<option>indices</option></arg>
<arg choice="req"><replaceable>instance</replaceable></arg>
</cmdsynopsis>
<para>
Recreates the disks of the given instance, or only a subset
of the disks (if the option <option>disks</option> is
passed, which must be a comma-separated list of disk
indices, starting from zero).
</para>
<para>
The <option>--submit</option> option is used to send the job to
the master daemon but not wait for its completion. The job
ID will be shown so that it can be examined via
<command>gnt-job info</command>.
</para>
</refsect3>
</refsect2>
<refsect2>
......
......@@ -660,7 +660,7 @@ def ActivateDisks(opts, args):
def DeactivateDisks(opts, args):
"""Deactivate an instance's disks..
"""Deactivate an instance's disks.
This function takes the instance name, looks for its primary node
and the tries to shutdown its block devices on that node.
......@@ -678,6 +678,32 @@ def DeactivateDisks(opts, args):
return 0
def RecreateDisks(opts, args):
"""Recreate an instance's disks.
@param opts: the command line options selected by the user
@type args: list
@param args: should contain only one element, the instance name
@rtype: int
@return: the desired exit code
"""
instance_name = args[0]
if opts.disks:
try:
opts.disks = [int(v) for v in opts.disks.split(",")]
except (ValueError, TypeError), err:
ToStderr("Invalid disks value: %s" % str(err))
return 1
else:
opts.disks = []
op = opcodes.OpRecreateInstanceDisks(instance_name=instance_name,
disks=opts.disks)
SubmitOrSend(op, opts)
return 0
def GrowDisk(opts, args):
"""Grow an instance's disks.
......@@ -1553,6 +1579,15 @@ commands = {
'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT, SUBMIT_OPT],
"<instance>",
"Deactivate an instance's disks"),
'recreate-disks': (RecreateDisks, ARGS_ONE,
[DEBUG_OPT, SUBMIT_OPT,
make_option("--disks", dest="disks", default=None,
help="Comma-separated list of disks"
" indices to replace (e.g. 0,2) (optional,"
" defaults to all disks)"),
],
"<instance>",
"Recreate an instance's disks"),
'grow-disk': (GrowDisk, ARGS_FIXED(3),
[DEBUG_OPT, SUBMIT_OPT,
make_option("--no-wait-for-sync",
......
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