ia64/xen-unstable

changeset 14887:55135bf6eb44

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>
author Tom Wilkie <tom.wilkie@gmail.com>
date Fri Apr 20 17:56:28 2007 +0100 (2007-04-20)
parents 53b1cfcf129f
children 9e44519ee9a2
files tools/python/xen/xend/XendCheckpoint.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/tools/python/xen/xend/XendCheckpoint.py	Fri Apr 20 17:51:10 2007 +0100
     1.2 +++ b/tools/python/xen/xend/XendCheckpoint.py	Fri Apr 20 17:56:28 2007 +0100
     1.3 @@ -253,8 +253,28 @@ def restore(xd, fd, dominfo = None, paus
     1.4          os.read(fd, 1)           # Wait for source to close connection
     1.5          
     1.6          dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
     1.7 -        
     1.8 -        dominfo.waitForDevices() # Wait for backends to set up
     1.9 +
    1.10 +        #
    1.11 +        # We shouldn't hold the domains_lock over a waitForDevices
    1.12 +        # As this function sometime gets called holding this lock,
    1.13 +        # we must release it and re-acquire it appropriately
    1.14 +        #
    1.15 +        from xen.xend import XendDomain
    1.16 +
    1.17 +        lock = True;
    1.18 +        try:
    1.19 +            XendDomain.instance().domains_lock.release()
    1.20 +        except:
    1.21 +            lock = False;
    1.22 +
    1.23 +        try:
    1.24 +            dominfo.waitForDevices() # Wait for backends to set up
    1.25 +        except Exception, exn:
    1.26 +            log.exception(exn)
    1.27 +
    1.28 +        if lock:
    1.29 +            XendDomain.instance().domains_lock.acquire()
    1.30 +
    1.31          if not paused:
    1.32              dominfo.unpause()
    1.33  
     2.1 --- a/tools/python/xen/xend/XendConfig.py	Fri Apr 20 17:51:10 2007 +0100
     2.2 +++ b/tools/python/xen/xend/XendConfig.py	Fri Apr 20 17:56:28 2007 +0100
     2.3 @@ -870,7 +870,7 @@ class XendConfig(dict):
     2.4                  sxpr.append([legacy, self[legacy]])
     2.5  
     2.6          sxpr.append(['image', self.image_sxpr()])
     2.7 -        sxpr.append(['status', domain.state])
     2.8 +        sxpr.append(['status', domain._stateGet()])
     2.9  
    2.10          if domain.getDomid() is not None:
    2.11              sxpr.append(['state', self._get_old_state_string()])
     3.1 --- a/tools/python/xen/xend/XendDomain.py	Fri Apr 20 17:51:10 2007 +0100
     3.2 +++ b/tools/python/xen/xend/XendDomain.py	Fri Apr 20 17:56:28 2007 +0100
     3.3 @@ -45,6 +45,7 @@ from xen.xend.XendConstants import DOM_S
     3.4  from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN
     3.5  from xen.xend.XendConstants import TRIGGER_TYPE
     3.6  from xen.xend.XendDevices import XendDevices
     3.7 +from xen.xend.XendAPIConstants import *
     3.8  
     3.9  from xen.xend.xenstore.xstransact import xstransact
    3.10  from xen.xend.xenstore.xswatch import xswatch
    3.11 @@ -457,7 +458,7 @@ class XendDomain:
    3.12              if domid == None:
    3.13                  domid = info.getDomid()
    3.14  
    3.15 -            if info.state != DOM_STATE_HALTED:
    3.16 +            if info._stateGet() != DOM_STATE_HALTED:
    3.17                  info.cleanupDomain()
    3.18              
    3.19              if domid in self.domains:
    3.20 @@ -577,7 +578,7 @@ class XendDomain:
    3.21          self.domains_lock.acquire()
    3.22          try:
    3.23              for dom_uuid, dom in self.managed_domains.items():
    3.24 -                if dom and dom.state == DOM_STATE_HALTED:
    3.25 +                if dom and dom._stateGet() == DOM_STATE_HALTED:
    3.26                      on_xend_start = dom.info.get('on_xend_start', 'ignore')
    3.27                      auto_power_on = dom.info.get('auto_power_on', False)
    3.28                      should_start = (on_xend_start == 'start') or auto_power_on
    3.29 @@ -602,7 +603,7 @@ class XendDomain:
    3.30                  if dom.getName() == DOM0_NAME:
    3.31                      continue
    3.32                  
    3.33 -                if dom.state == DOM_STATE_RUNNING:
    3.34 +                if dom._stateGet() == DOM_STATE_RUNNING:
    3.35                      shutdownAction = dom.info.get('on_xend_stop', 'ignore')
    3.36                      if shutdownAction == 'shutdown':
    3.37                          log.debug('Shutting down domain: %s' % dom.getName())
    3.38 @@ -780,7 +781,7 @@ class XendDomain:
    3.39                  return active_domains + inactive_domains
    3.40              else:
    3.41                  return filter(lambda x:
    3.42 -                                  POWER_STATE_NAMES[x.state].lower() == state,
    3.43 +                                  POWER_STATE_NAMES[x._stateGet()].lower() == state,
    3.44                                active_domains + inactive_domains)
    3.45          finally:
    3.46              self.domains_lock.release()
    3.47 @@ -825,10 +826,10 @@ class XendDomain:
    3.48              if dominfo.getDomid() == DOM0_ID:
    3.49                  raise XendError("Cannot save privileged domain %s" % domname)
    3.50  
    3.51 -            if dominfo.state != DOM_STATE_RUNNING:
    3.52 +            if dominfo._stateGet() != DOM_STATE_RUNNING:
    3.53                  raise VMBadState("Domain is not running",
    3.54                                   POWER_STATE_NAMES[DOM_STATE_RUNNING],
    3.55 -                                 POWER_STATE_NAMES[dominfo.state])
    3.56 +                                 POWER_STATE_NAMES[dominfo._stateGet()])
    3.57  
    3.58              dom_uuid = dominfo.get_uuid()
    3.59  
    3.60 @@ -869,8 +870,8 @@ class XendDomain:
    3.61                  if dominfo.getDomid() == DOM0_ID:
    3.62                      raise XendError("Cannot save privileged domain %s" % domname)
    3.63  
    3.64 -                if dominfo.state != DOM_STATE_HALTED:
    3.65 -                    raise XendError("Cannot resume domain that is not halted.")
    3.66 +                if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
    3.67 +                    raise XendError("Cannot resume domain that is not suspended.")
    3.68  
    3.69                  dom_uuid = dominfo.get_uuid()
    3.70                  chkpath = self._managed_check_point_path(dom_uuid)
    3.71 @@ -879,7 +880,7 @@ class XendDomain:
    3.72  
    3.73                  # Restore that replaces the existing XendDomainInfo
    3.74                  try:
    3.75 -                    log.debug('Current DomainInfo state: %d' % dominfo.state)
    3.76 +                    log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
    3.77                      oflags = os.O_RDONLY
    3.78                      if hasattr(os, "O_LARGEFILE"):
    3.79                          oflags |= os.O_LARGEFILE
    3.80 @@ -974,10 +975,10 @@ class XendDomain:
    3.81              if not dominfo:
    3.82                  raise XendInvalidDomain(str(domid))
    3.83  
    3.84 -            if dominfo.state != DOM_STATE_HALTED:
    3.85 +            if dominfo._stateGet() != DOM_STATE_HALTED:
    3.86                  raise VMBadState("Domain is already running",
    3.87                                   POWER_STATE_NAMES[DOM_STATE_HALTED],
    3.88 -                                 POWER_STATE_NAMES[dominfo.state])
    3.89 +                                 POWER_STATE_NAMES[dominfo._stateGet()])
    3.90              
    3.91              dominfo.start(is_managed = True)
    3.92          finally:
    3.93 @@ -1003,10 +1004,10 @@ class XendDomain:
    3.94                  if not dominfo:
    3.95                      raise XendInvalidDomain(str(domid))
    3.96  
    3.97 -                if dominfo.state != DOM_STATE_HALTED:
    3.98 -                    raise VMBadState("Domain is still running",
    3.99 +                if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
   3.100 +                    raise VMBadState("Domain is not halted.",
   3.101                                       POWER_STATE_NAMES[DOM_STATE_HALTED],
   3.102 -                                     POWER_STATE_NAMES[dominfo.state])
   3.103 +                                     POWER_STATE_NAMES[dominfo._stateGet()])
   3.104                  
   3.105                  self._domain_delete_by_info(dominfo)
   3.106              except Exception, ex:
     4.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Apr 20 17:51:10 2007 +0100
     4.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Apr 20 17:56:28 2007 +0100
     4.3 @@ -30,6 +30,7 @@ import threading
     4.4  import re
     4.5  import copy
     4.6  import os
     4.7 +import traceback
     4.8  from types import StringTypes
     4.9  
    4.10  import xen.lowlevel.xc
    4.11 @@ -309,8 +310,8 @@ class XendDomainInfo:
    4.12      @type shutdownWatch: xen.xend.xenstore.xswatch
    4.13      @ivar shutdownStartTime: UNIX Time when domain started shutting down.
    4.14      @type shutdownStartTime: float or None
    4.15 -    @ivar state: Domain state
    4.16 -    @type state: enum(DOM_STATE_HALTED, DOM_STATE_RUNNING, ...)
    4.17 +#    @ivar state: Domain state
    4.18 +#    @type state: enum(DOM_STATE_HALTED, DOM_STATE_RUNNING, ...)
    4.19      @ivar state_updated: lock for self.state
    4.20      @type state_updated: threading.Condition
    4.21      @ivar refresh_shutdown_lock: lock for polling shutdown state
    4.22 @@ -361,9 +362,9 @@ class XendDomainInfo:
    4.23          self.shutdownStartTime = None
    4.24          self._resume = resume
    4.25  
    4.26 -        self.state = DOM_STATE_HALTED
    4.27          self.state_updated = threading.Condition()
    4.28          self.refresh_shutdown_lock = threading.Condition()
    4.29 +        self._stateSet(DOM_STATE_HALTED)
    4.30  
    4.31          self._deviceControllers = {}
    4.32  
    4.33 @@ -389,7 +390,7 @@ class XendDomainInfo:
    4.34          """
    4.35          from xen.xend import XendDomain
    4.36  
    4.37 -        if self.state == DOM_STATE_HALTED:
    4.38 +        if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED, XEN_API_VM_POWER_STATE_SUSPENDED):
    4.39              try:
    4.40                  XendTask.log_progress(0, 30, self._constructDomain)
    4.41                  XendTask.log_progress(31, 60, self._initDomain)
    4.42 @@ -420,7 +421,8 @@ class XendDomainInfo:
    4.43  
    4.44      def resume(self):
    4.45          """Resumes a domain that has come back from suspension."""
    4.46 -        if self.state in (DOM_STATE_HALTED, DOM_STATE_SUSPENDED):
    4.47 +        state = self._stateGet()
    4.48 +        if state in (DOM_STATE_SUSPENDED, DOM_STATE_HALTED):
    4.49              try:
    4.50                  self._constructDomain()
    4.51                  self._storeVmDetails()
    4.52 @@ -433,12 +435,13 @@ class XendDomainInfo:
    4.53                  self.destroy()
    4.54                  raise
    4.55          else:
    4.56 -            raise XendError('VM already running')
    4.57 +            raise XendError('VM is not susupened; it is %s'
    4.58 +                            % XEN_API_VM_POWER_STATE[state])
    4.59  
    4.60      def shutdown(self, reason):
    4.61          """Shutdown a domain by signalling this via xenstored."""
    4.62          log.debug('XendDomainInfo.shutdown(%s)', reason)
    4.63 -        if self.state in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
    4.64 +        if self._stateGet() in (DOM_STATE_SHUTDOWN, DOM_STATE_HALTED,):
    4.65              raise XendError('Domain cannot be shutdown')
    4.66  
    4.67          if self.domid == 0:
    4.68 @@ -558,8 +561,7 @@ class XendDomainInfo:
    4.69          return self.getDeviceController(deviceClass).destroyDevice(devid, force)
    4.70  
    4.71      def getDeviceSxprs(self, deviceClass):
    4.72 -        if self.state == DOM_STATE_RUNNING \
    4.73 -               or self.state == DOM_STATE_PAUSED:
    4.74 +        if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
    4.75              return self.getDeviceController(deviceClass).sxprs()
    4.76          else:
    4.77              sxprs = []
    4.78 @@ -1579,12 +1581,11 @@ class XendDomainInfo:
    4.79      def waitForShutdown(self):
    4.80          self.state_updated.acquire()
    4.81          try:
    4.82 -            while self.state in (DOM_STATE_RUNNING,DOM_STATE_PAUSED):
    4.83 +            while self._stateGet() in (DOM_STATE_RUNNING,DOM_STATE_PAUSED):
    4.84                  self.state_updated.wait()
    4.85          finally:
    4.86              self.state_updated.release()
    4.87  
    4.88 -
    4.89      #
    4.90      # TODO: recategorise - called from XendCheckpoint
    4.91      # 
    4.92 @@ -1980,11 +1981,29 @@ class XendDomainInfo:
    4.93      # Utility functions
    4.94      #
    4.95  
    4.96 +    def __getattr__(self, name):
    4.97 +         if name == "state":
    4.98 +             log.warn("Somebody tried to read XendDomainInfo.state... should us _stateGet()!!!")
    4.99 +             log.warn("".join(traceback.format_stack()))
   4.100 +             return self._stateGet()
   4.101 +         else:
   4.102 +             raise AttributeError()
   4.103 +
   4.104 +    def __setattr__(self, name, value):
   4.105 +        if name == "state":
   4.106 +            log.warn("Somebody tried to set XendDomainInfo.state... should us _stateGet()!!!")
   4.107 +            log.warn("".join(traceback.format_stack()))
   4.108 +            self._stateSet(value)
   4.109 +        else:
   4.110 +            self.__dict__[name] = value
   4.111 +
   4.112      def _stateSet(self, state):
   4.113          self.state_updated.acquire()
   4.114          try:
   4.115 -            if self.state != state:
   4.116 -                self.state = state
   4.117 +            # TODO Not sure this is correct...
   4.118 +            # _stateGet is live now. Why not fire event
   4.119 +            # even when it hasn't changed?
   4.120 +            if self._stateGet() != state:
   4.121                  self.state_updated.notifyAll()
   4.122                  import XendAPI
   4.123                  XendAPI.event_dispatch('mod', 'VM', self.info['uuid'],
   4.124 @@ -1992,6 +2011,30 @@ class XendDomainInfo:
   4.125          finally:
   4.126              self.state_updated.release()
   4.127  
   4.128 +    def _stateGet(self):
   4.129 +        # Lets try and reconsitute the state from xc
   4.130 +        # first lets try and get the domain info
   4.131 +        # from xc - this will tell us if the domain
   4.132 +        # exists
   4.133 +        info = dom_get(self.getDomid())
   4.134 +        if info is None or info['shutdown']:
   4.135 +            # We are either HALTED or SUSPENDED
   4.136 +            # check saved image exists
   4.137 +            from xen.xend import XendDomain
   4.138 +            managed_config_path = \
   4.139 +                XendDomain.instance()._managed_check_point_path( \
   4.140 +                    self.get_uuid())
   4.141 +            if os.path.exists(managed_config_path):
   4.142 +                return XEN_API_VM_POWER_STATE_SUSPENDED
   4.143 +            else:
   4.144 +                return XEN_API_VM_POWER_STATE_HALTED
   4.145 +        else:
   4.146 +            # We are either RUNNING or PAUSED
   4.147 +            if info['paused']:
   4.148 +                return XEN_API_VM_POWER_STATE_PAUSED
   4.149 +            else:
   4.150 +                return XEN_API_VM_POWER_STATE_RUNNING
   4.151 +
   4.152      def _infoIsSet(self, name):
   4.153          return name in self.info and self.info[name] is not None
   4.154  
   4.155 @@ -2107,7 +2150,7 @@ class XendDomainInfo:
   4.156          retval = xc.sched_credit_domain_get(self.getDomid())
   4.157          return retval
   4.158      def get_power_state(self):
   4.159 -        return XEN_API_VM_POWER_STATE[self.state]
   4.160 +        return XEN_API_VM_POWER_STATE[self._stateGet()]
   4.161      def get_platform(self):
   4.162          return self.info.get('platform', {})    
   4.163      def get_pci_bus(self):
   4.164 @@ -2156,7 +2199,7 @@ class XendDomainInfo:
   4.165          # shortcut if the domain isn't started because
   4.166          # the devcontrollers will have no better information
   4.167          # than XendConfig.
   4.168 -        if self.state in (XEN_API_VM_POWER_STATE_HALTED,):
   4.169 +        if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED,):
   4.170              if dev_config:
   4.171                  return copy.deepcopy(dev_config)
   4.172              return None
   4.173 @@ -2215,7 +2258,7 @@ class XendDomainInfo:
   4.174  
   4.175              config['MTU'] = 1500 # TODO
   4.176              
   4.177 -            if self.state not in (XEN_API_VM_POWER_STATE_HALTED,):
   4.178 +            if self._stateGet() not in (XEN_API_VM_POWER_STATE_HALTED,):
   4.179                  xennode = XendNode.instance()
   4.180                  rx_bps, tx_bps = xennode.get_vif_util(self.domid, devid)
   4.181                  config['io_read_kbs'] = rx_bps/1024
   4.182 @@ -2226,7 +2269,7 @@ class XendDomainInfo:
   4.183  
   4.184          if dev_class == 'vbd':
   4.185  
   4.186 -            if self.state not in (XEN_API_VM_POWER_STATE_HALTED,):
   4.187 +            if self._stateGet() not in (XEN_API_VM_POWER_STATE_HALTED,):
   4.188                  controller = self.getDeviceController(dev_class)
   4.189                  devid, _1, _2 = controller.getDeviceDetails(config)
   4.190                  xennode = XendNode.instance()
   4.191 @@ -2312,8 +2355,8 @@ class XendDomainInfo:
   4.192          if not dev_uuid:
   4.193              raise XendError('Failed to create device')
   4.194  
   4.195 -        if self.state == XEN_API_VM_POWER_STATE_RUNNING or \
   4.196 -               self.state == XEN_API_VM_POWER_STATE_PAUSED:
   4.197 +        if self._stateGet() in (XEN_API_VM_POWER_STATE_RUNNING,
   4.198 +                                XEN_API_VM_POWER_STATE_PAUSED):
   4.199              _, config = self.info['devices'][dev_uuid]
   4.200              
   4.201              if vdi_image_path.startswith('tap'):
   4.202 @@ -2347,7 +2390,7 @@ class XendDomainInfo:
   4.203          if not dev_uuid:
   4.204              raise XendError('Failed to create device')
   4.205  
   4.206 -        if self.state == XEN_API_VM_POWER_STATE_RUNNING:
   4.207 +        if self._stateGet() == XEN_API_VM_POWER_STATE_RUNNING:
   4.208              _, config = self.info['devices'][dev_uuid]
   4.209              config['devid'] = self.getDeviceController('tap').createDevice(config)
   4.210  
   4.211 @@ -2364,8 +2407,8 @@ class XendDomainInfo:
   4.212          if not dev_uuid:
   4.213              raise XendError('Failed to create device')
   4.214          
   4.215 -        if self.state == XEN_API_VM_POWER_STATE_RUNNING \
   4.216 -               or self.state == XEN_API_VM_POWER_STATE_PAUSED:
   4.217 +        if self._stateGet() in (XEN_API_VM_POWER_STATE_RUNNING,
   4.218 +                                XEN_API_VM_POWER_STATE_PAUSED):
   4.219  
   4.220              _, config = self.info['devices'][dev_uuid]
   4.221              dev_control = self.getDeviceController('vif')
   4.222 @@ -2390,7 +2433,7 @@ class XendDomainInfo:
   4.223          @rtype: string
   4.224          """
   4.225  
   4.226 -        if self.state not in (DOM_STATE_HALTED,):
   4.227 +        if self._stateGet() not in (DOM_STATE_HALTED,):
   4.228              raise VmError("Can only add vTPM to a halted domain.")
   4.229          if self.get_vtpms() != []:
   4.230              raise VmError('Domain already has a vTPM.')
   4.231 @@ -2406,7 +2449,7 @@ class XendDomainInfo:
   4.232          @return: uuid of device
   4.233          @rtype: string
   4.234          """
   4.235 -        if self.state not in (DOM_STATE_HALTED,):
   4.236 +        if self._stateGet() not in (DOM_STATE_HALTED,):
   4.237              raise VmError("Can only add console to a halted domain.")
   4.238  
   4.239          dev_uuid = self.info.device_add('console', cfg_xenapi = xenapi_console)
   4.240 @@ -2420,8 +2463,8 @@ class XendDomainInfo:
   4.241              raise XendError('Device does not exist')
   4.242  
   4.243          try:
   4.244 -            if self.state == XEN_API_VM_POWER_STATE_RUNNING \
   4.245 -                   or self.state == XEN_API_VM_POWER_STATE_PAUSED:
   4.246 +            if self._stateGet() in (XEN_API_VM_POWER_STATE_RUNNING,
   4.247 +                                    XEN_API_VM_POWER_STATE_PAUSED):
   4.248                  _, config = self.info['devices'][dev_uuid]
   4.249                  devid = config.get('devid')
   4.250                  if devid != None:
   4.251 @@ -2448,7 +2491,7 @@ class XendDomainInfo:
   4.252      def __str__(self):
   4.253          return '<domain id=%s name=%s memory=%s state=%s>' % \
   4.254                 (str(self.domid), self.info['name_label'],
   4.255 -                str(self.info['memory_dynamic_max']), DOM_STATES[self.state])
   4.256 +                str(self.info['memory_dynamic_max']), DOM_STATES[self._stateGet()])
   4.257  
   4.258      __repr__ = __str__
   4.259