mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
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@gmail.com>
This commit is contained in:
1 parent
d1672c6b39
commit
edec108b06
4 files changed
+108
-44
No files matched your search
@@ -253,8 +253,28 @@ def restore(xd, fd, dominfo = None, paused = False):
|
||||
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()
|
||||
|
||||
|
||||
@@ -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()])
|
||||
|
||||
@@ -45,6 +45,7 @@ from xen.xend.XendConstants import DOM_STATE_RUNNING, DOM_STATE_SUSPENDED
|
||||
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:
|
||||
|
||||
@@ -30,6 +30,7 @@ import threading
|
||||
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,12 +1581,11 @@ 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,11 +1981,29 @@ 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'],
|
||||
@@ -1992,6 +2011,30 @@ class XendDomainInfo:
|
||||
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__
|
||||
|
||||