mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Add the config file parsing for the on_{poweroff,reboot,crash} options, so that
they actually take effect. Added behaviour "rename-restart" for debugging purposes, that renames the domain out of the way, preserving it for debugging, but starts a new domain too. Add explicit remove of old domain paths when creating a new domain, to avoid stale information affecting us (by shutting the domain down, for example). Signed-off-by: Ewan Mellor <ewan@xensource.com>
This commit is contained in:
1 parent
db730ecdd1
commit
42fb9678c9
6 files changed
+166
-56
No files matched your search
@@ -70,7 +70,8 @@ shutdown_reasons = {
|
||||
restart_modes = [
|
||||
"restart",
|
||||
"destroy",
|
||||
"preserve"
|
||||
"preserve",
|
||||
"rename-restart"
|
||||
]
|
||||
|
||||
STATE_VM_OK = "ok"
|
||||
@@ -653,21 +654,26 @@ class XendDomainInfo:
|
||||
restart_reason = 'crash'
|
||||
|
||||
elif xeninfo['shutdown']:
|
||||
reason = shutdown_reason(xeninfo['shutdown_reason'])
|
||||
|
||||
log.info('Domain has shutdown: name=%s id=%d reason=%s.',
|
||||
self.info['name'], self.domid, reason)
|
||||
|
||||
self.clearRestart()
|
||||
|
||||
if reason == 'suspend':
|
||||
self.state_set(STATE_VM_SUSPENDED)
|
||||
# Don't destroy the domain. XendCheckpoint will do this
|
||||
# once it has finished.
|
||||
elif reason in ['poweroff', 'reboot']:
|
||||
restart_reason = reason
|
||||
if self.readDom('xend/shutdown'):
|
||||
# We've seen this shutdown already, but we are preserving
|
||||
# the domain for debugging. Leave it alone.
|
||||
pass
|
||||
else:
|
||||
self.destroy()
|
||||
reason = shutdown_reason(xeninfo['shutdown_reason'])
|
||||
|
||||
log.info('Domain has shutdown: name=%s id=%d reason=%s.',
|
||||
self.info['name'], self.domid, reason)
|
||||
|
||||
self.clearRestart()
|
||||
|
||||
if reason == 'suspend':
|
||||
self.state_set(STATE_VM_SUSPENDED)
|
||||
# Don't destroy the domain. XendCheckpoint will do
|
||||
# this once it has finished.
|
||||
elif reason in ['poweroff', 'reboot']:
|
||||
restart_reason = reason
|
||||
else:
|
||||
self.destroy()
|
||||
|
||||
else:
|
||||
# Domain is alive. If we are shutting it down, then check
|
||||
@@ -702,6 +708,8 @@ class XendDomainInfo:
|
||||
self.storeDom('xend/shutdown_start_time', time.time())
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def clearRestart(self):
|
||||
self.removeDom("xend/shutdown_start_time")
|
||||
|
||||
@@ -709,9 +717,10 @@ class XendDomainInfo:
|
||||
def maybeRestart(self, reason):
|
||||
# Dispatch to the correct method based upon the configured on_{reason}
|
||||
# behaviour.
|
||||
{"destroy" : self.destroy,
|
||||
"restart" : self.restart,
|
||||
"preserve" : self.preserve}[self.info['on_' + reason]]()
|
||||
{"destroy" : self.destroy,
|
||||
"restart" : self.restart,
|
||||
"preserve" : self.preserve,
|
||||
"rename-restart" : self.renameRestart}[self.info['on_' + reason]]()
|
||||
|
||||
|
||||
def preserve(self):
|
||||
@@ -719,6 +728,10 @@ class XendDomainInfo:
|
||||
self.domid)
|
||||
|
||||
|
||||
def renameRestart(self):
|
||||
self.restart(True)
|
||||
|
||||
|
||||
def dumpCore(self):
|
||||
"""Create a core dump for this domain. Nothrow guarantee."""
|
||||
|
||||
@@ -758,6 +771,8 @@ class XendDomainInfo:
|
||||
self.console_channel = None
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def setConsoleRef(self, ref):
|
||||
self.console_mfn = ref
|
||||
self.storeDom("console/ring-ref", ref)
|
||||
@@ -973,6 +988,10 @@ class XendDomainInfo:
|
||||
try:
|
||||
self.dompath = DOMROOT + str(self.domid)
|
||||
|
||||
# Ensure that the domain entry is clean. This prevents a stale
|
||||
# shutdown_start_time from killing the domain, for example.
|
||||
self.removeDom()
|
||||
|
||||
self.initDomain()
|
||||
self.construct_image()
|
||||
self.configure()
|
||||
@@ -1083,6 +1102,8 @@ class XendDomainInfo:
|
||||
log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
|
||||
|
||||
|
||||
## private:
|
||||
|
||||
def is_terminated(self):
|
||||
"""Check if a domain has been terminated.
|
||||
"""
|
||||
@@ -1142,7 +1163,7 @@ class XendDomainInfo:
|
||||
log.error("Recovering from above exception.")
|
||||
self.storeDom(path, ret.port1)
|
||||
return ret
|
||||
|
||||
|
||||
def create_channel(self):
|
||||
"""Create the channels to the domain.
|
||||
"""
|
||||
@@ -1163,6 +1184,9 @@ class XendDomainInfo:
|
||||
if self.image:
|
||||
self.image.createDeviceModel()
|
||||
|
||||
|
||||
## public:
|
||||
|
||||
def device_create(self, dev_config):
|
||||
"""Create a new device.
|
||||
|
||||
@@ -1183,21 +1207,7 @@ class XendDomainInfo:
|
||||
self.configureDevice(deviceClass, devid, dev_config)
|
||||
|
||||
|
||||
def restart_needed(self, reason):
|
||||
"""Determine if the vm needs to be restarted when shutdown
|
||||
for the given reason.
|
||||
|
||||
@param reason: shutdown reason
|
||||
@return True if needs restart, False otherwise
|
||||
"""
|
||||
if self.info['restart_mode'] == RESTART_NEVER:
|
||||
return False
|
||||
if self.info['restart_mode'] == RESTART_ALWAYS:
|
||||
return True
|
||||
if self.info['restart_mode'] == RESTART_ONREBOOT:
|
||||
return reason == 'reboot'
|
||||
return False
|
||||
|
||||
## private:
|
||||
|
||||
def restart_check(self):
|
||||
"""Check if domain restart is OK.
|
||||
@@ -1216,15 +1226,17 @@ class XendDomainInfo:
|
||||
self.restart_count += 1
|
||||
|
||||
|
||||
def restart(self):
|
||||
"""Restart the domain after it has exited. """
|
||||
def restart(self, rename = False):
|
||||
"""Restart the domain after it has exited.
|
||||
|
||||
@param rename True if the old domain is to be renamed and preserved,
|
||||
False if it is to be destroyed.
|
||||
"""
|
||||
|
||||
# self.restart_check()
|
||||
|
||||
config = self.sxpr()
|
||||
|
||||
self.cleanupDomain()
|
||||
|
||||
if self.readVm('xend/restart_in_progress'):
|
||||
log.error('Xend failed during restart of domain %d. '
|
||||
'Refusing to restart to avoid loops.',
|
||||
@@ -1235,7 +1247,12 @@ class XendDomainInfo:
|
||||
self.writeVm('xend/restart_in_progress', 'True')
|
||||
|
||||
try:
|
||||
self.destroy()
|
||||
if rename:
|
||||
self.preserveShutdownDomain()
|
||||
else:
|
||||
self.cleanupDomain()
|
||||
self.destroy()
|
||||
|
||||
try:
|
||||
xd = get_component('xen.xend.XendDomain')
|
||||
xd.domain_unpause(xd.domain_create(config).getDomid())
|
||||
@@ -1248,6 +1265,37 @@ class XendDomainInfo:
|
||||
# self.exportToDB()
|
||||
|
||||
|
||||
def preserveShutdownDomain(self):
|
||||
"""Preserve a domain that has been shut down, by giving it a new UUID,
|
||||
cloning the VM details, and giving it a new name. This allows us to
|
||||
keep this domain for debugging, but restart a new one in its place
|
||||
preserving the restart semantics (name and UUID preserved).
|
||||
"""
|
||||
|
||||
new_name = self.generateShutdownName()
|
||||
new_uuid = getUuid()
|
||||
log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
|
||||
self.info['name'], self.domid, self.uuid, new_name, new_uuid)
|
||||
self.release_devices()
|
||||
self.info['name'] = new_name
|
||||
self.uuid = new_uuid
|
||||
self.vmpath = VMROOT + new_uuid
|
||||
self.storeVmDetails()
|
||||
self.storeDom('vm', self.vmpath)
|
||||
self.storeDom('xend/shutdown', 'True')
|
||||
|
||||
|
||||
def generateShutdownName(self):
|
||||
n = 1
|
||||
while True:
|
||||
name = "%s-%d" % (self.info['name'], n)
|
||||
try:
|
||||
self.check_name(name)
|
||||
return name
|
||||
except VmError:
|
||||
n += 1
|
||||
|
||||
|
||||
def configure_bootloader(self):
|
||||
if not self.info['bootloader']:
|
||||
return
|
||||
|
||||
@@ -163,11 +163,47 @@ gopts.var('cpu_weight', val='WEIGHT',
|
||||
|
||||
gopts.var('restart', val='onreboot|always|never',
|
||||
fn=set_value, default=None,
|
||||
use="""Whether the domain should be restarted on exit.
|
||||
use="""Deprecated. Use on_poweroff, on_reboot, and on_crash
|
||||
instead.
|
||||
|
||||
Whether the domain should be restarted on exit.
|
||||
- onreboot: restart on exit with shutdown code reboot
|
||||
- always: always restart on exit, ignore exit code
|
||||
- never: never restart on exit, ignore exit code""")
|
||||
|
||||
gopts.var('on_poweroff', val='destroy|restart|preserve|rename-restart',
|
||||
fn=set_value, default=None,
|
||||
use="""Behaviour when a domain exits with reason 'poweroff'.
|
||||
- destroy: the domain is cleaned up as normal;
|
||||
- restart: a new domain is started in place of the old one;
|
||||
- preserve: no clean-up is done until the domain is manually
|
||||
destroyed (using xm destroy, for example);
|
||||
- rename-restart: the old domain is not cleaned up, but is
|
||||
renamed and a new domain started in its place.
|
||||
""")
|
||||
|
||||
gopts.var('on_reboot', val='destroy|restart|preserve|rename-restart',
|
||||
fn=set_value, default=None,
|
||||
use="""Behaviour when a domain exits with reason 'reboot'.
|
||||
- destroy: the domain is cleaned up as normal;
|
||||
- restart: a new domain is started in place of the old one;
|
||||
- preserve: no clean-up is done until the domain is manually
|
||||
destroyed (using xm destroy, for example);
|
||||
- rename-restart: the old domain is not cleaned up, but is
|
||||
renamed and a new domain started in its place.
|
||||
""")
|
||||
|
||||
gopts.var('on_crash', val='destroy|restart|preserve|rename-restart',
|
||||
fn=set_value, default=None,
|
||||
use="""Behaviour when a domain exits with reason 'crash'.
|
||||
- destroy: the domain is cleaned up as normal;
|
||||
- restart: a new domain is started in place of the old one;
|
||||
- preserve: no clean-up is done until the domain is manually
|
||||
destroyed (using xm destroy, for example);
|
||||
- rename-restart: the old domain is not cleaned up, but is
|
||||
renamed and a new domain started in its place.
|
||||
""")
|
||||
|
||||
gopts.var('blkif', val='no|yes',
|
||||
fn=set_bool, default=0,
|
||||
use="Make the domain a block device backend.")
|
||||
@@ -536,6 +572,12 @@ def make_config(opts, vals):
|
||||
config.append(['backend', ['tpmif']])
|
||||
if vals.restart:
|
||||
config.append(['restart', vals.restart])
|
||||
if vals.on_poweroff:
|
||||
config.append(['on_poweroff', vals.on_poweroff])
|
||||
if vals.on_reboot:
|
||||
config.append(['on_reboot', vals.on_reboot])
|
||||
if vals.on_crash:
|
||||
config.append(['on_crash', vals.on_crash])
|
||||
|
||||
if vals.bootloader:
|
||||
config.append(['bootloader', vals.bootloader])
|
||||
|
||||