mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Fix the recently-introduced failure to preserve uuid across a guest reboot.
Store the uuid in string form inside XendDomainInfo, to aid this. Add restart-squelching logic to ensure that runaway domains to restart indefinitely. The logic here could be cleverer, say including a backoff for retrying, in case a network block device has gone away, but for now this will do to stop the pathological behaviour. Fixes bug #275. Signed-off-by: Ewan Mellor <ewan@xensource.com>
This commit is contained in:
1 parent
e68e8c51d2
commit
dd319571b5
1 file changed
+46
-51
@@ -87,6 +87,10 @@ VMROOT = '/vm/'
|
||||
|
||||
ZOMBIE_PREFIX = 'Zombie-'
|
||||
|
||||
"""Minimum time between domain restarts in seconds."""
|
||||
MINIMUM_RESTART_TIME = 20
|
||||
|
||||
|
||||
xc = xen.lowlevel.xc.new()
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
@@ -102,6 +106,7 @@ log = logging.getLogger("xend.XendDomainInfo")
|
||||
# file, so those are handled separately.
|
||||
ROUNDTRIPPING_CONFIG_ENTRIES = [
|
||||
('name', str),
|
||||
('uuid', str),
|
||||
('ssidref', int),
|
||||
('vcpus', int),
|
||||
('vcpu_avail', int),
|
||||
@@ -141,7 +146,7 @@ def create(config):
|
||||
|
||||
log.debug("XendDomainInfo.create(%s)", config)
|
||||
|
||||
vm = XendDomainInfo(uuid.create(), parseConfig(config))
|
||||
vm = XendDomainInfo(parseConfig(config))
|
||||
try:
|
||||
vm.construct()
|
||||
vm.initDomain()
|
||||
@@ -166,10 +171,13 @@ def recreate(xeninfo, priv):
|
||||
|
||||
domid = xeninfo['dom']
|
||||
uuid1 = xeninfo['handle']
|
||||
xeninfo['uuid'] = uuid.toString(uuid1)
|
||||
dompath = GetDomainPath(domid)
|
||||
if not dompath:
|
||||
raise XendError(
|
||||
'No domain path in store for existing domain %d' % domid)
|
||||
|
||||
log.info("Recreating domain %d, UUID %s.", domid, xeninfo['uuid'])
|
||||
try:
|
||||
vmpath = xstransact.Read(dompath, "vm")
|
||||
if not vmpath:
|
||||
@@ -185,19 +193,15 @@ def recreate(xeninfo, priv):
|
||||
if uuid1 != uuid2:
|
||||
raise XendError(
|
||||
'Uuid in store does not match uuid for existing domain %d: '
|
||||
'%s != %s' % (domid, uuid2_str, uuid.toString(uuid1)))
|
||||
'%s != %s' % (domid, uuid2_str, xeninfo['uuid']))
|
||||
|
||||
log.info("Recreating domain %d, UUID %s.", domid, uuid2_str)
|
||||
|
||||
vm = XendDomainInfo(uuid1, xeninfo, domid, dompath, True)
|
||||
vm = XendDomainInfo(xeninfo, domid, dompath, True)
|
||||
|
||||
except Exception, exn:
|
||||
log.warn(str(exn))
|
||||
if True:
|
||||
log.warn(str(exn))
|
||||
|
||||
log.info("Recreating domain %d with UUID %s.", domid,
|
||||
uuid.toString(uuid1))
|
||||
|
||||
vm = XendDomainInfo(uuid1, xeninfo, domid, dompath, True)
|
||||
vm = XendDomainInfo(xeninfo, domid, dompath, True)
|
||||
vm.removeDom()
|
||||
vm.removeVm()
|
||||
vm.storeVmDetails()
|
||||
@@ -215,8 +219,7 @@ def restore(config):
|
||||
|
||||
log.debug("XendDomainInfo.restore(%s)", config)
|
||||
|
||||
vm = XendDomainInfo(uuid.fromString(sxp.child_value(config, 'uuid')),
|
||||
parseConfig(config))
|
||||
vm = XendDomainInfo(parseConfig(config))
|
||||
try:
|
||||
vm.construct()
|
||||
vm.storeVmDetails()
|
||||
@@ -335,19 +338,15 @@ def dom_get(dom):
|
||||
return None
|
||||
|
||||
class XendDomainInfo:
|
||||
"""Virtual machine object."""
|
||||
|
||||
"""Minimum time between domain restarts in seconds.
|
||||
"""
|
||||
MINIMUM_RESTART_TIME = 20
|
||||
|
||||
|
||||
def __init__(self, uuidbytes, info, domid = None, dompath = None,
|
||||
augment = False):
|
||||
def __init__(self, info, domid = None, dompath = None, augment = False):
|
||||
|
||||
self.uuidbytes = uuidbytes
|
||||
self.info = info
|
||||
|
||||
if not self.infoIsSet('uuid'):
|
||||
self.info['uuid'] = uuid.toString(uuid.create())
|
||||
|
||||
if domid is not None:
|
||||
self.domid = domid
|
||||
elif 'dom' in info:
|
||||
@@ -355,7 +354,7 @@ class XendDomainInfo:
|
||||
else:
|
||||
self.domid = None
|
||||
|
||||
self.vmpath = VMROOT + uuid.toString(uuidbytes)
|
||||
self.vmpath = VMROOT + self.info['uuid']
|
||||
self.dompath = dompath
|
||||
|
||||
if augment:
|
||||
@@ -571,7 +570,7 @@ class XendDomainInfo:
|
||||
|
||||
def storeVmDetails(self):
|
||||
to_store = {
|
||||
'uuid': uuid.toString(self.uuidbytes),
|
||||
'uuid': self.info['uuid'],
|
||||
|
||||
# XXX
|
||||
'memory/target': str(self.info['memory_KiB'])
|
||||
@@ -928,7 +927,6 @@ class XendDomainInfo:
|
||||
def sxpr(self):
|
||||
sxpr = ['domain',
|
||||
['domid', self.domid],
|
||||
['uuid', uuid.toString(self.uuidbytes)],
|
||||
['memory', self.info['memory_KiB'] / 1024]]
|
||||
|
||||
for e in ROUNDTRIPPING_CONFIG_ENTRIES:
|
||||
@@ -1045,8 +1043,9 @@ class XendDomainInfo:
|
||||
self.domid,
|
||||
self.info['ssidref'])
|
||||
|
||||
self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'],
|
||||
handle = self.uuidbytes)
|
||||
self.domid = xc.domain_create(
|
||||
dom = 0, ssidref = self.info['ssidref'],
|
||||
handle = uuid.fromString(self.info['uuid']))
|
||||
|
||||
if self.domid < 0:
|
||||
raise VmError('Creating domain failed: name=%s' %
|
||||
@@ -1253,23 +1252,6 @@ class XendDomainInfo:
|
||||
|
||||
## private:
|
||||
|
||||
def restart_check(self):
|
||||
"""Check if domain restart is OK.
|
||||
To prevent restart loops, raise an error if it is
|
||||
less than MINIMUM_RESTART_TIME seconds since the last restart.
|
||||
"""
|
||||
tnow = time.time()
|
||||
if self.restart_time is not None:
|
||||
tdelta = tnow - self.restart_time
|
||||
if tdelta < self.MINIMUM_RESTART_TIME:
|
||||
self.restart_cancel()
|
||||
msg = 'VM %s restarting too fast' % self.info['name']
|
||||
log.error(msg)
|
||||
raise VmError(msg)
|
||||
self.restart_time = tnow
|
||||
self.restart_count += 1
|
||||
|
||||
|
||||
def restart(self, rename = False):
|
||||
"""Restart the domain after it has exited.
|
||||
|
||||
@@ -1277,8 +1259,6 @@ class XendDomainInfo:
|
||||
False if it is to be destroyed.
|
||||
"""
|
||||
|
||||
# self.restart_check()
|
||||
|
||||
config = self.sxpr()
|
||||
|
||||
if self.readVm('xend/restart_in_progress'):
|
||||
@@ -1290,11 +1270,27 @@ class XendDomainInfo:
|
||||
|
||||
self.writeVm('xend/restart_in_progress', 'True')
|
||||
|
||||
now = time.time()
|
||||
rst = self.readVm('xend/previous_restart_time')
|
||||
log.error(rst)
|
||||
if rst:
|
||||
rst = float(rst)
|
||||
timeout = now - rst
|
||||
if timeout < MINIMUM_RESTART_TIME:
|
||||
log.error(
|
||||
'VM %s restarting too fast (%f seconds since the last '
|
||||
'restart). Refusing to restart to avoid loops.',
|
||||
self.info['name'], timeout)
|
||||
self.destroy()
|
||||
return
|
||||
|
||||
self.writeVm('xend/previous_restart_time', str(now))
|
||||
|
||||
try:
|
||||
if rename:
|
||||
self.preserveForRestart()
|
||||
else:
|
||||
self.destroy()
|
||||
self.destroyDomain()
|
||||
|
||||
try:
|
||||
xd = get_component('xen.xend.XendDomain')
|
||||
@@ -1321,15 +1317,14 @@ class XendDomainInfo:
|
||||
"""
|
||||
|
||||
new_name = self.generateUniqueName()
|
||||
new_uuid = uuid.create()
|
||||
new_uuid_str = uuid.toString(new_uuid)
|
||||
new_uuid = uuid.toString(uuid.create())
|
||||
log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
|
||||
self.info['name'], self.domid, uuid.toString(self.uuidbytes),
|
||||
new_name, new_uuid_str)
|
||||
self.info['name'], self.domid, self.info['uuid'],
|
||||
new_name, new_uuid)
|
||||
self.release_devices()
|
||||
self.info['name'] = new_name
|
||||
self.uuidbytes = new_uuid
|
||||
self.vmpath = VMROOT + new_uuid_str
|
||||
self.info['uuid'] = new_uuid
|
||||
self.vmpath = VMROOT + new_uuid
|
||||
self.storeVmDetails()
|
||||
self.preserve()
|
||||
|
||||
|
||||