ia64/xen-unstable

changeset 7863:32b574b24b18

Watch for changes in the /vm section of the store, so that we update our
internal state if the store is configured by an external tool.

We react properly to changes in name and on_{reboot,poweroff,crash}. Reacting
correctly to vcpus, vcpu_avail, memory, and maxmem will come soon (those code
aspects are already under review). cpu_weight and bootloader to be considered.

Removed unused and semantically invalid method XendDomainInfo.setDomid.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Wed Nov 16 15:32:56 2005 +0100 (2005-11-16)
parents 3631592ad7d3
children 9b345321fd06
files tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Wed Nov 16 15:27:59 2005 +0100
     1.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Nov 16 15:32:56 2005 +0100
     1.3 @@ -45,6 +45,8 @@ import uuid
     1.4  
     1.5  from xen.xend.xenstore.xstransact import xstransact
     1.6  from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain
     1.7 +from xen.xend.xenstore.xswatch import xswatch
     1.8 +
     1.9  
    1.10  """Shutdown code for poweroff."""
    1.11  DOMAIN_POWEROFF = 0
    1.12 @@ -82,7 +84,6 @@ STATE_DOM_SHUTDOWN = 2
    1.13  
    1.14  SHUTDOWN_TIMEOUT = 30
    1.15  
    1.16 -DOMROOT = '/local/domain/'
    1.17  VMROOT  = '/vm/'
    1.18  
    1.19  ZOMBIE_PREFIX = 'Zombie-'
    1.20 @@ -100,27 +101,53 @@ log = logging.getLogger("xend.XendDomain
    1.21  #log.setLevel(logging.TRACE)
    1.22  
    1.23  
    1.24 -## Configuration entries that we expect to round-trip -- be read from the
    1.25 +##
    1.26 +# All parameters of VMs that may be configured on-the-fly, or at start-up.
    1.27 +# 
    1.28 +VM_CONFIG_PARAMS = [
    1.29 +    ('name',        str),
    1.30 +    ('on_poweroff', str),
    1.31 +    ('on_reboot',   str),
    1.32 +    ('on_crash',    str),
    1.33 +    ]
    1.34 +
    1.35 +
    1.36 +##
    1.37 +# Configuration entries that we expect to round-trip -- be read from the
    1.38  # config file or xc, written to save-files (i.e. through sxpr), and reused as
    1.39  # config on restart or restore, all without munging.  Some configuration
    1.40  # entries are munged for backwards compatibility reasons, or because they
    1.41  # don't come out of xc in the same form as they are specified in the config
    1.42  # file, so those are handled separately.
    1.43  ROUNDTRIPPING_CONFIG_ENTRIES = [
    1.44 -        ('name',         str),
    1.45 -        ('uuid',         str),
    1.46 -        ('ssidref',      int),
    1.47 -        ('vcpus',        int),
    1.48 -        ('vcpu_avail',   int),
    1.49 -        ('cpu_weight',   float),
    1.50 -        ('memory',       int),
    1.51 -        ('maxmem',       int),
    1.52 -        ('bootloader',   str),
    1.53 -        ('on_poweroff',  str),
    1.54 -        ('on_reboot',    str),
    1.55 -        ('on_crash',     str)
    1.56 +    ('uuid',       str),
    1.57 +    ('ssidref',    int),
    1.58 +    ('vcpus',      int),
    1.59 +    ('vcpu_avail', int),
    1.60 +    ('cpu_weight', float),
    1.61 +    ('memory',     int),
    1.62 +    ('maxmem',     int),
    1.63 +    ('bootloader', str),
    1.64      ]
    1.65  
    1.66 +ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_PARAMS
    1.67 +
    1.68 +
    1.69 +##
    1.70 +# All entries written to the store.  This is VM_CONFIGURATION_PARAMS, plus
    1.71 +# those entries written to the store that cannot be reconfigured on-the-fly.
    1.72 +#
    1.73 +VM_STORE_ENTRIES = [
    1.74 +    ('uuid',       str),
    1.75 +    ('ssidref',    int),
    1.76 +    ('vcpus',      int),
    1.77 +    ('vcpu_avail', int),
    1.78 +    ('memory',     int),
    1.79 +    ('maxmem',     int),
    1.80 +    ]
    1.81 +
    1.82 +VM_STORE_ENTRIES += VM_CONFIG_PARAMS
    1.83 +
    1.84  
    1.85  #
    1.86  # There are a number of CPU-related fields:
    1.87 @@ -156,6 +183,7 @@ def create(config):
    1.88          vm.initDomain()
    1.89          vm.storeVmDetails()
    1.90          vm.storeDomDetails()
    1.91 +        vm.registerWatch()
    1.92          vm.refreshShutdown()
    1.93          return vm
    1.94      except:
    1.95 @@ -211,6 +239,7 @@ def recreate(xeninfo, priv):
    1.96          vm.storeVmDetails()
    1.97          vm.storeDomDetails()
    1.98  
    1.99 +    vm.registerWatch()
   1.100      vm.refreshShutdown(xeninfo)
   1.101      return vm
   1.102  
   1.103 @@ -371,6 +400,8 @@ class XendDomainInfo:
   1.104          self.console_port = None
   1.105          self.console_mfn = None
   1.106  
   1.107 +        self.vmWatch = None
   1.108 +
   1.109          self.state = STATE_DOM_OK
   1.110          self.state_updated = threading.Condition()
   1.111          self.refresh_shutdown_lock = threading.Condition()
   1.112 @@ -378,6 +409,42 @@ class XendDomainInfo:
   1.113  
   1.114      ## private:
   1.115  
   1.116 +    def readVMDetails(self, params):
   1.117 +        """Read from the store all of those entries that we consider 
   1.118 +        """
   1.119 +        try:
   1.120 +            return self.gatherVm(*params)
   1.121 +        except ValueError:
   1.122 +            # One of the int/float entries in params has a corresponding store
   1.123 +            # entry that is invalid.  We recover, because older versions of
   1.124 +            # Xend may have put the entry there (memory/target, for example),
   1.125 +            # but this is in general a bad situation to have reached.
   1.126 +            log.exception(
   1.127 +                "Store corrupted at %s!  Domain %d's configuration may be "
   1.128 +                "affected.", self.vmpath, self.domid)
   1.129 +            return []
   1.130 +
   1.131 +
   1.132 +    def storeChanged(self):
   1.133 +        log.debug("XendDomainInfo.storeChanged");
   1.134 +
   1.135 +        changed = False
   1.136 +        
   1.137 +        def f(x, y):
   1.138 +            if y is not None and self.info[x[0]] != y:
   1.139 +                self.info[x[0]] = y
   1.140 +                changed = True
   1.141 +
   1.142 +        map(f, VM_CONFIG_PARAMS, self.readVMDetails(VM_CONFIG_PARAMS))
   1.143 +
   1.144 +        if changed:
   1.145 +            # Update the domain section of the store, as this contains some
   1.146 +            # parameters derived from the VM configuration.
   1.147 +            self.storeDomDetails()
   1.148 +
   1.149 +        return 1
   1.150 +
   1.151 +
   1.152      def augmentInfo(self):
   1.153          """Augment self.info, as given to us through {@link #recreate}, with
   1.154          values taken from the store.  This recovers those values known to xend
   1.155 @@ -387,30 +454,8 @@ class XendDomainInfo:
   1.156              if not self.infoIsSet(name) and val is not None:
   1.157                  self.info[name] = val
   1.158  
   1.159 -        params = (("name", str),
   1.160 -                  ("on_poweroff",  str),
   1.161 -                  ("on_reboot",    str),
   1.162 -                  ("on_crash",     str),
   1.163 -                  ("image",        str),
   1.164 -                  ("memory",       int),
   1.165 -                  ("maxmem",       int),
   1.166 -                  ("vcpus",        int),
   1.167 -                  ("vcpu_avail",   int),
   1.168 -                  ("start_time", float))
   1.169 -
   1.170 -        try:
   1.171 -            from_store = self.gatherVm(*params)
   1.172 -        except ValueError, exn:
   1.173 -            # One of the int/float entries in params has a corresponding store
   1.174 -            # entry that is invalid.  We recover, because older versions of
   1.175 -            # Xend may have put the entry there (memory/target, for example),
   1.176 -            # but this is in general a bad situation to have reached.
   1.177 -            log.exception(
   1.178 -                "Store corrupted at %s!  Domain %d's configuration may be "
   1.179 -                "affected.", self.vmpath, self.domid)
   1.180 -            return
   1.181 -
   1.182 -        map(lambda x, y: useIfNeeded(x[0], y), params, from_store)
   1.183 +        map(lambda x, y: useIfNeeded(x[0], y), VM_STORE_ENTRIES,
   1.184 +            self.readVMDetails(VM_STORE_ENTRIES))
   1.185  
   1.186          device = []
   1.187          for c in controllerClasses:
   1.188 @@ -536,23 +581,23 @@ class XendDomainInfo:
   1.189  
   1.190          self.introduceDomain()
   1.191          self.storeDomDetails()
   1.192 +        self.registerWatch()
   1.193          self.refreshShutdown()
   1.194  
   1.195          log.debug("XendDomainInfo.completeRestore done")
   1.196  
   1.197  
   1.198      def storeVmDetails(self):
   1.199 -        to_store = {
   1.200 -            'uuid':               self.info['uuid']
   1.201 -            }
   1.202 +        to_store = {}
   1.203 +
   1.204 +        for k in VM_STORE_ENTRIES:
   1.205 +            if self.infoIsSet(k[0]):
   1.206 +                to_store[k[0]] = str(self.info[k[0]])
   1.207  
   1.208          if self.infoIsSet('image'):
   1.209              to_store['image'] = sxp.to_string(self.info['image'])
   1.210  
   1.211 -        for k in ['name', 'ssidref', 'memory', 'maxmem', 'on_poweroff',
   1.212 -                  'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail']:
   1.213 -            if self.infoIsSet(k):
   1.214 -                to_store[k] = str(self.info[k])
   1.215 +        to_store['start_time'] = str(self.info['start_time'])
   1.216  
   1.217          log.debug("Storing VM details: %s", to_store)
   1.218  
   1.219 @@ -599,13 +644,16 @@ class XendDomainInfo:
   1.220          return result
   1.221  
   1.222  
   1.223 -    def setDomid(self, domid):
   1.224 -        """Set the domain id.
   1.225 +    ## public:
   1.226  
   1.227 -        @param dom: domain id
   1.228 -        """
   1.229 -        self.domid = domid
   1.230 -        self.storeDom("domid", self.domid)
   1.231 +    def registerWatch(self):
   1.232 +        """Register a watch on this VM's entries in the store, so that
   1.233 +        when they are changed externally, we keep up to date.  This should
   1.234 +        only be called by {@link #create}, {@link #recreate}, or {@link
   1.235 +        #restore}, once the domain's details have been written, but before the
   1.236 +        new instance is returned."""
   1.237 +        self.vmWatch = xswatch(self.vmpath, self.storeChanged)
   1.238 +
   1.239  
   1.240      def getDomid(self):
   1.241          return self.domid
   1.242 @@ -1116,6 +1164,13 @@ class XendDomainInfo:
   1.243          """Cleanup VM resources.  Idempotent.  Nothrow guarantee."""
   1.244  
   1.245          try:
   1.246 +            try:
   1.247 +                if self.vmWatch:
   1.248 +                    self.vmWatch.unwatch()
   1.249 +                self.vmWatch = None
   1.250 +            except:
   1.251 +                log.exception("Unwatching VM path failed.")
   1.252 +
   1.253              self.removeVm()
   1.254          except:
   1.255              log.exception("Removing VM path failed.")