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

Implement instance rename operation

This patch adds support for instance rename operation at all remaining
layers: RPC, OpCode/LU and CLI.

Reviewed-by: imsnah
parent 2c30e9d7
...@@ -287,6 +287,15 @@ class ServerObject(pb.Avatar): ...@@ -287,6 +287,15 @@ class ServerObject(pb.Avatar):
inst = objects.ConfigObject.Loads(inst_s) inst = objects.ConfigObject.Loads(inst_s)
return backend.AddOSToInstance(inst, os_disk, swap_disk) return backend.AddOSToInstance(inst, os_disk, swap_disk)
@staticmethod
def perspective_instance_run_rename(params):
"""Runs the OS rename script for an instance.
"""
inst_s, old_name, os_disk, swap_disk = params
inst = objects.ConfigObject.Loads(inst_s)
return backend.RunRenameInstance(inst, old_name, os_disk, swap_disk)
@staticmethod @staticmethod
def perspective_instance_os_import(params): def perspective_instance_os_import(params):
"""Run the import function of an OS onto a given instance. """Run the import function of an OS onto a given instance.
......
...@@ -416,6 +416,64 @@ def AddOSToInstance(instance, os_disk, swap_disk): ...@@ -416,6 +416,64 @@ def AddOSToInstance(instance, os_disk, swap_disk):
return True return True
def RunRenameInstance(instance, old_name, os_disk, swap_disk):
"""Run the OS rename script for an instance.
Args:
instance: the instance object
old_name: the old name of the instance
os_disk: the instance-visible name of the os device
swap_disk: the instance-visible name of the swap device
"""
inst_os = OSFromDisk(instance.os)
script = inst_os.rename_script
os_device = instance.FindDisk(os_disk)
if os_device is None:
logger.Error("Can't find this device-visible name '%s'" % os_disk)
return False
swap_device = instance.FindDisk(swap_disk)
if swap_device is None:
logger.Error("Can't find this device-visible name '%s'" % swap_disk)
return False
real_os_dev = _RecursiveFindBD(os_device)
if real_os_dev is None:
raise errors.BlockDeviceError("Block device '%s' is not set up" %
str(os_device))
real_os_dev.Open()
real_swap_dev = _RecursiveFindBD(swap_device)
if real_swap_dev is None:
raise errors.BlockDeviceError("Block device '%s' is not set up" %
str(swap_device))
real_swap_dev.Open()
logfile = "%s/rename-%s-%s-%s-%d.log" % (constants.LOG_OS_DIR, instance.os,
old_name,
instance.name, int(time.time()))
if not os.path.exists(constants.LOG_OS_DIR):
os.mkdir(constants.LOG_OS_DIR, 0750)
command = utils.BuildShellCmd("cd %s && %s -o %s -n %s -b %s -s %s &>%s",
inst_os.path, script, old_name, instance.name,
real_os_dev.dev_path, real_swap_dev.dev_path,
logfile)
result = utils.RunCmd(command)
if result.failed:
logger.Error("os create command '%s' returned error: %s"
" output: %s" %
(command, result.fail_reason, result.output))
return False
return True
def _GetVGInfo(vg_name): def _GetVGInfo(vg_name):
"""Get informations about the volume group. """Get informations about the volume group.
......
...@@ -2034,6 +2034,87 @@ class LUReinstallInstance(LogicalUnit): ...@@ -2034,6 +2034,87 @@ class LUReinstallInstance(LogicalUnit):
_ShutdownInstanceDisks(inst, self.cfg) _ShutdownInstanceDisks(inst, self.cfg)
class LURenameInstance(LogicalUnit):
"""Rename an instance.
"""
HPATH = "instance-rename"
HTYPE = constants.HTYPE_INSTANCE
_OP_REQP = ["instance_name", "new_name"]
def BuildHooksEnv(self):
"""Build hooks env.
This runs on master, primary and secondary nodes of the instance.
"""
env = _BuildInstanceHookEnvByObject(self.instance)
env["INSTANCE_NEW_NAME"] = self.op.new_name
nl = ([self.sstore.GetMasterNode(), self.instance.primary_node] +
list(self.instance.secondary_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.cfg.ExpandInstanceName(self.op.instance_name))
if instance is None:
raise errors.OpPrereqError("Instance '%s' not known" %
self.op.instance_name)
if instance.status != "down":
raise errors.OpPrereqError("Instance '%s' is marked to be up" %
self.op.instance_name)
remote_info = rpc.call_instance_info(instance.primary_node, instance.name)
if remote_info:
raise errors.OpPrereqError("Instance '%s' is running on the node %s" %
(self.op.instance_name,
instance.primary_node))
self.instance = instance
# new name verification
hostname1 = utils.LookupHostname(self.op.new_name)
if not hostname1:
raise errors.OpPrereqError("New instance name '%s' not found in dns" %
self.op.new_name)
self.op.new_name = new_name = hostname1['hostname']
if not getattr(self.op, "ignore_ip", False):
command = ["fping", "-q", hostname1['ip']]
result = utils.RunCmd(command)
if not result.failed:
raise errors.OpPrereqError("IP %s of instance %s already in use" %
(hostname1['ip'], new_name))
def Exec(self, feedback_fn):
"""Reinstall the instance.
"""
inst = self.instance
old_name = inst.name
self.cfg.RenameInstance(inst.name, self.op.new_name)
# re-read the instance from the configuration after rename
inst = self.cfg.GetInstanceInfo(self.op.new_name)
_StartInstanceDisks(self.cfg, inst, None)
try:
if not rpc.call_instance_run_rename(inst.primary_node, inst, old_name,
"sda", "sdb"):
msg = ("Could run OS rename script for instance %s\n"
"on node %s\n"
"(but the instance has been renamed in Ganeti)" %
(inst.name, inst.primary_node))
logger.Error(msg)
finally:
_ShutdownInstanceDisks(inst, self.cfg)
class LURemoveInstance(LogicalUnit): class LURemoveInstance(LogicalUnit):
"""Remove an instance. """Remove an instance.
......
...@@ -58,6 +58,7 @@ class Processor(object): ...@@ -58,6 +58,7 @@ class Processor(object):
opcodes.OpCreateInstance: cmdlib.LUCreateInstance, opcodes.OpCreateInstance: cmdlib.LUCreateInstance,
opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance, opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance,
opcodes.OpRemoveInstance: cmdlib.LURemoveInstance, opcodes.OpRemoveInstance: cmdlib.LURemoveInstance,
opcodes.OpRenameInstance: cmdlib.LURenameInstance,
opcodes.OpActivateInstanceDisks: cmdlib.LUActivateInstanceDisks, opcodes.OpActivateInstanceDisks: cmdlib.LUActivateInstanceDisks,
opcodes.OpShutdownInstance: cmdlib.LUShutdownInstance, opcodes.OpShutdownInstance: cmdlib.LUShutdownInstance,
opcodes.OpStartupInstance: cmdlib.LUStartupInstance, opcodes.OpStartupInstance: cmdlib.LUStartupInstance,
......
...@@ -145,6 +145,12 @@ class OpRemoveInstance(OpCode): ...@@ -145,6 +145,12 @@ class OpRemoveInstance(OpCode):
__slots__ = ["instance_name"] __slots__ = ["instance_name"]
class OpRenameInstance(OpCode):
"""Rename an instance."""
OP_ID = "OP_INSTANCE_RENAME"
__slots__ = ["instance_name", "ignore_ip", "new_name"]
class OpStartupInstance(OpCode): class OpStartupInstance(OpCode):
"""Startup an instance.""" """Startup an instance."""
OP_ID = "OP_INSTANCE_STARTUP" OP_ID = "OP_INSTANCE_STARTUP"
......
...@@ -324,6 +324,19 @@ def call_instance_os_add(node, inst, osdev, swapdev): ...@@ -324,6 +324,19 @@ def call_instance_os_add(node, inst, osdev, swapdev):
return c.getresult().get(node, False) return c.getresult().get(node, False)
def call_instance_run_rename(node, inst, old_name, osdev, swapdev):
"""Run the OS rename script for an instance.
This is a single-node call.
"""
params = [inst.Dumps(), old_name, osdev, swapdev]
c = Client("instance_run_rename", params)
c.connect(node)
c.run()
return c.getresult().get(node, False)
def call_instance_info(node, instance): def call_instance_info(node, instance):
"""Returns information about a single instance. """Returns information about a single instance.
......
...@@ -413,6 +413,27 @@ ...@@ -413,6 +413,27 @@
</para> </para>
</refsect3> </refsect3>
<refsect3>
<title>RENAME</title>
<cmdsynopsis>
<command>rename</command>
<arg>--no-ip-check</arg>
<arg choice="req"><replaceable>instance</replaceable></arg>
<arg choice="req"><replaceable>new_name</replaceable></arg>
</cmdsynopsis>
<para>
Renames the given instance. The instance must be stopped
when running this command. The requirements for the new name
are the same as for adding an instance: the new name must be
resolvable and the IP it resolves to must not be reachable
(in order to prevent duplicate IPs the next time the
instance is started). The IP test can be skipped if the
<option>--no-ip-check</option> option is passed.
</para>
</refsect3>
</refsect2> </refsect2>
<refsect2> <refsect2>
......
...@@ -239,6 +239,22 @@ def RemoveInstance(opts, args): ...@@ -239,6 +239,22 @@ def RemoveInstance(opts, args):
return 0 return 0
def RenameInstance(opts, args):
"""Reinstall an instance.
Args:
opts - class with options as members
args - list containing two elements, the instance name and the new name
"""
op = opcodes.OpRenameInstance(instance_name=args[0],
new_name=args[1],
ignore_ip=opts.ignore_ip)
SubmitOpCode(op)
return 0
def ActivateDisks(opts, args): def ActivateDisks(opts, args):
"""Activate an instance's disks. """Activate an instance's disks.
...@@ -270,7 +286,7 @@ def DeactivateDisks(opts, args): ...@@ -270,7 +286,7 @@ def DeactivateDisks(opts, args):
def StartupInstance(opts, args): def StartupInstance(opts, args):
"""Shutdown an instance. """Startup an instance.
Args: Args:
opts - class with options as members opts - class with options as members
...@@ -634,6 +650,14 @@ commands = { ...@@ -634,6 +650,14 @@ commands = {
], ],
"-b disk -p port <instance>", "-b disk -p port <instance>",
"Removes a mirror from the instance"), "Removes a mirror from the instance"),
'rename': (RenameInstance, ARGS_FIXED(2),
[DEBUG_OPT,
make_option("--no-ip-check", dest="ignore_ip",
help="Do not check that the IP of the new name"
" is alive",
default=False, action="store_true"),
],
"<instance> <new_name>", "Rename the instance"),
'replace-disks': (ReplaceDisks, ARGS_ONE, 'replace-disks': (ReplaceDisks, ARGS_ONE,
[DEBUG_OPT, [DEBUG_OPT,
make_option("-n", "--new-secondary", dest="new_secondary", make_option("-n", "--new-secondary", dest="new_secondary",
...@@ -655,7 +679,7 @@ commands = { ...@@ -655,7 +679,7 @@ commands = {
default=None, type="string", metavar="<ADDRESS>"), default=None, type="string", metavar="<ADDRESS>"),
make_option("-b", "--bridge", dest="bridge", make_option("-b", "--bridge", dest="bridge",
help="Bridge to connect this instance to", help="Bridge to connect this instance to",
default=None, type="string", metavar="<bridge>") default=None, type="string", metavar="<bridge>"),
], ],
"<instance>", "Alters the parameters of an instance"), "<instance>", "Alters the parameters of an instance"),
'shutdown': (ShutdownInstance, ARGS_ANY, 'shutdown': (ShutdownInstance, ARGS_ANY,
......
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