ia64/xen-unstable

changeset 7006:9647be59212d

Split the configuration file parsing and xc dominfo parsing aspects of
XendDomainInfo out from the rest of the code, creating an intermediate
dictionary of common format. This means that the rest of XendDomainInfo can
work whether creating a domain for the first time, or whether xend is
restarted but the domains still exist. This means that xend is now robust in
the face of restarts. The phase of validation of configuration details is
now more explicit, and stronger too.

Change the handling of memory sizes in XendDomainInfo's interface to use KiB
in setMemoryTarget and getMemoryTarget. This gives reasonable granularity
whilst ensuring that we can handle values up to 2TiB without overflowing a
signed 32 bit value. It is not clear that the xend code, especially the C /
Python interface, is either 64-bit clean or unsigned 32-bit clean, so this is
the safest choice for now. The behaviour of Python's shift operator will
change in Python 2.4, so it is best to address this problem once we have moved
to that version.

Determine the backend flags on-the-fly, in getBackendFlags, rather than
computing them in advance in configureBackends and storing the value. Change
addControllerClass so that backend flag information is in this table too,
rather than hard-coded elsewhere.

Improve the error reporting for name clashes.

Remove XendDomainInfo's dependence upon DBMap, and use xstransact directly
instead. This changes the interface from XendDomain to XendDomainInfo, as
paths rather than DBMaps are passed in.

Remove the XendDomainInfo.recreate and restore flags. Since the device and
domain handling is now stateless inside xend, much less work is necessary for
recreate and restore procedures, so we can do without these flags.

Remove XendDomainInfo's unused dependency upon SrvDaemon, and its unnecessary
dependence upon PrettyPrint. Remove the unused show method.

Decouple image.py from XendDomainInfo.bootloader by passing a bootloading flag
into initDomain instead. Decouple it from XendDomainInfo.config by passing
the semiparsed device configuration into create(). Move configuration in
VmxImageHandler so that rather than being scattered around the class it is in
or called from the configure method. Device configuration is no longer
available anywhere else.

From Dan Smith <danms@us.ibm.com>:

