Commit 323f9095 authored by Stephen Shirley's avatar Stephen Shirley
Browse files

Add gnt-instance start --pause



Creates the instance, but pauses execution before booting. This combined
with 'gnt-instance console' unpausing instances means that the entire
boot process can be viewed and monitored.
Signed-off-by: default avatarStephen Shirley <diamond@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parent ae082df0
......@@ -1086,11 +1086,13 @@ def _GatherAndLinkBlockDevs(instance):
return block_devices
def StartInstance(instance):
def StartInstance(instance, startup_paused):
"""Start an instance.
@type instance: L{objects.Instance}
@param instance: the instance object
@type startup_paused: bool
@param instance: pause instance at startup?
@rtype: None
"""
......@@ -1103,7 +1105,7 @@ def StartInstance(instance):
try:
block_devices = _GatherAndLinkBlockDevs(instance)
hyper = hypervisor.GetHypervisor(instance.hypervisor)
hyper.StartInstance(instance, block_devices)
hyper.StartInstance(instance, block_devices, startup_paused)
except errors.BlockDeviceError, err:
_Fail("Block device error: %s", err, exc=True)
except errors.HypervisorError, err:
......
......@@ -162,6 +162,7 @@ __all__ = [
"SRC_DIR_OPT",
"SRC_NODE_OPT",
"SUBMIT_OPT",
"STARTUP_PAUSED_OPT",
"STATIC_OPT",
"SYNC_OPT",
"TAG_ADD_OPT",
......@@ -1223,6 +1224,10 @@ SECONDARY_ONLY_OPT = cli_option("-s", "--secondary-only",
" disk templates, e.g. %s)" %
utils.CommaJoin(constants.DTS_INT_MIRROR))
STARTUP_PAUSED_OPT = cli_option("--paused", dest="startup_paused",
action="store_true", default=False,
help="Pause instance at startup")
#: Options provided by all commands
COMMON_OPTS = [DEBUG_OPT]
......
......@@ -662,7 +662,8 @@ def _StartupInstance(name, opts):
op = opcodes.OpInstanceStartup(instance_name=name,
force=opts.force,
ignore_offline_nodes=opts.ignore_offline,
no_remember=opts.no_remember)
no_remember=opts.no_remember,
startup_paused=opts.startup_paused)
# do not add these parameters to the opcode unless they're defined
if opts.hvparams:
op.hvparams = opts.hvparams
......@@ -1453,7 +1454,7 @@ commands = {
m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
m_inst_tags_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT, HVOPTS_OPT,
BACKEND_OPT, DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT,
NO_REMEMBER_OPT],
NO_REMEMBER_OPT, STARTUP_PAUSED_OPT],
"<instance>", "Starts an instance"),
'reboot': (
GenericManyOps("reboot", _RebootInstance), [ArgInstance()],
......
......@@ -5705,7 +5705,8 @@ class LUInstanceStartup(LogicalUnit):
_StartInstanceDisks(self, instance, force)
result = self.rpc.call_instance_start(node_current, instance,
self.op.hvparams, self.op.beparams)
self.op.hvparams, self.op.beparams,
self.op.startup_paused)
msg = result.fail_msg
if msg:
_ShutdownInstanceDisks(self, instance)
......@@ -5795,7 +5796,8 @@ class LUInstanceReboot(LogicalUnit):
self.LogInfo("Instance %s was already stopped, starting now",
instance.name)
_StartInstanceDisks(self, instance, ignore_secondaries)
result = self.rpc.call_instance_start(node_current, instance, None, None)
result = self.rpc.call_instance_start(node_current, instance,
None, None, False)
msg = result.fail_msg
if msg:
_ShutdownInstanceDisks(self, instance)
......@@ -6646,7 +6648,8 @@ class LUInstanceMove(LogicalUnit):
_ShutdownInstanceDisks(self, instance)
raise errors.OpExecError("Can't activate the instance's disks")
result = self.rpc.call_instance_start(target_node, instance, None, None)
result = self.rpc.call_instance_start(target_node, instance,
None, None, False)
msg = result.fail_msg
if msg:
_ShutdownInstanceDisks(self, instance)
......@@ -8771,7 +8774,8 @@ class LUInstanceCreate(LogicalUnit):
self.cfg.Update(iobj, feedback_fn)
logging.info("Starting instance %s on node %s", instance, pnode_name)
feedback_fn("* starting instance...")
result = self.rpc.call_instance_start(pnode_name, iobj, None, None)
result = self.rpc.call_instance_start(pnode_name, iobj,
None, None, False)
result.Raise("Could not start instance")
return list(iobj.all_nodes)
......@@ -11190,7 +11194,8 @@ class LUBackupExport(LogicalUnit):
not self.op.remove_instance):
assert not activate_disks
feedback_fn("Starting instance %s" % instance.name)
result = self.rpc.call_instance_start(src_node, instance, None, None)
result = self.rpc.call_instance_start(src_node, instance,
None, None, False)
msg = result.fail_msg
if msg:
feedback_fn("Failed to start instance: %s" % msg)
......
......@@ -134,7 +134,7 @@ class BaseHypervisor(object):
def __init__(self):
pass
def StartInstance(self, instance, block_devices):
def StartInstance(self, instance, block_devices, startup_paused):
"""Start an instance."""
raise NotImplementedError
......
......@@ -135,7 +135,7 @@ class ChrootManager(hv_base.BaseHypervisor):
data.append((file_name, 0, 0, 0, 0, 0))
return data
def StartInstance(self, instance, block_devices):
def StartInstance(self, instance, block_devices, startup_paused):
"""Start an instance.
For the chroot manager, we try to mount the block device and
......
......@@ -147,7 +147,7 @@ class FakeHypervisor(hv_base.BaseHypervisor):
file_name = self._InstanceFile(instance_name)
utils.RemoveFile(file_name)
def StartInstance(self, instance, block_devices):
def StartInstance(self, instance, block_devices, startup_paused):
"""Start an instance.
For the fake hypervisor, it just creates a file in the base dir,
......
......@@ -502,7 +502,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
data.append(info)
return data
def _GenerateKVMRuntime(self, instance, block_devices):
def _GenerateKVMRuntime(self, instance, block_devices, startup_paused):
"""Generate KVM information to start an instance.
"""
......@@ -523,6 +523,8 @@ class KVMHypervisor(hv_base.BaseHypervisor):
kvm_cmd.extend(['-daemonize'])
if not instance.hvparams[constants.HV_ACPI]:
kvm_cmd.extend(['-no-acpi'])
if startup_paused:
kvm_cmd.extend(['-S'])
hvp = instance.hvparams
boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
......@@ -901,12 +903,12 @@ class KVMHypervisor(hv_base.BaseHypervisor):
for filename in temp_files:
utils.RemoveFile(filename)
def StartInstance(self, instance, block_devices):
def StartInstance(self, instance, block_devices, startup_paused):
"""Start an instance.
"""
self._CheckDown(instance.name)
kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, startup_paused)
self._SaveKVMRuntime(instance, kvm_runtime)
self._ExecuteKVMRuntime(instance, kvm_runtime)
......
......@@ -266,7 +266,7 @@ class LXCHypervisor(hv_base.BaseHypervisor):
return "\n".join(out) + "\n"
def StartInstance(self, instance, block_devices):
def StartInstance(self, instance, block_devices, startup_paused):
"""Start an instance.
For LCX, we try to mount the block device and execute 'lxc-start'.
......
......@@ -180,12 +180,16 @@ class XenHypervisor(hv_base.BaseHypervisor):
xm_list = self._GetXMList(False)
return xm_list
def StartInstance(self, instance, block_devices):
def StartInstance(self, instance, block_devices, startup_paused):
"""Start an instance.
"""
self._WriteConfigFile(instance, block_devices)
result = utils.RunCmd(["xm", "create", instance.name])
cmd = ["xm", "create"]
if startup_paused:
cmd.extend(["--paused"])
cmd.extend([instance.name])
result = utils.RunCmd(cmd)
if result.failed:
raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
......
......@@ -125,6 +125,10 @@ _PNoRemember = ("no_remember", False, ht.TBool,
_PMigrationTargetNode = ("target_node", None, ht.TMaybeString,
"Target node for shared-storage instances")
_PStartupPaused = ("startup_paused", False, ht.TBool,
"Pause instance at startup")
#: OP_ID conversion regular expression
_OPID_RE = re.compile("([a-z])([A-Z])")
......@@ -1018,6 +1022,7 @@ class OpInstanceStartup(OpCode):
"Temporary hypervisor parameters, hypervisor-dependent"),
("beparams", ht.EmptyDict, ht.TDict, "Temporary backend parameters"),
_PNoRemember,
_PStartupPaused,
]
......
......@@ -661,14 +661,14 @@ class RpcRunner(object):
return self._SingleNodeCall(node, "bridges_exist", [bridges_list])
@_RpcTimeout(_TMO_NORMAL)
def call_instance_start(self, node, instance, hvp, bep):
def call_instance_start(self, node, instance, hvp, bep, startup_paused):
"""Starts an instance.
This is a single-node call.
"""
idict = self._InstDict(instance, hvp=hvp, bep=bep)
return self._SingleNodeCall(node, "instance_start", [idict])
return self._SingleNodeCall(node, "instance_start", [idict, startup_paused])
@_RpcTimeout(_TMO_NORMAL)
def call_instance_shutdown(self, node, instance, timeout):
......
......@@ -557,8 +557,9 @@ class NodeHttpServer(http.server.HttpServer):
"""Start an instance.
"""
instance = objects.Instance.FromDict(params[0])
return backend.StartInstance(instance)
(instance_name, startup_paused) = params
instance = objects.Instance.FromDict(instance_name)
return backend.StartInstance(instance, startup_paused)
@staticmethod
def perspective_migration_info(params):
......
......@@ -848,7 +848,7 @@ STARTUP
| --tags \| --node-tags \| --pri-node-tags \| --sec-node-tags]
| [{-H|--hypervisor-parameters} ``key=value...``]
| [{-B|--backend-parameters} ``key=value...``]
| [--submit]
| [--submit] [--paused]
| {*name*...}
Starts one or more instances, depending on the following options. The
......@@ -889,7 +889,6 @@ four available modes are:
will start all instances in the cluster on secondary nodes with the
tags given as arguments
Note that although you can pass more than one selection option, the
last one wins, so in order to guarantee the desired result, don't pass
more than one such option.
......@@ -927,6 +926,11 @@ 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
**gnt-job info**.
The ``--paused`` option is only valid for Xen and kvm hypervisors. This
pauses the instance at the start of bootup, awaiting ``gnt-instance
console`` to unpause it, allowing the entire boot process to be
monitored for debugging.
Example::
# gnt-instance start instance1.example.com
......@@ -1039,6 +1043,10 @@ of the instance. To connect to the virtualized "physical" console of a
HVM instance, use a VNC client with the connection info from the
**info** command.
For Xen/kvm instances, if the instance is paused, this attempts to
unpause the instance after waiting a few seconds for the connection to
the console to be made.
Example::
# gnt-instance console instance1.example.com
......
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