# HG changeset patch
# User Tom Wilkie <tom.wilkie@xxxxxxxxx>
# Date 1177088188 -3600
# Node ID 55135bf6eb4459fb130e9d27f7ccbeb89b86637b
# Parent 53b1cfcf129fd89139723512c3560dac22961aff
Deprecate XendDomainInfo.state - now use _stateGet() to get the live
state of a domain. Should still call _stateSet() to notify others
when you expect the state has changed.
Also some changes to locking in save/suspend, restore/resume and migrate
Passes xm-test against XenAPI...
signed-off-by: Tom Wilkie <tom.wilkie@xxxxxxxxx>
---
tools/python/xen/xend/XendCheckpoint.py | 24 +++++++
tools/python/xen/xend/XendConfig.py | 2
tools/python/xen/xend/XendDomain.py | 29 ++++-----
tools/python/xen/xend/XendDomainInfo.py | 97 +++++++++++++++++++++++---------
4 files changed, 108 insertions(+), 44 deletions(-)
diff -r 53b1cfcf129f -r 55135bf6eb44 tools/python/xen/xend/XendCheckpoint.py
--- a/tools/python/xen/xend/XendCheckpoint.py Fri Apr 20 17:51:10 2007 +0100
+++ b/tools/python/xen/xend/XendCheckpoint.py Fri Apr 20 17:56:28 2007 +0100
@@ -253,8 +253,28 @@ def restore(xd, fd, dominfo = None, paus
os.read(fd, 1) # Wait for source to close connection
dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
-
- dominfo.waitForDevices() # Wait for backends to set up
+
+ #
+ # We shouldn't hold the domains_lock over a waitForDevices
+ # As this function sometime gets called holding this lock,
+ # we must release it and re-acquire it appropriately
+ #
+ from xen.xend import XendDomain
+
+ lock = True;
+ try:
+ XendDomain.instance().domains_lock.release()
+ except:
+ lock = False;
+
+ try:
+ dominfo.waitForDevices() # Wait for backends to set up
+ except Exception, exn:
+ log.exception(exn)
+
+ if lock:
+ XendDomain.instance().domains_lock.acquire()
+
if not paused:
dominfo.unpause()
diff -r 53b1cfcf129f -r 55135bf6eb44 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py Fri Apr 20 17:51:10 2007 +0100
+++ b/tools/python/xen/xend/XendConfig.py Fri Apr 20 17:56:28 2007 +0100
@@ -870,7 +870,7 @@ class XendConfig(dict):
sxpr.append([legacy, self[legacy]])
sxpr.append(['image', self.image_sxpr()])
- sxpr.append(['status', domain.state])
+ sxpr.append(['status', domain._stateGet()])
if domain.getDomid() is not None:
sxpr.append(['state', self._get_old_state_string()])
diff -r 53b1cfcf129f -r 55135bf6eb44 tools/python/xen/xend/XendDomain.py
--- a/tools/python/xen/xend/XendDomain.py Fri Apr 20 17:51:10 2007 +0100
+++ b/tools/python/xen/xend/XendDomain.py Fri Apr 20 17:56:28 2007 +0100
@@ -45,6 +45,7 @@ from xen.xend.XendConstants import DOM_S
from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN
from xen.xend.XendConstants import TRIGGER_TYPE
from xen.xend.XendDevices import XendDevices
+from xen.xend.XendAPIConstants import *
from xen.xend.xenstore.xstransact import xstransact
from xen.xend.xenstore.xswatch import xswatch
@@ -457,7 +458,7 @@ class XendDomain:
if domid == None:
domid = info.getDomid()
- if info.state != DOM_STATE_HALTED:
+ if info._stateGet() != DOM_STATE_HALTED:
info.cleanupDomain()
if domid in self.domains:
@@ -577,7 +578,7 @@ class XendDomain:
self.domains_lock.acquire()
try:
for dom_uuid, dom in self.managed_domains.items():
- if dom and dom.state == DOM_STATE_HALTED:
+ if dom and dom._stateGet() == DOM_STATE_HALTED:
on_xend_start = dom.info.get('on_xend_start', 'ignore')
auto_power_on = dom.info.get('auto_power_on', False)
should_start = (on_xend_start == 'start') or auto_power_on
@@ -602,7 +603,7 @@ class XendDomain:
if dom.getName() == DOM0_NAME:
continue
- if dom.state == DOM_STATE_RUNNING:
+ if dom._stateGet() == DOM_STATE_RUNNING:
shutdownAction = dom.info.get('on_xend_stop', 'ignore')
if shutdownAction == 'shutdown':
log.debug('Shutting down domain: %s' % dom.getName())
@@ -780,7 +781,7 @@ class XendDomain:
return active_domains + inactive_domains
else:
return filter(lambda x:
- POWER_STATE_NAMES[x.state].lower() == state,
+ POWER_STATE_NAMES[x._stateGet()].lower() ==
state,
active_domains + inactive_domains)
finally:
self.domains_lock.release()
@@ -825,10 +826,10 @@ class XendDomain:
if dominfo.getDomid() == DOM0_ID:
raise XendError("Cannot save privileged domain %s" % domname)
- if dominfo.state != DOM_STATE_RUNNING:
+ if dominfo._stateGet() != DOM_STATE_RUNNING:
raise VMBadState("Domain is not running",
POWER_STATE_NAMES[DOM_STATE_RUNNING],
- POWER_STATE_NAMES[dominfo.state])
+ POWER_STATE_NAMES[dominfo._stateGet()])
dom_uuid = dominfo.get_uuid()
@@ -869,8 +870,8 @@ class XendDomain:
if dominfo.getDomid() == DOM0_ID:
raise XendError("Cannot save privileged domain %s" %
domname)
- if dominfo.state != DOM_STATE_HALTED:
- raise XendError("Cannot resume domain that is not halted.")
+ if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
+ raise XendError("Cannot resume domain that is not
suspended.")
dom_uuid = dominfo.get_uuid()
chkpath = self._managed_check_point_path(dom_uuid)
@@ -879,7 +880,7 @@ class XendDomain:
# Restore that replaces the existing XendDomainInfo
try:
- log.debug('Current DomainInfo state: %d' % dominfo.state)
+ log.debug('Current DomainInfo state: %d' %
dominfo._stateGet())
oflags = os.O_RDONLY
if hasattr(os, "O_LARGEFILE"):
oflags |= os.O_LARGEFILE
@@ -974,10 +975,10 @@ class XendDomain:
if not dominfo:
raise XendInvalidDomain(str(domid))
- if dominfo.state != DOM_STATE_HALTED:
+ if dominfo._stateGet() != DOM_STATE_HALTED:
raise VMBadState("Domain is already running",
POWER_STATE_NAMES[DOM_STATE_HALTED],
- POWER_STATE_NAMES[dominfo.state])
+ POWER_STATE_NAMES[dominfo._stateGet()])
dominfo.start(is_managed = True)
finally:
@@ -1003,10 +1004,10 @@ class XendDomain:
if not dominfo:
raise XendInvalidDomain(str(domid))
- if dominfo.state != DOM_STATE_HALTED:
- raise VMBadState("Domain is still running",
+ if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
+ raise VMBadState("Domain is not halted.",
POWER_STATE_NAMES[DOM_STATE_HALTED],
- POWER_STATE_NAMES[dominfo.state])
+ POWER_STATE_NAMES[dominfo._stateGet()])
self._domain_delete_by_info(dominfo)
except Exception, ex:
diff -r 53b1cfcf129f -r 55135bf6eb44 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Fri Apr 20 17:51:10 2007 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py Fri Apr 20 17:56:28 2007 +0100
@@ -30,6 +30,7 @@ import re
import re
import copy
import os
+import traceback
from types import StringTypes
import xen.lowlevel.xc
@@ -309,8 +310,8 @@ class XendDomainInfo:
@type shutdownWatch: xen.xend.xenstore.xswatch
@ivar shutdownStartTime: UNIX Time when domain started shutting down.
@type shutdownStartTime: float or None
- @ivar state: Domain state
- @type state: enum(DOM_STATE_HALTED, DOM_STATE_RUNNING, ...)
+# @ivar state: Domain state
+# @type state: enum(DOM_STATE_HALTED, DOM_STATE_RUNNING, ...)
@ivar state_updated: lock for self.state
@type state_updated: threading.Condition
@ivar refresh_shutdown_lock: lock for polling shutdown state
@@ -361,9 +362,9 @@ class XendDomainInfo:
self.shutdownStartTime = None
self._resume = resume
- self.state = DOM_STATE_HALTED
self.state_updated = threading.Condition()
self.refresh_shutdown_lock = threading.Condition()
+ self._stateSet(DOM_STATE_HALTED)
self._deviceControllers = {}
@@ -389,7 +390,7 @@ class XendDomainInfo:
"""
from xen.xend import XendDomain
- if self.state == DOM_STATE_HALTED:
+ if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED,
XEN_API_VM_POWER_STATE_SUSPENDED):
try:
XendTask.log_progress(0, 30, self._constructDomain)
XendTask.log_progress(31, 60, self._initDomain)
@@ -420,7 +421,8 @@ class XendDomainInfo:
def resume(self):
"""Resumes a domain that has come back from suspension."""
- if self.state in (DOM_STATE_HALTED, DOM_STATE_SUSPENDED):
+ state = self._stateGet()
+ if state in (DOM_STATE_SUSPENDED, DOM_STATE_HALTED):
try:
self._constructDomain()
self._storeVmDetails()
@@ -433,12 +435,13 @@ class XendDomainInfo:
self.destroy()
raise
else:
- raise XendError('VM already running')
+ raise XendError('VM is not susupened; it is %s'
+ % XEN_API_VM_POWER_STATE[state])
def shutdown(self, reason):
"""Shutdown a domain by signalling this via xenstored."""
log.debug('XendDomainInfo.shutdown(%s)', reason)
- if self.state in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
+ if self._stateGet() in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
raise XendError('Domain cannot be shutdown')
if self.domid == 0:
@@ -558,8 +561,7 @@ class XendDomainInfo:
return self.getDeviceController(deviceClass).destroyDevice(devid,
force)
def getDeviceSxprs(self, deviceClass):
- if self.state == DOM_STATE_RUNNING \
- or self.state == DOM_STATE_PAUSED:
+ if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
return self.getDeviceController(deviceClass).sxprs()
else:
sxprs = []
@@ -1579,11 +1581,10 @@ class XendDomainInfo:
def waitForShutdown(self):
self.state_updated.acquire()
try:
- while self.state in (DOM_STATE_RUNNING,DOM_STATE_PAUSED):
+ while self._stateGet() in (DOM_STATE_RUNNING,DOM_STATE_PAUSED):
self.state_updated.wait()
finally:
self.state_updated.release()
-
#
# TODO: recategorise - called from XendCheckpoint
@@ -1980,17 +1981,59 @@ class XendDomainInfo:
# Utility functions
#
+ def __getattr__(self, name):
+ if name == "state":
+ log.warn("Somebody tried to read XendDomainInfo.state... should
us _stateGet()!!!")
+ log.warn("".join(traceback.format_stack()))
+ return self._stateGet()
+ else:
+ raise AttributeError()
+
+ def __setattr__(self, name, value):
+ if name == "state":
+ log.warn("Somebody tried to set XendDomainInfo.state... should us
_stateGet()!!!")
+ log.warn("".join(traceback.format_stack()))
+ self._stateSet(value)
+ else:
+ self.__dict__[name] = value
+
def _stateSet(self, state):
self.state_updated.acquire()
try:
- if self.state != state:
- self.state = state
+ # TODO Not sure this is correct...
+ # _stateGet is live now. Why not fire event
+ # even when it hasn't changed?
+ if self._stateGet() != state:
self.state_updated.notifyAll()
import XendAPI
XendAPI.event_dispatch('mod', 'VM', self.info['uuid'],
'power_state')
finally:
self.state_updated.release()
+
+ def _stateGet(self):
+ # Lets try and reconsitute the state from xc
+ # first lets try and get the domain info
+ # from xc - this will tell us if the domain
+ # exists
+ info = dom_get(self.getDomid())
+ if info is None or info['shutdown']:
+ # We are either HALTED or SUSPENDED
+ # check saved image exists
+ from xen.xend import XendDomain
+ managed_config_path = \
+ XendDomain.instance()._managed_check_point_path( \
+ self.get_uuid())
+ if os.path.exists(managed_config_path):
+ return XEN_API_VM_POWER_STATE_SUSPENDED
+ else:
+ return XEN_API_VM_POWER_STATE_HALTED
+ else:
+ # We are either RUNNING or PAUSED
+ if info['paused']:
+ return XEN_API_VM_POWER_STATE_PAUSED
+ else:
+ return XEN_API_VM_POWER_STATE_RUNNING
def _infoIsSet(self, name):
return name in self.info and self.info[name] is not None
@@ -2107,7 +2150,7 @@ class XendDomainInfo:
retval = xc.sched_credit_domain_get(self.getDomid())
return retval
def get_power_state(self):
- return XEN_API_VM_POWER_STATE[self.state]
+ return XEN_API_VM_POWER_STATE[self._stateGet()]
def get_platform(self):
return self.info.get('platform', {})
def get_pci_bus(self):
@@ -2156,7 +2199,7 @@ class XendDomainInfo:
# shortcut if the domain isn't started because
# the devcontrollers will have no better information
# than XendConfig.
- if self.state in (XEN_API_VM_POWER_STATE_HALTED,):
+ if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED,):
if dev_config:
return copy.deepcopy(dev_config)
return None
@@ -2215,7 +2258,7 @@ class XendDomainInfo:
config['MTU'] = 1500 # TODO
- if self.state not in (XEN_API_VM_POWER_STATE_HALTED,):
+ if self._stateGet() not in (XEN_API_VM_POWER_STATE_HALTED,):
xennode = XendNode.instance()
rx_bps, tx_bps = xennode.get_vif_util(self.domid, devid)
config['io_read_kbs'] = rx_bps/1024
@@ -2226,7 +2269,7 @@ class XendDomainInfo:
if dev_class == 'vbd':
- if self.state not in (XEN_API_VM_POWER_STATE_HALTED,):
+ if self._stateGet() not in (XEN_API_VM_POWER_STATE_HALTED,):
controller = self.getDeviceController(dev_class)
devid, _1, _2 = controller.getDeviceDetails(config)
xennode = XendNode.instance()
@@ -2312,8 +2355,8 @@ class XendDomainInfo:
if not dev_uuid:
raise XendError('Failed to create device')
- if self.state == XEN_API_VM_POWER_STATE_RUNNING or \
- self.state == XEN_API_VM_POWER_STATE_PAUSED:
+ if self._stateGet() in (XEN_API_VM_POWER_STATE_RUNNING,
+ XEN_API_VM_POWER_STATE_PAUSED):
_, config = self.info['devices'][dev_uuid]
if vdi_image_path.startswith('tap'):
@@ -2347,7 +2390,7 @@ class XendDomainInfo:
if not dev_uuid:
raise XendError('Failed to create device')
- if self.state == XEN_API_VM_POWER_STATE_RUNNING:
+ if self._stateGet() == XEN_API_VM_POWER_STATE_RUNNING:
_, config = self.info['devices'][dev_uuid]
config['devid'] =
self.getDeviceController('tap').createDevice(config)
@@ -2364,8 +2407,8 @@ class XendDomainInfo:
if not dev_uuid:
raise XendError('Failed to create device')
- if self.state == XEN_API_VM_POWER_STATE_RUNNING \
- or self.state == XEN_API_VM_POWER_STATE_PAUSED:
+ if self._stateGet() in (XEN_API_VM_POWER_STATE_RUNNING,
+ XEN_API_VM_POWER_STATE_PAUSED):
_, config = self.info['devices'][dev_uuid]
dev_control = self.getDeviceController('vif')
@@ -2390,7 +2433,7 @@ class XendDomainInfo:
@rtype: string
"""
- if self.state not in (DOM_STATE_HALTED,):
+ if self._stateGet() not in (DOM_STATE_HALTED,):
raise VmError("Can only add vTPM to a halted domain.")
if self.get_vtpms() != []:
raise VmError('Domain already has a vTPM.')
@@ -2406,7 +2449,7 @@ class XendDomainInfo:
@return: uuid of device
@rtype: string
"""
- if self.state not in (DOM_STATE_HALTED,):
+ if self._stateGet() not in (DOM_STATE_HALTED,):
raise VmError("Can only add console to a halted domain.")
dev_uuid = self.info.device_add('console', cfg_xenapi = xenapi_console)
@@ -2420,8 +2463,8 @@ class XendDomainInfo:
raise XendError('Device does not exist')
try:
- if self.state == XEN_API_VM_POWER_STATE_RUNNING \
- or self.state == XEN_API_VM_POWER_STATE_PAUSED:
+ if self._stateGet() in (XEN_API_VM_POWER_STATE_RUNNING,
+ XEN_API_VM_POWER_STATE_PAUSED):
_, config = self.info['devices'][dev_uuid]
devid = config.get('devid')
if devid != None:
@@ -2448,7 +2491,7 @@ class XendDomainInfo:
def __str__(self):
return '<domain id=%s name=%s memory=%s state=%s>' % \
(str(self.domid), self.info['name_label'],
- str(self.info['memory_dynamic_max']), DOM_STATES[self.state])
+ str(self.info['memory_dynamic_max']),
DOM_STATES[self._stateGet()])
__repr__ = __str__
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|