I could not find in the existing code the point at which
a domain was added to the XendDomain list after restore. Several
attempts to restore would result in positive log messages, but the
restored domain would not show up in "xm list". This patch includes a
call to _add_domain(), which results in restore working for me.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Wed Sep 21 15:23:26 2005 +0100 (2005-09-21)
parents 19572dec7d3c
children 55fc0ecc19c3
files tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/image.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomain.py	Wed Sep 21 15:13:26 2005 +0100
     1.2 +++ b/tools/python/xen/xend/XendDomain.py	Wed Sep 21 15:23:26 2005 +0100
     1.3 @@ -14,17 +14,14 @@
     1.4  #============================================================================
     1.5  # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
     1.6  # Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
     1.7 +# Copyright (C) 2005 XenSource Ltd
     1.8  #============================================================================
     1.9  
    1.10  """Handler for domain operations.
    1.11   Nothing here is persistent (across reboots).
    1.12   Needs to be persistent for one uptime.
    1.13  """
    1.14 -import errno
    1.15  import os
    1.16 -import sys
    1.17 -import time
    1.18 -import traceback
    1.19  
    1.20  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
    1.21  
    1.22 @@ -155,10 +152,8 @@ class XendDomain:
    1.23                  continue
    1.24              log.info("recreating domain %d, uuid %s" % (domid, uuid))
    1.25              dompath = "/".join(dompath.split("/")[0:-1])
    1.26 -            db = self.dbmap.addChild("%s/xend" % uuid)
    1.27              try:
    1.28 -                dominfo = XendDomainInfo.recreate(uuid, dompath, domid, db,
    1.29 -                                                  dom)
    1.30 +                dominfo = XendDomainInfo.recreate(uuid, dompath, domid, dom)
    1.31              except Exception, ex:
    1.32                  log.exception("Error recreating domain info: id=%d", domid)
    1.33                  continue
    1.34 @@ -275,7 +270,7 @@ class XendDomain:
    1.35          @param config: configuration
    1.36          @return: domain
    1.37          """
    1.38 -        dominfo = XendDomainInfo.create(self.dbmap, config)
    1.39 +        dominfo = XendDomainInfo.create(self.dbmap.getPath(), config)
    1.40          self._add_domain(dominfo)
    1.41          return dominfo
    1.42  
    1.43 @@ -310,8 +305,7 @@ class XendDomain:
    1.44          @param vmconfig: vm configuration
    1.45          """
    1.46          config = sxp.child_value(vmconfig, 'config')
    1.47 -        dominfo = XendDomainInfo.restore(self.dbmap, config)
    1.48 -        return dominfo
    1.49 +        return XendDomainInfo.restore(self.dbmap.getPath(), config)
    1.50  
    1.51      def domain_restore(self, src, progress=False):
    1.52          """Restore a domain from file.
    1.53 @@ -353,15 +347,15 @@ class XendDomain:
    1.54              dompath = self.domroot
    1.55          log.info("Creating entry for unknown xend domain: id=%d uuid=%s",
    1.56                   dom0, uuid)
    1.57 -        db = self.dbmap.addChild("%s/xend" % uuid)
    1.58          try:
    1.59 -            dominfo = XendDomainInfo.recreate(uuid, dompath, dom0,
    1.60 -                                              db, info)
    1.61 -        except:
    1.62 -            raise XendError("Error recreating xend domain info: id=%d" %
    1.63 -                            dom0)
    1.64 -        self._add_domain(dominfo)
    1.65 -        return dominfo
    1.66 +            dominfo = XendDomainInfo.recreate(uuid, dompath, dom0, info)
    1.67 +            self._add_domain(dominfo)
    1.68 +            return dominfo
    1.69 +        except Exception, exn:
    1.70 +            log.exception(exn)
    1.71 +            raise XendError("Error recreating xend domain info: id=%d: %s" %
    1.72 +                            (dom0, str(exn)))
    1.73 +
    1.74          
    1.75      def domain_lookup(self, id):
    1.76          return self.domains.get(id)
    1.77 @@ -729,7 +723,7 @@ class XendDomain:
    1.78          @return: 0 on success, -1 on error
    1.79          """
    1.80          dominfo = self.domain_lookup(id)
    1.81 -        return dominfo.setMemoryTarget(mem * (1 << 20))
    1.82 +        return dominfo.setMemoryTarget(mem << 10)
    1.83  
    1.84      def domain_vcpu_hotplug(self, id, vcpu, state):
    1.85          """Enable or disable VCPU vcpu in DOM id
     2.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Wed Sep 21 15:13:26 2005 +0100
     2.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Sep 21 15:23:26 2005 +0100
     2.3 @@ -13,6 +13,7 @@
     2.4  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     2.5  #============================================================================
     2.6  # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
     2.7 +# Copyright (C) 2005 XenSource Ltd
     2.8  #============================================================================
     2.9  
    2.10  """Representation of a single domain.
    2.11 @@ -31,18 +32,15 @@ import errno
    2.12  import xen.lowlevel.xc
    2.13  from xen.util.blkif import blkdev_uname_to_file
    2.14  
    2.15 -from xen.xend.server import SrvDaemon
    2.16  from xen.xend.server.channel import EventChannel
    2.17  
    2.18  from xen.xend import sxp
    2.19 -from xen.xend.PrettyPrint import prettyprintstring
    2.20  from xen.xend.XendBootloader import bootloader
    2.21  from xen.xend.XendLogging import log
    2.22  from xen.xend.XendError import XendError, VmError
    2.23  from xen.xend.XendRoot import get_component
    2.24  
    2.25  from xen.xend.uuid import getUuid
    2.26 -from xen.xend.xenstore import DBVar
    2.27  from xen.xend.xenstore.xstransact import xstransact
    2.28  from xen.xend.xenstore.xsutil import IntroduceDomain
    2.29  
    2.30 @@ -96,9 +94,6 @@ SIF_TPM_BE_DOMAIN = (1<<7)
    2.31  xc = xen.lowlevel.xc.new()
    2.32  
    2.33  
    2.34 -xend = SrvDaemon.instance()
    2.35 -
    2.36 -
    2.37  def domain_exists(name):
    2.38      # See comment in XendDomain constructor.
    2.39      xd = get_component('xen.xend.XendDomain')
    2.40 @@ -136,142 +131,282 @@ class XendDomainInfo:
    2.41      """
    2.42      MINIMUM_RESTART_TIME = 20
    2.43  
    2.44 -    def create(cls, parentdb, config):
    2.45 +
    2.46 +    def create(cls, dompath, config):
    2.47          """Create a VM from a configuration.
    2.48  
    2.49 -        @param parentdb:  parent db
    2.50 +        @param dompath:   The path to all domain information
    2.51          @param config    configuration
    2.52          @raise: VmError for invalid configuration
    2.53          """
    2.54 -        uuid = getUuid()
    2.55 -        db = parentdb.addChild("%s/xend" % uuid)
    2.56 -        path = parentdb.getPath()
    2.57 -        vm = cls(uuid, path, db)
    2.58 -        vm.construct(config)
    2.59 -        vm.saveToDB(sync=True)
    2.60  
    2.61 +        log.debug("XendDomainInfo.create(%s, ...)", dompath)
    2.62 +        
    2.63 +        vm = cls(getUuid(), dompath, cls.parseConfig(config))
    2.64 +        vm.construct()
    2.65          return vm
    2.66  
    2.67      create = classmethod(create)
    2.68  
    2.69 -    def recreate(cls, uuid, path, domid, db, info):
    2.70 +
    2.71 +    def recreate(cls, uuid, dompath, domid, info):
    2.72          """Create the VM object for an existing domain.
    2.73  
    2.74 -        @param db:        domain db
    2.75 +        @param dompath:   The path to all domain information
    2.76          @param info:      domain info from xc
    2.77          """
    2.78 -        vm = cls(uuid, path, db)
    2.79 -        vm.setDomid(domid)
    2.80 -        vm.name, vm.start_time = vm.gatherVm(("name", str),
    2.81 -                                             ("start-time", float))
    2.82 -        try:
    2.83 -            db.readDB()
    2.84 -        except: pass
    2.85 -        vm.importFromDB()
    2.86 -        config = vm.config
    2.87 -        log.debug('info=' + str(info))
    2.88 -        log.debug('config=' + prettyprintstring(config))
    2.89  
    2.90 -        vm.memory = info['mem_kb'] / 1024
    2.91 -        vm.target = info['mem_kb'] * 1024
    2.92 +        log.debug("XendDomainInfo.recreate(%s, %s, %s, %s)", uuid, dompath,
    2.93 +                  domid, info)
    2.94  
    2.95 -        if config:
    2.96 -            try:
    2.97 -                vm.recreate = True
    2.98 -                vm.construct(config)
    2.99 -            finally:
   2.100 -                vm.recreate = False
   2.101 -        else:
   2.102 -            vm.setName("Domain-%d" % domid)
   2.103 -
   2.104 -        vm.exportToDB(save=True)
   2.105 -        return vm
   2.106 +        return cls(uuid, dompath, info, domid, True)
   2.107  
   2.108      recreate = classmethod(recreate)
   2.109  
   2.110 -    def restore(cls, parentdb, config, uuid=None):
   2.111 +
   2.112 +    def restore(cls, dompath, config, uuid = None):
   2.113          """Create a domain and a VM object to do a restore.
   2.114  
   2.115 -        @param parentdb:  parent db
   2.116 +        @param dompath:   The path to all domain information
   2.117          @param config:    domain configuration
   2.118          @param uuid:      uuid to use
   2.119          """
   2.120 +        
   2.121 +        log.debug("XendDomainInfo.restore(%s, ..., %s)", dompath, uuid)
   2.122 +
   2.123          if not uuid:
   2.124              uuid = getUuid()
   2.125 -        db = parentdb.addChild("%s/xend" % uuid)
   2.126 -        path = parentdb.getPath()
   2.127 -        vm = cls(uuid, path, db)
   2.128 -        ssidref = int(sxp.child_value(config, 'ssidref'))
   2.129 -        log.debug('restoring with ssidref='+str(ssidref))
   2.130 -        id = xc.domain_create(ssidref = ssidref)
   2.131 -        vm.setDomid(id)
   2.132 +
   2.133 +        try:
   2.134 +            ssidref = int(sxp.child_value(config, 'ssidref'))
   2.135 +        except TypeError, exn:
   2.136 +            raise VmError('Invalid ssidref in config: %s' % exn)
   2.137 +
   2.138 +        log.debug('restoring with ssidref = %d' % ssidref)
   2.139 +
   2.140 +        vm = cls(uuid, dompath, cls.parseConfig(config),
   2.141 +                 xc.domain_create(ssidref = ssidref))
   2.142          vm.clear_shutdown()
   2.143 -        try:
   2.144 -            vm.restore = True
   2.145 -            vm.construct(config)
   2.146 -        finally:
   2.147 -            vm.restore = False
   2.148 -        vm.exportToDB(save=True, sync=True)
   2.149          return vm
   2.150  
   2.151      restore = classmethod(restore)
   2.152  
   2.153 -    __exports__ = [
   2.154 -        DBVar('config',        ty='sxpr'),
   2.155 -        DBVar('state',         ty='str'),
   2.156 -        DBVar('restart_mode',  ty='str'),
   2.157 -        DBVar('restart_state', ty='str'),
   2.158 -        DBVar('restart_time',  ty='float'),
   2.159 -        DBVar('restart_count', ty='int'),
   2.160 -        ]
   2.161 -    
   2.162 -    def __init__(self, uuid, path, db):
   2.163 -        self.uuid = uuid
   2.164 -        self.path = path + "/" + uuid
   2.165  
   2.166 -        self.db = db
   2.167 +    def parseConfig(cls, config):
   2.168 +        def get_cfg(name, conv = None):
   2.169 +            val = sxp.child_value(config, name)
   2.170  
   2.171 -        self.recreate = 0
   2.172 -        self.restore = 0
   2.173 -        
   2.174 -        self.config = None
   2.175 -        self.domid = None
   2.176 -        self.cpu_weight = 1
   2.177 -        self.start_time = None
   2.178 -        self.name = None
   2.179 -        self.memory = None
   2.180 -        self.ssidref = None
   2.181 +            if conv and not val is None:
   2.182 +                try:
   2.183 +                    return conv(val)
   2.184 +                except TypeError, exn:
   2.185 +                    raise VmError(
   2.186 +                        'Invalid setting %s = %s in configuration: %s' %
   2.187 +                        (name, val, str(exn)))
   2.188 +            else:
   2.189 +                return val
   2.190 +
   2.191 +
   2.192 +        log.debug("parseConfig: config is %s" % str(config))
   2.193 +
   2.194 +        result = {}
   2.195 +        imagecfg = "()"
   2.196 +
   2.197 +        result['name']         = get_cfg('name')
   2.198 +        result['ssidref']      = get_cfg('ssidref',    int)
   2.199 +        result['memory']       = get_cfg('memory',     int)
   2.200 +        result['mem_kb']       = get_cfg('mem_kb',     int)
   2.201 +        result['maxmem']       = get_cfg('maxmem',     int)
   2.202 +        result['maxmem_kb']    = get_cfg('maxmem_kb',  int)
   2.203 +        result['cpu']          = get_cfg('cpu',        int)
   2.204 +        result['cpu_weight']   = get_cfg('cpu_weight', float)
   2.205 +        result['bootloader']   = get_cfg('bootloader')
   2.206 +        result['restart_mode'] = get_cfg('restart')
   2.207 +
   2.208 +        try:
   2.209 +            imagecfg = get_cfg('image')
   2.210 +
   2.211 +            if imagecfg:
   2.212 +                result['image'] = imagecfg
   2.213 +                result['vcpus'] = int(sxp.child_value(imagecfg, 'vcpus',
   2.214 +                                                      1))
   2.215 +            else:
   2.216 +                result['vcpus'] = 1
   2.217 +        except TypeError, exn:
   2.218 +            raise VmError(
   2.219 +                'Invalid configuration setting: vcpus = %s: %s' %
   2.220 +                (sxp.child_value(imagecfg, 'vcpus', 1),
   2.221 +                 str(exn)))
   2.222 +
   2.223 +        result['backend'] = []
   2.224 +        for c in sxp.children(config, 'backend'):
   2.225 +            result['backend'].append(sxp.name(sxp.child0(c)))
   2.226 +
   2.227 +        result['device'] = []
   2.228 +        for d in sxp.children(config, 'device'):
   2.229 +            c = sxp.child0(d)
   2.230 +            result['device'].append((sxp.name(c), c))
   2.231 +
   2.232 +        log.debug("parseConfig: result is %s" % str(result))
   2.233 +        return result
   2.234 +
   2.235 +
   2.236 +    parseConfig = classmethod(parseConfig)
   2.237 +
   2.238 +    
   2.239 +    def __init__(self, uuid, parentpath, info, domid = None, augment = False):
   2.240 +
   2.241 +        self.uuid = uuid
   2.242 +        self.info = info
   2.243 +
   2.244 +        self.path = parentpath + "/" + uuid
   2.245 +
   2.246 +        if domid:
   2.247 +            self.domid = domid
   2.248 +        elif 'dom' in info:
   2.249 +            self.domid = int(info['dom'])
   2.250 +        else:
   2.251 +            self.domid = None
   2.252 +
   2.253 +        if augment:
   2.254 +            self.augmentInfo()
   2.255 +
   2.256 +        self.validateInfo()
   2.257 +
   2.258          self.image = None
   2.259  
   2.260 -        self.target = None
   2.261 -
   2.262          self.store_channel = None
   2.263          self.store_mfn = None
   2.264          self.console_channel = None
   2.265          self.console_mfn = None
   2.266          
   2.267 -        self.info = None
   2.268 -        self.backend_flags = 0
   2.269 -        
   2.270          #todo: state: running, suspended
   2.271          self.state = STATE_VM_OK
   2.272          self.state_updated = threading.Condition()
   2.273          self.shutdown_pending = None
   2.274  
   2.275 -        #todo: set to migrate info if migrating
   2.276 -        self.migrate = None
   2.277 -        
   2.278 -        self.restart_mode = RESTART_ONREBOOT
   2.279          self.restart_state = None
   2.280          self.restart_time = None
   2.281          self.restart_count = 0
   2.282          
   2.283 -        self.vcpus = 1
   2.284 -        self.bootloader = None
   2.285 -
   2.286          self.writeVm("uuid", self.uuid)
   2.287          self.storeDom("vm", self.path)
   2.288  
   2.289 +
   2.290 +    def augmentInfo(self):
   2.291 +        def useIfNeeded(name, val):
   2.292 +            if not self.infoIsSet(name) and val is not None:
   2.293 +                self.info[name] = val
   2.294 +
   2.295 +        params = (("name", str),
   2.296 +                  ("start-time", float))
   2.297 +
   2.298 +        from_store = self.gatherVm(*params)
   2.299 +
   2.300 +        map(lambda x, y: useIfNeeded(x[0], y), params, from_store)
   2.301 +
   2.302 +
   2.303 +    def validateInfo(self):
   2.304 +        """Validate and normalise the info block.  This has either been parsed
   2.305 +        by parseConfig, or received from xc through recreate.
   2.306 +        """
   2.307 +        def defaultInfo(name, val):
   2.308 +            if not self.infoIsSet(name):
   2.309 +                self.info[name] = val()
   2.310 +
   2.311 +        try:
   2.312 +            defaultInfo('name',         lambda: "Domain-%d" % self.domid)
   2.313 +            defaultInfo('restart_mode', lambda: RESTART_ONREBOOT)
   2.314 +            defaultInfo('cpu_weight',   lambda: 1.0)
   2.315 +            defaultInfo('bootloader',   lambda: None)
   2.316 +            defaultInfo('backend',      lambda: [])
   2.317 +            defaultInfo('device',       lambda: [])
   2.318 +
   2.319 +            self.check_name(self.info['name'])
   2.320 +
   2.321 +            # Internally, we keep only maxmem_KiB, and not maxmem or maxmem_kb
   2.322 +            # (which come from outside, and are in MiB and KiB respectively).
   2.323 +            # This means that any maxmem or maxmem_kb settings here have come
   2.324 +            # from outside, and maxmem_KiB must be updated to reflect them.
   2.325 +            # If we have both maxmem and maxmem_kb and these are not
   2.326 +            # consistent, then this is an error, as we've no way to tell which
   2.327 +            # one takes precedence.
   2.328 +
   2.329 +            # Exactly the same thing applies to memory_KiB, memory, and
   2.330 +            # mem_kb.
   2.331 +
   2.332 +            def discard_negatives(name):
   2.333 +                if self.infoIsSet(name) and self.info[name] <= 0:
   2.334 +                    del self.info[name]
   2.335 +
   2.336 +            def valid_KiB_(mb_name, kb_name):
   2.337 +                discard_negatives(kb_name)
   2.338 +                discard_negatives(mb_name)
   2.339 +                
   2.340 +                if self.infoIsSet(kb_name):
   2.341 +                    if self.infoIsSet(mb_name):
   2.342 +                        mb = self.info[mb_name]
   2.343 +                        kb = self.info[kb_name]
   2.344 +                        if mb * 1024 == kb:
   2.345 +                            return kb
   2.346 +                        else:
   2.347 +                            raise VmError(
   2.348 +                                'Inconsistent %s / %s settings: %s / %s' %
   2.349 +                                (mb_name, kb_name, mb, kb))
   2.350 +                    else:
   2.351 +                        return self.info[kb_name]
   2.352 +                elif self.infoIsSet(mb_name):
   2.353 +                    return self.info[mb_name] * 1024
   2.354 +                else:
   2.355 +                    return None
   2.356 +
   2.357 +            def valid_KiB(mb_name, kb_name):
   2.358 +                result = valid_KiB_(mb_name, kb_name)
   2.359 +                if result <= 0:
   2.360 +                    raise VmError('Invalid %s / %s: %s' %
   2.361 +                                  (mb_name, kb_name, result))
   2.362 +                else:
   2.363 +                    return result
   2.364 +
   2.365 +            def delIf(name):
   2.366 +                if name in self.info:
   2.367 +                    del self.info[name]
   2.368 +
   2.369 +            self.info['memory_KiB'] = valid_KiB('memory', 'mem_kb')
   2.370 +            delIf('memory')
   2.371 +            delIf('mem_kb')
   2.372 +            self.info['maxmem_KiB'] = valid_KiB_('maxmem', 'maxmem_kb')
   2.373 +            delIf('maxmem')
   2.374 +            delIf('maxmem_kb')
   2.375 +
   2.376 +            if not self.info['maxmem_KiB']:
   2.377 +                self.info['maxmem_KiB'] = 1 << 30
   2.378 +
   2.379 +            # Validate the given backend names.
   2.380 +            for s in self.info['backend']:
   2.381 +                if s not in backendFlags:
   2.382 +                    raise VmError('Invalid backend type: %s' % s)
   2.383 +
   2.384 +            for (n, c) in self.info['device']:
   2.385 +                if not n or not c or n not in controllerClasses:
   2.386 +                    raise VmError('invalid device (%s, %s)' %
   2.387 +                                  (str(n), str(c)))
   2.388 +
   2.389 +            if self.info['restart_mode'] not in restart_modes:
   2.390 +                raise VmError('invalid restart mode: ' +
   2.391 +                              str(self.info['restart_mode']))
   2.392 +
   2.393 +            if 'cpumap' not in self.info:
   2.394 +                if [self.info['vcpus'] == 1]:
   2.395 +                    self.info['cpumap'] = [1];
   2.396 +                else:
   2.397 +                    raise VmError('Cannot create CPU map')
   2.398 +
   2.399 +        except KeyError, exn:
   2.400 +            log.exception(exn)
   2.401 +            raise VmError('Unspecified domain detail: %s' % str(exn))
   2.402 +
   2.403 +
   2.404      def readVm(self, *args):
   2.405          return xstransact.Read(self.path, *args)
   2.406  
   2.407 @@ -302,18 +437,28 @@ class XendDomainInfo:
   2.408      def storeDom(self, *args):
   2.409          return xstransact.Store(self.path, *args)
   2.410  
   2.411 -    def setDB(self, db):
   2.412 -        self.db = db
   2.413 -
   2.414 -    def saveToDB(self, save=False, sync=False):
   2.415 -        self.db.saveDB(save=save, sync=sync)
   2.416  
   2.417 -    def exportToDB(self, save=False, sync=False):
   2.418 -        self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
   2.419 +    def exportToDB(self, save=False):
   2.420 +        to_store = {
   2.421 +            'domid':              str(self.domid),
   2.422 +            'uuid':               self.uuid,
   2.423  
   2.424 -    def importFromDB(self):
   2.425 -        self.db.importFromDB(self, fields=self.__exports__)
   2.426 -        self.store_channel = self.eventChannel("store/port")
   2.427 +            'restart_time':       str(self.restart_time),
   2.428 +
   2.429 +            'xend/state':         self.state,
   2.430 +            'xend/restart_count': str(self.restart_count),
   2.431 +            'xend/restart_mode':  str(self.info['restart_mode']),
   2.432 +
   2.433 +            'memory/target':      str(self.info['memory_KiB'])
   2.434 +            }
   2.435 +
   2.436 +        for (k, v) in self.info.items():
   2.437 +            to_store[k] = str(v)
   2.438 +
   2.439 +        log.debug("Storing %s" % str(to_store))
   2.440 +
   2.441 +        self.writeVm(to_store)
   2.442 +
   2.443  
   2.444      def setDomid(self, domid):
   2.445          """Set the domain id.
   2.446 @@ -327,11 +472,12 @@ class XendDomainInfo:
   2.447          return self.domid
   2.448  
   2.449      def setName(self, name):
   2.450 -        self.name = name
   2.451 +        self.check_name(name)
   2.452 +        self.info['name'] = name
   2.453          self.storeVm("name", name)
   2.454  
   2.455      def getName(self):
   2.456 -        return self.name
   2.457 +        return self.info['name']
   2.458  
   2.459      def getPath(self):
   2.460          return self.path
   2.461 @@ -340,14 +486,14 @@ class XendDomainInfo:
   2.462          return self.uuid
   2.463  
   2.464      def getVCpuCount(self):
   2.465 -        return self.vcpus
   2.466 +        return self.info['vcpus']
   2.467  
   2.468      def getSsidref(self):
   2.469 -        return self.ssidref
   2.470 +        return self.info['ssidref']
   2.471  
   2.472      def getMemoryTarget(self):
   2.473 -        """Get this domain's target memory size, in MiB."""
   2.474 -        return self.memory
   2.475 +        """Get this domain's target memory size, in KiB."""
   2.476 +        return self.info['memory_KiB']
   2.477  
   2.478      def setStoreRef(self, ref):
   2.479          self.store_mfn = ref
   2.480 @@ -355,7 +501,8 @@ class XendDomainInfo:
   2.481  
   2.482  
   2.483      def getBackendFlags(self):
   2.484 -        return self.backend_flags
   2.485 +        return reduce(lambda x, y: x | backendFlags[y],
   2.486 +                      self.info['backend'], 0)
   2.487  
   2.488  
   2.489      def closeStoreChannel(self):
   2.490 @@ -376,21 +523,32 @@ class XendDomainInfo:
   2.491          self.console_mfn = ref
   2.492          self.storeDom("console/ring-ref", ref)
   2.493  
   2.494 +
   2.495      def setMemoryTarget(self, target):
   2.496 +        """Set the memory target of this domain.
   2.497 +        @param target In KiB.
   2.498 +        """
   2.499 +        self.info['memory_KiB'] = target
   2.500          self.storeDom("memory/target", target)
   2.501  
   2.502 -    def update(self, info=None):
   2.503 -        """Update with  info from xc.domain_getinfo().
   2.504 +
   2.505 +    def update(self, info = None):
   2.506 +        """Update with info from xc.domain_getinfo().
   2.507          """
   2.508 -        if info:
   2.509 -            self.info = info
   2.510 -        else:
   2.511 -            di = dom_get(self.domid)
   2.512 -            if not di:
   2.513 +
   2.514 +        log.debug("XendDomainInfo.update(%s) on domain %d", info, self.domid)
   2.515 +
   2.516 +        if not info:
   2.517 +            info = dom_get(self.domid)
   2.518 +            if not info:
   2.519                  return
   2.520 -            self.info = di 
   2.521 -        self.memory = self.info['mem_kb'] / 1024
   2.522 -        self.ssidref = self.info['ssidref']
   2.523 +            
   2.524 +        self.info.update(info)
   2.525 +        self.validateInfo()
   2.526 +
   2.527 +        log.debug("XendDomainInfo.update done on domain %d: %s", self.domid,
   2.528 +                  self.info)
   2.529 +
   2.530  
   2.531      def state_set(self, state):
   2.532          self.state_updated.acquire()
   2.533 @@ -398,7 +556,7 @@ class XendDomainInfo:
   2.534              self.state = state
   2.535              self.state_updated.notifyAll()
   2.536          self.state_updated.release()
   2.537 -        self.saveToDB()
   2.538 +        self.exportToDB()
   2.539  
   2.540      def state_wait(self, state):
   2.541          self.state_updated.acquire()
   2.542 @@ -409,9 +567,9 @@ class XendDomainInfo:
   2.543      def __str__(self):
   2.544          s = "<domain"
   2.545          s += " id=" + str(self.domid)
   2.546 -        s += " name=" + self.name
   2.547 -        s += " memory=" + str(self.memory)
   2.548 -        s += " ssidref=" + str(self.ssidref)
   2.549 +        s += " name=" + self.info['name']
   2.550 +        s += " memory=" + str(self.info['memory_KiB'] / 1024)
   2.551 +        s += " ssidref=" + str(self.info['ssidref'])
   2.552          s += ">"
   2.553          return s
   2.554  
   2.555 @@ -441,37 +599,47 @@ class XendDomainInfo:
   2.556      def sxpr(self):
   2.557          sxpr = ['domain',
   2.558                  ['domid', self.domid],
   2.559 -                ['name', self.name],
   2.560 -                ['memory', self.memory],
   2.561 -                ['ssidref', self.ssidref],
   2.562 -                ['target', self.target] ]
   2.563 +                ['name', self.info['name']],
   2.564 +                ['memory', self.info['memory_KiB'] / 1024],
   2.565 +                ['ssidref', self.info['ssidref']]]
   2.566          if self.uuid:
   2.567              sxpr.append(['uuid', self.uuid])
   2.568          if self.info:
   2.569 -            sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ])
   2.570 -            run   = (self.info['running']  and 'r') or '-'
   2.571 -            block = (self.info['blocked']  and 'b') or '-'
   2.572 -            pause = (self.info['paused']   and 'p') or '-'
   2.573 -            shut  = (self.info['shutdown'] and 's') or '-'
   2.574 -            crash = (self.info['crashed']  and 'c') or '-'
   2.575 -            state = run + block + pause + shut + crash
   2.576 +            sxpr.append(['maxmem', self.info['maxmem_KiB'] / 1024])
   2.577 +
   2.578 +            def stateChar(name):
   2.579 +                if name in self.info:
   2.580 +                    if self.info[name]:
   2.581 +                        return name[0]
   2.582 +                    else:
   2.583 +                        return '-'
   2.584 +                else:
   2.585 +                    return '?'
   2.586 +
   2.587 +            state = reduce(
   2.588 +                lambda x, y: x + y,
   2.589 +                map(stateChar,
   2.590 +                    ['running', 'blocked', 'paused', 'shutdown', 'crashed']))
   2.591 +
   2.592              sxpr.append(['state', state])
   2.593 -            if self.info['shutdown']:
   2.594 +            if self.infoIsSet('shutdown'):
   2.595                  reason = shutdown_reason(self.info['shutdown_reason'])
   2.596                  sxpr.append(['shutdown_reason', reason])
   2.597 -            sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
   2.598 -            sxpr.append(['cpu_time', self.info['cpu_time']/1e9])    
   2.599 +            if self.infoIsSet('cpu_time'):
   2.600 +                sxpr.append(['cpu_time', self.info['cpu_time']/1e9])    
   2.601              sxpr.append(['vcpus', self.info['vcpus']])
   2.602              sxpr.append(['cpumap', self.info['cpumap']])
   2.603 -            # build a string, using '|' to seperate items, show only up
   2.604 -            # to number of vcpus in domain, and trim the trailing '|'
   2.605 -            sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x)+'|',
   2.606 -                        self.info['vcpu_to_cpu'][0:self.info['vcpus']]))[:-1]])
   2.607 +            if self.infoIsSet('vcpu_to_cpu'):
   2.608 +                sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
   2.609 +                # build a string, using '|' to separate items, show only up
   2.610 +                # to number of vcpus in domain, and trim the trailing '|'
   2.611 +                sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x)+'|',
   2.612 +                            self.info['vcpu_to_cpu'][0:self.info['vcpus']]))[:-1]])
   2.613              
   2.614 -        if self.start_time:
   2.615 -            up_time =  time.time() - self.start_time  
   2.616 +        if self.infoIsSet('start_time'):
   2.617 +            up_time =  time.time() - self.info['start_time']
   2.618              sxpr.append(['up_time', str(up_time) ])
   2.619 -            sxpr.append(['start_time', str(self.start_time) ])
   2.620 +            sxpr.append(['start_time', str(self.info['start_time']) ])
   2.621  
   2.622          if self.store_channel:
   2.623              sxpr.append(self.store_channel.sxpr())
   2.624 @@ -481,19 +649,12 @@ class XendDomainInfo:
   2.625              sxpr.append(['console_channel', self.console_channel.sxpr()])
   2.626          if self.console_mfn:
   2.627              sxpr.append(['console_mfn', self.console_mfn])
   2.628 -# already in (devices)
   2.629 -#        console = self.getConsole()
   2.630 -#        if console:
   2.631 -#            sxpr.append(console.sxpr())
   2.632 -
   2.633          if self.restart_count:
   2.634              sxpr.append(['restart_count', self.restart_count])
   2.635          if self.restart_state:
   2.636              sxpr.append(['restart_state', self.restart_state])
   2.637          if self.restart_time:
   2.638              sxpr.append(['restart_time', str(self.restart_time)])
   2.639 -        if self.config:
   2.640 -            sxpr.append(['config', self.config])
   2.641          return sxpr
   2.642  
   2.643      def check_name(self, name):
   2.644 @@ -502,9 +663,8 @@ class XendDomainInfo:
   2.645          The same name cannot be used for more than one vm at the same time.
   2.646  
   2.647          @param name: name
   2.648 -        @raise: VMerror if invalid
   2.649 +        @raise: VmError if invalid
   2.650          """
   2.651 -        if self.recreate: return
   2.652          if name is None or name == '':
   2.653              raise VmError('missing vm name')
   2.654          for c in name:
   2.655 @@ -520,28 +680,50 @@ class XendDomainInfo:
   2.656              return
   2.657          if dominfo.is_terminated():
   2.658              return
   2.659 -        if not self.domid or (dominfo.domid != self.domid):
   2.660 -            raise VmError('vm name clash: ' + name)
   2.661 -        
   2.662 -    def construct(self, config):
   2.663 +        if self.domid is None:
   2.664 +            raise VmError("VM name '%s' already in use by domain %d" %
   2.665 +                          (name, dominfo.domid))
   2.666 +        if dominfo.domid != self.domid:
   2.667 +            raise VmError("VM name '%s' is used in both domains %d and %d" %
   2.668 +                          (name, self.domid, dominfo.domid))
   2.669 +
   2.670 +
   2.671 +    def construct(self):
   2.672          """Construct the vm instance from its configuration.
   2.673  
   2.674          @param config: configuration
   2.675          @raise: VmError on error
   2.676          """
   2.677          # todo - add support for scheduling params?
   2.678 -        self.config = config
   2.679          try:
   2.680              # Initial domain create.
   2.681 -            self.setName(sxp.child_value(config, 'name'))
   2.682 -            self.check_name(self.name)
   2.683 -            self.init_image()
   2.684 -            self.configure_cpus(config)
   2.685 -            self.init_domain()
   2.686 +            if 'image' not in self.info:
   2.687 +                raise VmError('Missing image in configuration')
   2.688 +
   2.689 +            self.image = ImageHandler.create(self, self.info['image'],
   2.690 +                                             self.info['device'])
   2.691 +
   2.692 +            log.debug('XendDomainInfo.construct: '
   2.693 +                      'calling initDomain(%s %s %s %s %s)',
   2.694 +                      str(self.domid),
   2.695 +                      str(self.info['memory_KiB']),
   2.696 +                      str(self.info['ssidref']),
   2.697 +                      str(self.info['cpu']),
   2.698 +                      str(self.info['cpu_weight']))
   2.699 +
   2.700 +            self.setDomid(self.image.initDomain(self.domid,
   2.701 +                                                self.info['memory_KiB'],
   2.702 +                                                self.info['ssidref'],
   2.703 +                                                self.info['cpu'],
   2.704 +                                                self.info['cpu_weight'],
   2.705 +                                                self.info['bootloader']))
   2.706 +            
   2.707 +            self.info['start_time'] = time.time()
   2.708 +
   2.709 +            log.debug('init_domain> Created domain=%d name=%s memory=%d',
   2.710 +                      self.domid, self.info['name'], self.info['memory_KiB'])
   2.711  
   2.712              # Create domain devices.
   2.713 -            self.configure_backends()
   2.714 -            self.configure_restart()
   2.715              self.construct_image()
   2.716              self.configure()
   2.717              self.exportToDB(save=True)
   2.718 @@ -553,41 +735,12 @@ class XendDomainInfo:
   2.719              self.destroy()
   2.720              raise
   2.721  
   2.722 -    def configure_cpus(self, config):
   2.723 -        try:
   2.724 -            self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
   2.725 -        except:
   2.726 -            raise VmError('invalid cpu weight')
   2.727 -        self.memory = int(sxp.child_value(config, 'memory'))
   2.728 -        if self.memory is None:
   2.729 -            raise VmError('missing memory size')
   2.730 -        self.setMemoryTarget(self.memory * (1 << 20))
   2.731 -        self.ssidref = int(sxp.child_value(config, 'ssidref'))
   2.732 -        cpu = sxp.child_value(config, 'cpu')
   2.733 -        if self.recreate and self.domid and cpu is not None and int(cpu) >= 0:
   2.734 -            xc.domain_pincpu(self.domid, 0, 1<<int(cpu))
   2.735 -        try:
   2.736 -            image = sxp.child_value(self.config, 'image')
   2.737 -            vcpus = sxp.child_value(image, 'vcpus')
   2.738 -            if vcpus:
   2.739 -                self.vcpus = int(vcpus)
   2.740 -        except:
   2.741 -            raise VmError('invalid vcpus value')
   2.742 -
   2.743      def configure_vcpus(self, vcpus):
   2.744          d = {}
   2.745          for v in range(0, vcpus):
   2.746              d["cpu/%d/availability" % v] = "online"
   2.747          self.writeVm(d)
   2.748  
   2.749 -    def init_image(self):
   2.750 -        """Create boot image handler for the domain.
   2.751 -        """
   2.752 -        image = sxp.child_value(self.config, 'image')
   2.753 -        if image is None:
   2.754 -            raise VmError('missing image')
   2.755 -        self.image = ImageHandler.create(self, image)
   2.756 -
   2.757      def construct_image(self):
   2.758          """Construct the boot image for the domain.
   2.759          """
   2.760 @@ -598,21 +751,17 @@ class XendDomainInfo:
   2.761              IntroduceDomain(self.domid, self.store_mfn,
   2.762                              self.store_channel.port1, self.path)
   2.763          # get the configured value of vcpus and update store
   2.764 -        self.configure_vcpus(self.vcpus)
   2.765 +        self.configure_vcpus(self.info['vcpus'])
   2.766 +
   2.767  
   2.768      def delete(self):
   2.769          """Delete the vm's db.
   2.770          """
   2.771 -        self.domid = None
   2.772 -        self.saveToDB(sync=True)
   2.773          try:
   2.774 -            # Todo: eventually will have to wait for devices to signal
   2.775 -            # destruction before can delete the db.
   2.776 -            if self.db:
   2.777 -                self.db.delete()
   2.778 +            xstransact.Remove(self.path, 'domid')
   2.779          except Exception, ex:
   2.780              log.warning("error in domain db delete: %s", ex)
   2.781 -            pass
   2.782 +
   2.783  
   2.784      def destroy_domain(self):
   2.785          """Destroy the vm's domain.
   2.786 @@ -624,7 +773,7 @@ class XendDomainInfo:
   2.787          try:
   2.788              xc.domain_destroy(dom=self.domid)
   2.789          except Exception, err:
   2.790 -            log.exception("Domain destroy failed: %s", self.name)
   2.791 +            log.exception("Domain destroy failed: %s", self.info['name'])
   2.792  
   2.793      def cleanup(self):
   2.794          """Cleanup vm resources: release devices.
   2.795 @@ -647,11 +796,14 @@ class XendDomainInfo:
   2.796                  pass
   2.797  
   2.798      def destroy(self):
   2.799 -        """Clenup vm and destroy domain.
   2.800 +        """Cleanup vm and destroy domain.
   2.801          """
   2.802 +
   2.803 +        log.debug("XendDomainInfo.destroy")
   2.804 +
   2.805          self.destroy_domain()
   2.806          self.cleanup()
   2.807 -        self.saveToDB()
   2.808 +        self.exportToDB()
   2.809          return 0
   2.810  
   2.811      def is_terminated(self):
   2.812 @@ -664,6 +816,7 @@ class XendDomainInfo:
   2.813          """
   2.814  
   2.815          t = xstransact("%s/device" % self.path)
   2.816 +
   2.817          for n in controllerClasses.keys():
   2.818              for d in t.list(n):
   2.819                  try:
   2.820 @@ -677,31 +830,6 @@ class XendDomainInfo:
   2.821          t.commit()
   2.822  
   2.823  
   2.824 -    def show(self):
   2.825 -        """Print virtual machine info.
   2.826 -        """
   2.827 -        print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.domid, self.name, self.memory, self.ssidref)
   2.828 -        print "image:"
   2.829 -        sxp.show(self.image)
   2.830 -        print "]"
   2.831 -
   2.832 -    def init_domain(self):
   2.833 -        """Initialize the domain memory.
   2.834 -        """
   2.835 -        if self.recreate:
   2.836 -            return
   2.837 -        if self.start_time is None:
   2.838 -            self.start_time = time.time()
   2.839 -            self.storeVm(("start-time", self.start_time))
   2.840 -        try:
   2.841 -            cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
   2.842 -        except:
   2.843 -            raise VmError('invalid cpu')
   2.844 -        id = self.image.initDomain(self.domid, self.memory, self.ssidref, cpu, self.cpu_weight)
   2.845 -        log.debug('init_domain> Created domain=%d name=%s memory=%d',
   2.846 -                  id, self.name, self.memory)
   2.847 -        self.setDomid(id)
   2.848 -
   2.849      def eventChannel(self, path=None):
   2.850          """Create an event channel to the domain.
   2.851          
   2.852 @@ -725,14 +853,8 @@ class XendDomainInfo:
   2.853          self.console_channel = self.eventChannel("console/port")
   2.854  
   2.855      def create_configured_devices(self):
   2.856 -        devices = sxp.children(self.config, 'device')
   2.857 -        for d in devices:
   2.858 -            dev_config = sxp.child0(d)
   2.859 -            if dev_config is None:
   2.860 -                raise VmError('invalid device')
   2.861 -            dev_type = sxp.name(dev_config)
   2.862 -
   2.863 -            self.createDevice(dev_type, dev_config)
   2.864 +        for (n, c) in self.info['device']:
   2.865 +            self.createDevice(n, c)
   2.866  
   2.867  
   2.868      def create_devices(self):
   2.869 @@ -740,8 +862,6 @@ class XendDomainInfo:
   2.870  
   2.871          @raise: VmError for invalid devices
   2.872          """
   2.873 -        if self.recreate:
   2.874 -            return
   2.875          if not self.rebooting():
   2.876              self.create_configured_devices()
   2.877          self.image.createDeviceModel()
   2.878 @@ -766,14 +886,6 @@ class XendDomainInfo:
   2.879          self.configureDevice(deviceClass, devid, dev_config)
   2.880  
   2.881  
   2.882 -    def configure_restart(self):
   2.883 -        """Configure the vm restart mode.
   2.884 -        """
   2.885 -        r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
   2.886 -        if r not in restart_modes:
   2.887 -            raise VmError('invalid restart mode: ' + str(r))
   2.888 -        self.restart_mode = r;
   2.889 -
   2.890      def restart_needed(self, reason):
   2.891          """Determine if the vm needs to be restarted when shutdown
   2.892          for the given reason.
   2.893 @@ -781,11 +893,11 @@ class XendDomainInfo:
   2.894          @param reason: shutdown reason
   2.895          @return True if needs restart, False otherwise
   2.896          """
   2.897 -        if self.restart_mode == RESTART_NEVER:
   2.898 +        if self.info['restart_mode'] == RESTART_NEVER:
   2.899              return False
   2.900 -        if self.restart_mode == RESTART_ALWAYS:
   2.901 +        if self.info['restart_mode'] == RESTART_ALWAYS:
   2.902              return True
   2.903 -        if self.restart_mode == RESTART_ONREBOOT:
   2.904 +        if self.info['restart_mode'] == RESTART_ONREBOOT:
   2.905              return reason == 'reboot'
   2.906          return False
   2.907  
   2.908 @@ -817,7 +929,7 @@ class XendDomainInfo:
   2.909              tdelta = tnow - self.restart_time
   2.910              if tdelta < self.MINIMUM_RESTART_TIME:
   2.911                  self.restart_cancel()
   2.912 -                msg = 'VM %s restarting too fast' % self.name
   2.913 +                msg = 'VM %s restarting too fast' % self.info['name']
   2.914                  log.error(msg)
   2.915                  raise VmError(msg)
   2.916          self.restart_time = tnow
   2.917 @@ -836,14 +948,13 @@ class XendDomainInfo:
   2.918              self.exportToDB()
   2.919              self.restart_state = STATE_RESTART_BOOTING
   2.920              self.configure_bootloader()
   2.921 -            self.construct(self.config)
   2.922 -            self.saveToDB()
   2.923 +            self.construct()
   2.924 +            self.exportToDB()
   2.925          finally:
   2.926              self.restart_state = None
   2.927  
   2.928      def configure_bootloader(self):
   2.929 -        self.bootloader = sxp.child_value(self.config, "bootloader")
   2.930 -        if not self.bootloader:
   2.931 +        if not self.info['bootloader']:
   2.932              return
   2.933          # if we're restarting with a bootloader, we need to run it
   2.934          # FIXME: this assumes the disk is the first device and
   2.935 @@ -854,30 +965,13 @@ class XendDomainInfo:
   2.936          if dev:
   2.937              disk = sxp.child_value(dev, "uname")
   2.938              fn = blkdev_uname_to_file(disk)
   2.939 -            blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
   2.940 +            blcfg = bootloader(self.info['bootloader'], fn, 1, self.info['vcpus'])
   2.941          if blcfg is None:
   2.942              msg = "Had a bootloader specified, but can't find disk"
   2.943              log.error(msg)
   2.944              raise VmError(msg)
   2.945          self.config = sxp.merge(['vm', ['image', blcfg]], self.config)
   2.946  
   2.947 -    def configure_backends(self):
   2.948 -        """Set configuration flags if the vm is a backend for netif or blkif.
   2.949 -        Configure the backends to use for vbd and vif if specified.
   2.950 -        """
   2.951 -        for c in sxp.children(self.config, 'backend'):
   2.952 -            v = sxp.child0(c)
   2.953 -            name = sxp.name(v)
   2.954 -            if name == 'blkif':
   2.955 -                self.backend_flags |= SIF_BLK_BE_DOMAIN
   2.956 -            elif name == 'netif':
   2.957 -                self.backend_flags |= SIF_NET_BE_DOMAIN
   2.958 -            elif name == 'usbif':
   2.959 -                pass
   2.960 -            elif name == 'tpmif':
   2.961 -                self.backend_flags |= SIF_TPM_BE_DOMAIN
   2.962 -            else:
   2.963 -                raise VmError('invalid backend type:' + str(name))
   2.964  
   2.965      def configure(self):
   2.966          """Configure a vm.
   2.967 @@ -895,19 +989,15 @@ class XendDomainInfo:
   2.968          """
   2.969          return
   2.970  
   2.971 +
   2.972      def configure_maxmem(self):
   2.973 -        try:
   2.974 -            maxmem = int(sxp.child_value(self.config, 'maxmem', self.memory))
   2.975 -            xc.domain_setmaxmem(self.domid, maxmem_kb = maxmem * 1024)
   2.976 -        except:
   2.977 -            raise VmError("invalid maxmem: " +
   2.978 -                          sxp.child_value(self.config, 'maxmem'))
   2.979 +        xc.domain_setmaxmem(self.domid, maxmem_kb = self.info['maxmem_KiB'])
   2.980  
   2.981  
   2.982      def vcpu_hotplug(self, vcpu, state):
   2.983          """Disable or enable VCPU in domain.
   2.984          """
   2.985 -        if vcpu > self.vcpus:
   2.986 +        if vcpu > self.info['vcpus']:
   2.987              log.error("Invalid VCPU %d" % vcpu)
   2.988              return
   2.989          if int(state) == 0:
   2.990 @@ -974,6 +1064,9 @@ class XendDomainInfo:
   2.991                  self.vcpu_hotplug(vcpu, 0)
   2.992  
   2.993  
   2.994 +    def infoIsSet(self, name):
   2.995 +        return name in self.info and self.info[name] is not None
   2.996 +
   2.997  
   2.998  #============================================================================
   2.999  # Register image handlers.
  2.1000 @@ -996,16 +1089,24 @@ implements the device control specific t
  2.1001  controllerClasses = {}
  2.1002  
  2.1003  
  2.1004 -def addControllerClass(device_class, cls):
  2.1005 +"""A map of backend names and the corresponding flag."""
  2.1006 +backendFlags = {}
  2.1007 +
  2.1008 +
  2.1009 +def addControllerClass(device_class, backend_name, backend_flag, cls):
  2.1010      """Register a subclass of DevController to handle the named device-class.
  2.1011 +
  2.1012 +    @param backend_flag One of the SIF_XYZ_BE_DOMAIN constants, or None if
  2.1013 +    no flag is to be set.
  2.1014      """
  2.1015      cls.deviceClass = device_class
  2.1016 +    backendFlags[backend_name] = backend_flag
  2.1017      controllerClasses[device_class] = cls
  2.1018  
  2.1019  
  2.1020  from xen.xend.server import blkif, netif, tpmif, pciif, usbif
  2.1021 -addControllerClass('vbd',  blkif.BlkifController)
  2.1022 -addControllerClass('vif',  netif.NetifController)
  2.1023 -addControllerClass('vtpm', tpmif.TPMifController)
  2.1024 -addControllerClass('pci',  pciif.PciController)
  2.1025 -addControllerClass('usb',  usbif.UsbifController)
  2.1026 +addControllerClass('vbd',  'blkif', SIF_BLK_BE_DOMAIN, blkif.BlkifController)
  2.1027 +addControllerClass('vif',  'netif', SIF_NET_BE_DOMAIN, netif.NetifController)
  2.1028 +addControllerClass('vtpm', 'tpmif', SIF_TPM_BE_DOMAIN, tpmif.TPMifController)
  2.1029 +addControllerClass('pci',  'pciif', None,              pciif.PciController)
  2.1030 +addControllerClass('usb',  'usbif', None,              usbif.UsbifController)
     3.1 --- a/tools/python/xen/xend/image.py	Wed Sep 21 15:13:26 2005 +0100
     3.2 +++ b/tools/python/xen/xend/image.py	Wed Sep 21 15:23:26 2005 +0100
     3.3 @@ -13,8 +13,10 @@
     3.4  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     3.5  #============================================================================
     3.6  # Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
     3.7 +# Copyright (C) 2005 XenSource Ltd
     3.8  #============================================================================
     3.9  
    3.10 +
    3.11  import os, string
    3.12  import re
    3.13  
    3.14 @@ -22,8 +24,6 @@ import xen.lowlevel.xc
    3.15  from xen.xend import sxp
    3.16  from xen.xend.XendError import VmError
    3.17  from xen.xend.XendLogging import log
    3.18 -from xen.xend.xenstore import DBVar
    3.19 -from xen.xend.xenstore.xstransact import xstransact
    3.20  
    3.21  from xen.xend.server import channel
    3.22  
    3.23 @@ -86,15 +86,13 @@ class ImageHandler:
    3.24  
    3.25      findImageHandlerClass = classmethod(findImageHandlerClass)
    3.26  
    3.27 -    def create(cls, vm, image):
    3.28 +    def create(cls, vm, imageConfig, deviceConfig):
    3.29          """Create an image handler for a vm.
    3.30  
    3.31 -        @param vm vm
    3.32 -        @param image image config
    3.33          @return ImageHandler instance
    3.34          """
    3.35 -        imageClass = cls.findImageHandlerClass(image)
    3.36 -        return imageClass(vm, image)
    3.37 +        imageClass = cls.findImageHandlerClass(imageConfig)
    3.38 +        return imageClass(vm, imageConfig, deviceConfig)
    3.39  
    3.40      create = classmethod(create)
    3.41  
    3.42 @@ -109,29 +107,25 @@ class ImageHandler:
    3.43  
    3.44      flags = 0
    3.45  
    3.46 -    def __init__(self, vm, config=None):
    3.47 +    def __init__(self, vm, imageConfig, deviceConfig):
    3.48          self.vm = vm
    3.49 -        self.configure(config)
    3.50 +        self.configure(imageConfig, deviceConfig)
    3.51  
    3.52 -    def configure(self, config):
    3.53 +    def configure(self, imageConfig, _):
    3.54          """Config actions common to all unix-like domains."""
    3.55 -        if not config:
    3.56 -            self.kernel, self.cmdline, self.ramdisk = self.vm.gatherVm(
    3.57 -                ("image/kernel"), ("image/cmdline"), ("image/ramdisk"))
    3.58 -            return
    3.59 -        
    3.60 -        self.kernel = sxp.child_value(config, "kernel")
    3.61 +
    3.62 +        self.kernel = sxp.child_value(imageConfig, "kernel")
    3.63          self.cmdline = ""
    3.64 -        ip = sxp.child_value(config, "ip", None)
    3.65 +        ip = sxp.child_value(imageConfig, "ip", None)
    3.66          if ip:
    3.67              self.cmdline += " ip=" + ip
    3.68 -        root = sxp.child_value(config, "root")
    3.69 +        root = sxp.child_value(imageConfig, "root")
    3.70          if root:
    3.71              self.cmdline += " root=" + root
    3.72 -        args = sxp.child_value(config, "args")
    3.73 +        args = sxp.child_value(imageConfig, "args")
    3.74          if args:
    3.75              self.cmdline += " " + args
    3.76 -        self.ramdisk = sxp.child_value(config, "ramdisk", '')
    3.77 +        self.ramdisk = sxp.child_value(imageConfig, "ramdisk", '')
    3.78          
    3.79          self.vm.storeVm(("image/ostype", self.ostype),
    3.80                          ("image/kernel", self.kernel),
    3.81 @@ -145,22 +139,22 @@ class ImageHandler:
    3.82          except OSError, ex:
    3.83              log.warning("error removing bootloader file '%s': %s", f, ex)
    3.84  
    3.85 -    def initDomain(self, dom, memory, ssidref, cpu, cpu_weight):
    3.86 +    def initDomain(self, dom, memory, ssidref, cpu, cpu_weight, bootloading):
    3.87          """Initial domain create.
    3.88  
    3.89 +        @param memory In KiB
    3.90          @return domain id
    3.91          """
    3.92  
    3.93          mem_kb = self.getDomainMemory(memory)
    3.94 -        if not self.vm.restore:
    3.95 -            dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
    3.96 -            # if bootloader, unlink here. But should go after buildDomain() ?
    3.97 -            if self.vm.bootloader:
    3.98 -                self.unlink(self.kernel)
    3.99 -                self.unlink(self.ramdisk)
   3.100 -            if dom <= 0:
   3.101 -                raise VmError('Creating domain failed: name=%s' %
   3.102 -                              self.vm.getName())
   3.103 +        dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
   3.104 +        # if bootloader, unlink here. But should go after buildDomain() ?
   3.105 +        if bootloading:
   3.106 +            self.unlink(self.kernel)
   3.107 +            self.unlink(self.ramdisk)
   3.108 +        if dom <= 0:
   3.109 +            raise VmError('Creating domain failed: name=%s' %
   3.110 +                          self.vm.getName())
   3.111          log.debug("initDomain: cpu=%d mem_kb=%d ssidref=%d dom=%d", cpu, mem_kb, ssidref, dom)
   3.112          xc.domain_setcpuweight(dom, cpu_weight)
   3.113          xc.domain_setmaxmem(dom, mem_kb)
   3.114 @@ -184,9 +178,6 @@ class ImageHandler:
   3.115      def createDomain(self):
   3.116          """Build the domain boot image.
   3.117          """
   3.118 -        if self.vm.recreate or self.vm.restore:
   3.119 -            return
   3.120 -
   3.121          # Set params and call buildDomain().
   3.122          self.flags = self.vm.getBackendFlags()
   3.123  
   3.124 @@ -205,9 +196,11 @@ class ImageHandler:
   3.125              raise VmError('Building domain failed: ostype=%s dom=%d err=%d'
   3.126                            % (self.ostype, self.vm.getDomain(), err))
   3.127  
   3.128 -    def getDomainMemory(self, mem_mb):
   3.129 -        """Memory (in KB) the domain will need for mem_mb (in MB)."""
   3.130 -        return mem_mb * 1024
   3.131 +    def getDomainMemory(self, mem):
   3.132 +        """@return The memory required, in KiB, by the domain to store the
   3.133 +        given amount, also in KiB.  This is normally just mem, but VMX domains
   3.134 +        have overheads to account for."""
   3.135 +        return mem
   3.136  
   3.137      def buildDomain(self):
   3.138          """Build the domain. Define in subclass."""
   3.139 @@ -269,38 +262,33 @@ class VmxImageHandler(ImageHandler):
   3.140  
   3.141      ostype = "vmx"
   3.142  
   3.143 -    memmap = None
   3.144 -    memmap_value = []
   3.145 -    device_channel = None
   3.146 -    pid = 0
   3.147 -
   3.148 -    def configure(self, config):
   3.149 -        ImageHandler.configure(self, config)
   3.150 -        if not config:
   3.151 -            self.memmap, dmargs, self.device_model, self.display = self.vm.gatherVm(
   3.152 -                ("image/memmap"), ("image/dmargs"), ("image/device-model"),
   3.153 -                ("image/display"))
   3.154 -            self.dmargs = dmargs.split(' ')
   3.155 -            return
   3.156 +    def configure(self, imageConfig, deviceConfig):
   3.157 +        ImageHandler.configure(self, imageConfig, deviceConfig)
   3.158          
   3.159 -        self.memmap = sxp.child_value(config, 'memmap')
   3.160 -        self.dmargs = self.parseDeviceModelArgs(config)
   3.161 -        self.device_model = sxp.child_value(config, 'device_model')
   3.162 +        self.memmap = sxp.child_value(imageConfig, 'memmap')
   3.163 +        self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig)
   3.164 +        self.device_model = sxp.child_value(imageConfig, 'device_model')
   3.165          if not self.device_model:
   3.166              raise VmError("vmx: missing device model")
   3.167 -        self.display = sxp.child_value(config, 'display')
   3.168 +        self.display = sxp.child_value(imageConfig, 'display')
   3.169  
   3.170          self.vm.storeVm(("image/memmap", self.memmap),
   3.171                          ("image/dmargs", " ".join(self.dmargs)),
   3.172                          ("image/device-model", self.device_model),
   3.173                          ("image/display", self.display))
   3.174  
   3.175 +        self.device_channel = None
   3.176 +        self.pid = 0
   3.177 +        self.memmap_value = []
   3.178 +
   3.179 +        self.dmargs += self.configVNC(imageConfig)
   3.180 +
   3.181 +
   3.182      def createImage(self):
   3.183          """Create a VM for the VMX environment.
   3.184          """
   3.185          self.parseMemmap()
   3.186          self.createDomain()
   3.187 -        self.dmargs += self.configVNC(sxp.child_value(self.vm.config, 'image'))
   3.188  
   3.189      def buildDomain(self):
   3.190          # Create an event channel
   3.191 @@ -314,7 +302,7 @@ class VmxImageHandler(ImageHandler):
   3.192                             image          = self.kernel,
   3.193                             control_evtchn = self.device_channel.port2,
   3.194                             store_evtchn   = store_evtchn,
   3.195 -                           memsize        = self.vm.getMemoryTarget(),
   3.196 +                           memsize        = self.vm.getMemoryTarget() / 1024,
   3.197                             memmap         = self.memmap_value,
   3.198                             cmdline        = self.cmdline,
   3.199                             ramdisk        = self.ramdisk,
   3.200 @@ -334,12 +322,12 @@ class VmxImageHandler(ImageHandler):
   3.201          
   3.202      # Return a list of cmd line args to the device models based on the
   3.203      # xm config file
   3.204 -    def parseDeviceModelArgs(self, config):
   3.205 +    def parseDeviceModelArgs(self, imageConfig, deviceConfig):
   3.206          dmargs = [ 'cdrom', 'boot', 'fda', 'fdb',
   3.207                     'localtime', 'serial', 'stdvga', 'isa' ] 
   3.208          ret = []
   3.209          for a in dmargs:
   3.210 -            v = sxp.child_value(config, a)
   3.211 +            v = sxp.child_value(imageConfig, a)
   3.212  
   3.213              # python doesn't allow '-' in variable names
   3.214              if a == 'stdvga': a = 'std-vga'
   3.215 @@ -354,14 +342,11 @@ class VmxImageHandler(ImageHandler):
   3.216                  ret.append("%s" % v)
   3.217  
   3.218          # Handle disk/network related options
   3.219 -        devices = sxp.children(self.vm.config, 'device')
   3.220 -        for device in devices:
   3.221 -            name = sxp.name(sxp.child0(device))
   3.222 +        for (name, info) in deviceConfig:
   3.223              if name == 'vbd':
   3.224 -               vbdinfo = sxp.child(device, 'vbd')
   3.225 -               uname = sxp.child_value(vbdinfo, 'uname')
   3.226 -               typedev = sxp.child_value(vbdinfo, 'dev')
   3.227 -               (vbdtype, vbdparam) = string.split(uname, ':', 1)
   3.228 +               uname = sxp.child_value(info, 'uname')
   3.229 +               typedev = sxp.child_value(info, 'dev')
   3.230 +               (_, vbdparam) = string.split(uname, ':', 1)
   3.231                 if re.match('^ioemu:', typedev):
   3.232                    (emtype, vbddev) = string.split(typedev, ':', 1)
   3.233                 else:
   3.234 @@ -375,13 +360,11 @@ class VmxImageHandler(ImageHandler):
   3.235                 ret.append("-%s" % vbddev)
   3.236                 ret.append("%s" % vbdparam)
   3.237              if name == 'vif':
   3.238 -               vifinfo = sxp.child(device, 'vif')
   3.239 -               mac = sxp.child_value(vifinfo, 'mac')
   3.240 +               mac = sxp.child_value(info, 'mac')
   3.241                 ret.append("-macaddr")
   3.242                 ret.append("%s" % mac)
   3.243              if name == 'vtpm':
   3.244 -               vtpminfo = sxp.child(device, 'vtpm')
   3.245 -               instance = sxp.child_value(vtpminfo, 'instance')
   3.246 +               instance = sxp.child_value(info, 'instance')
   3.247                 ret.append("-instance")
   3.248                 ret.append("%s" % instance)
   3.249          return ret
   3.250 @@ -417,7 +400,7 @@ class VmxImageHandler(ImageHandler):
   3.251              args = args + vnc
   3.252          args = args + ([ "-d",  "%d" % self.vm.getDomain(),
   3.253                    "-p", "%d" % self.device_channel.port1,
   3.254 -                  "-m", "%s" % self.vm.getMemoryTarget() ])
   3.255 +                  "-m", "%s" % self.vm.getMemoryTarget() / 1024 ])
   3.256          args = args + self.dmargs
   3.257          env = dict(os.environ)
   3.258          env['DISPLAY'] = self.display
   3.259 @@ -445,13 +428,14 @@ class VmxImageHandler(ImageHandler):
   3.260          if not self.pid:
   3.261              return
   3.262          os.kill(self.pid, signal.SIGKILL)
   3.263 -        (pid, status) = os.waitpid(self.pid, 0)
   3.264 +        os.waitpid(self.pid, 0)
   3.265          self.pid = 0
   3.266  
   3.267 -    def getDomainMemory(self, mem_mb):
   3.268 +    def getDomainMemory(self, mem):
   3.269 +        """@see ImageHandler.getDomainMemory"""
   3.270          # for ioreq_t and xenstore
   3.271          static_pages = 2
   3.272 -        return (mem_mb * 1024) + self.getPageTableSize(mem_mb) + 4 * static_pages
   3.273 +        return mem + self.getPageTableSize(mem * 1024) + 4 * static_pages
   3.274              
   3.275      def getPageTableSize(self, mem_mb):
   3.276          """Return the size of memory needed for 1:1 page tables for physical