[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [XEND] XendConfig is an extended python dictionary that is used to exchange



# HG changeset patch
# User Alastair Tse <atse@xxxxxxxxxxxxx>
# Node ID ec29b6262a8bb7a3c659b208ffeb310ecd9595e0
# Parent  ea65d8be211f8531db307c14f6f63dddd052280e
[XEND] XendConfig is an extended python dictionary that is used to exchange
VM configuration information to allow easy import and export to different
file types.

Signed-off-by: Alastair Tse <atse@xxxxxxxxxxxxx>
---
 tools/python/xen/xend/XendConfig.py |  819 ++++++++++++++++++++++++++++++++++++
 1 files changed, 819 insertions(+)

diff -r ea65d8be211f -r ec29b6262a8b tools/python/xen/xend/XendConfig.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendConfig.py       Thu Oct 05 17:29:19 2006 +0100
@@ -0,0 +1,819 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2006 XenSource Ltd
+#============================================================================
+
+import re
+import time
+
+from xen.xend import sxp
+from xen.xend import uuid
+from xen.xend.XendError import VmError
+from xen.xend.XendDevices import XendDevices
+from xen.xend.XendLogging import log
+from xen.xend.PrettyPrint import prettyprintstring
+
+"""
+XendConfig API
+
+  XendConfig will try to mirror as closely the Xen API VM Struct
+  providing a backwards compatibility mode for SXP dumping, loading.
+
+XendConfig is a subclass of the python dict in order to emulate the
+previous behaviour of the XendDomainInfo.info dictionary. However,
+the new dictionary also exposes a set of attributes that implement
+the Xen API VM configuration interface.
+
+Example:
+
+>>> cfg = XendConfig(cfg = dict_from_xc_domain_getinfo)
+>>> cfg.name_label
+Domain-0
+>>> cfg['name']
+Domain-0
+>>> cfg.kernel_kernel
+/boot/vmlinuz-xen
+>>> cfg.kernel_initrd
+/root/initrd
+>>> cfg.kernel_args
+root=/dev/sda1 ro
+>>> cfg['image']
+(linux
+  (kernel /boot/vmlinuz-xen)
+  (ramdisk /root/initrd)
+  (root '/dev/sda1 ro'))
+>>>  
+
+Internally, XendConfig will make sure changes via the old 'dict'
+interface get reflected, if possible, to the attribute store.
+
+It does this by overriding __setitem__, __getitem__, __hasitem__,
+__getattr__, __setattr__, __hasattr__.
+
+What this means is that as code is moved from the SXP interface to
+the Xen API interface, we can spot unported code by tracing calls
+to  __getitem__ and __setitem__.
+
+"""
+
+
+LEGACY_CFG_TO_XENAPI_CFG = {
+    'uuid': 'uuid',
+    'vcpus': 'vcpus_number',
+    'maxmem': 'memory_static_max',
+    'memory': 'memory_static_min',
+    'name': 'name_label',
+    'on_poweroff': 'actions_after_shutdown',            
+    'on_reboot': 'actions_after_reboot',
+    'on_crash': 'actions_after_crash',
+    'bootloader': 'boot_method',
+    'kernel_kernel': 'kernel_kernel',
+    'kernel_initrd': 'kernel_initrd',
+    'kernel_args': 'kernel_args',
+    }
+
+XENAPI_CFG_CUSTOM_TRANSLATE = [
+    'vifs',
+    'vbds',
+    ]
+
+XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [
+    'name_description',
+    'user_version',
+    'is_a_template',
+    'memory_dynamic_min',
+    'memory_dynamic_max',
+    'memory_actual',
+    'vcpus_policy',
+    'vcpus_params',
+    'vcpus_features_required',
+    'vcpus_features_can_use',
+    'vcpus_features_force_on',
+    'vcpus_features_force_off',
+    'actions_after_suspend',
+    'tpm_instance',
+    'tpm_backends',
+    'bios_boot',
+    'platform_std_vga',
+    'platform_serial',
+    'platform_localtime',
+    'platform_clock_offset',
+    'platform_enable_audio',
+    'builder',
+    'grub_cmdline',
+    'pci_bus',
+    'otherconfig'
+    ]
+
+##
+## Xend Configuration Parameters
+##
+
+
+# All parameters of VMs that may be configured on-the-fly, or at start-up.
+VM_CONFIG_ENTRIES = [
+    ('autostart',  int),
+    ('autostop',   int),    
+    ('name',        str),
+    ('on_crash',    str),
+    ('on_poweroff', str),
+    ('on_reboot',   str),
+    ('on_xend_stop', str),        
+]
+
+# All entries written to the store.  This is VM_CONFIG_ENTRIES, plus those
+# entries written to the store that cannot be reconfigured on-the-fly.
+VM_STORE_ENTRIES = [
+    ('uuid',       str),
+    ('vcpus',      int),
+    ('vcpu_avail', int),
+    ('memory',     int),
+    ('maxmem',     int),
+    ('start_time', float),
+]
+
+VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES
+
+# Configuration entries that we expect to round-trip -- be read from the
+# config file or xc, written to save-files (i.e. through sxpr), and reused as
+# config on restart or restore, all without munging.  Some configuration
+# entries are munged for backwards compatibility reasons, or because they
+# don't come out of xc in the same form as they are specified in the config
+# file, so those are handled separately.
+
+ROUNDTRIPPING_CONFIG_ENTRIES = [
+    ('uuid',       str),
+    ('vcpus',      int),
+    ('vcpu_avail', int),
+    ('cpu_weight', float),
+    ('memory',     int),
+    ('shadow_memory', int),
+    ('maxmem',     int),
+    ('bootloader', str),
+    ('bootloader_args', str),
+    ('features', str),
+    ('localtime', int),
+]
+ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES
+
+## Static Configuration
+
+STATIC_CONFIG_ENTRIES = [
+    ('cpu',      int),
+    ('cpus',     str),
+    ('image',    list),
+    ('security', list), # TODO: what if null?
+]
+
+DEPRECATED_ENTRIES = [
+    ('restart', str),
+]
+
+##
+## Config Choices
+##
+
+CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
+CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
+                         'crashed', 'dying')
+
+##
+## Defaults
+##
+
+def DEFAULT_VCPUS(info):
+    if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1
+    else: return 1
+
+DEFAULT_CONFIGURATION = (
+    ('uuid',         lambda info: uuid.createString()),
+    ('name',         lambda info: 'Domain-' + info['uuid']),
+
+    ('on_poweroff',  lambda info: 'destroy'),
+    ('on_reboot',    lambda info: 'restart'),
+    ('on_crash',     lambda info: 'restart'),
+    ('features',     lambda info: ''),
+
+    
+    ('memory',       lambda info: 0),
+    ('shadow_memory',lambda info: 0),
+    ('maxmem',       lambda info: 0),
+    ('bootloader',   lambda info: None),
+    ('bootloader_args', lambda info: None),            
+    ('backend',      lambda info: []),
+    ('device',       lambda info: {}),
+    ('image',        lambda info: None),
+    ('security',     lambda info: []),
+    ('autostart',    lambda info: 0),
+    ('autostop',     lambda info: 0),
+    ('on_xend_stop', lambda info: 'shutdown'),
+
+    ('cpus',         lambda info: []),
+    ('cpu_weight',   lambda info: 1.0),
+    ('vcpus',        lambda info: DEFAULT_VCPUS(info)),
+    ('online_vcpus', lambda info: info['vcpus']),
+    ('max_vcpu_id',  lambda info: info['vcpus']-1),
+    ('vcpu_avail',   lambda info: (1<<info['vcpus'])-1),
+
+    # New for Xen API
+    ('kernel_kernel', lambda info: ''),
+    ('kernel_initrd', lambda info: ''),
+    ('kernel_args',   lambda info: ''),
+    
+)
+    
+class XendConfigError(VmError):
+    def __str__(self):
+        return 'Invalid Configuration: %s' % str(self.value)
+
+##
+## XendConfig SXP Config Compat
+##
+
+class XendSXPConfig:
+    def get_domid(self):
+        pass
+    def get_handle(self):
+        return self['uuid']
+        
+
+##
+## XendConfig Class (an extended dictionary)
+##
+
+class XendConfig(dict):
+    """ Generic Configuration Parser accepting SXP, Python or XML.
+    This is a dictionary-like object that is populated.
+
+    @ivar legacy: dictionary holding legacy xen domain info
+    @ivar xenapi: dictionary holding xen api config info
+    """
+
+    def __init__(self, filename = None, fd = None,
+                 sxp = None, xml = None, pycfg = None, xenapi_vm = None,
+                 cfg = {}):
+        """Constructor. Provide either the filename, fd or sxp.
+
+        @keyword filename: filename of an SXP file
+        @keyword fd: file descriptor of an SXP file
+        @keyword sxp: a list of list of a parsed SXP
+        @keyword xml: an XML tree object
+        @keyword xenapi_vm: a struct passed from an XMLRPC call (Xen API)
+        @keyword cfg: a dictionary of configuration (eg. from xc)
+        """
+        format = 'unknown'
+
+        self.xenapi = {}
+
+        if filename and not fd:
+            fd = open(filename, 'r')
+
+        if fd:
+            format = self._detect_format(fd)
+        
+        if fd:
+            if format == 'sxp':
+                sxp = self._read_sxp(fd)
+            elif format == 'python' and filename != None:
+                pycfg = self._read_python(filename)
+            elif format == 'python' and filename == None:
+                raise XendConfigError("Python files must be passed as a "
+                                      "filename rather than file descriptor.")
+            elif format == 'xml':
+                xml = self._read_xml(fd)
+            else:
+                raise XendConfigError("Unable to determine format of file")
+                
+        if sxp:
+            cfg = self._populate_from_sxp(sxp)
+        if xml:
+            cfg = self._populate_from_xml(xml)
+        if pycfg:
+            cfg = self._populate_from_python_config(pycfg)
+        if xenapi_vm:
+            cfg = self._populate_from_xenapi_vm(xenapi_vm)
+            
+        if cfg:
+            self.update(cfg)
+            
+        if xenapi_vm:
+            self.xenapi.update(xenapi_vm)
+
+        log.debug('XendConfig: %s' % str(self))
+        self.validate()
+
+    #
+    # Xen API Attribute Access
+    #
+
+    def __getattr__(self, name):
+        try:
+            return dict.__getattr__(self, name)
+        except AttributeError:
+            try:
+                return  self.__dict__['xenapi'][name]
+            except KeyError:
+                raise AttributeError("XendConfig Xen API has no attribute "
+                                     "'%s'" % name)
+            
+
+    def __setattr__(self, name, value):
+        try:
+            return dict.__setattr__(self, name, value)
+        except AttributeError:
+            self.xenapi[name] = value
+            #self.set_legacy_api_with_xen_api_value(name, value)
+
+    def __delattr__(self, name):
+        try:
+            dict.__delattr__(self, name)
+        except AttributeError:
+            del self.xenapi[name]
+        #self.del_legacy_api_with_xen_api_key(name)
+
+
+    """
+    #
+    # Legacy API Attribute Access
+    #
+
+    def __getitem__(self, key):
+        try:
+            return self.legacy[key]
+        except KeyError:
+            raise AttributeError, "XendConfig Legacy has no attribute '%s'"\
+                  % key
+
+    def __setitem__(self, key, value):
+        self.legacy[key] = value
+        self.set_xen_api_with_legacy_api_value(key, value)
+
+    def __delitem__(self, key):
+        del self.legacy[key]
+        self.del_xen_api_with_legacy_api_key(key)
+    """
+    
+
+    def _detect_format(self, fd):
+        """Detect the format of the configuration passed.
+
+        @param fd: file descriptor of contents to detect
+        @rtype: string, 'sxp', 'xml', 'python' or 'unknown'
+        """
+        format = 'unknown'
+        
+        fd.seek(0)
+        for line in fd:
+            stripped = line.strip()
+            if stripped:
+                if re.search(r'^\(', stripped): 
+                    format = 'sxp'
+                elif re.search(r'^\<?xml', stripped):
+                    format = 'xml'
+                else:
+                    format = 'python'
+                break
+
+        fd.seek(0)
+        return format
+
+    def _read_sxp(self, fd):
+        """ Read and parse SXP (from SXP to list of lists)
+
+        @rtype: list of lists.
+        """
+        try:
+            parsed = sxp.parse(fd)[0]
+            return parsed
+        except:
+            raise
+            return None
+
+    def _read_xml(self, fd):
+        """TODO: Read and parse XML (from XML to dict)
+
+        @rtype: dict
+        """
+        raise NotImplementedError
+
+    def _read_python(self, filename):
+        """Read and parse python module that represents the config.
+
+        @rtype: dict
+        """
+        cfg_globals = {}
+        execfile(filename, cfg_globals, {})
+        return cfg_globals
+
+    def _populate_from_sxp(self, parsed):
+        """ Populate this XendConfig using the parsed SXP.
+
+        @rtype: dictionary
+        """
+        cfg = {}
+
+        # First step is to convert deprecated options to
+        # current equivalents.
+        
+        restart = sxp.child_value(parsed, 'restart')
+        if restart:
+            if restart == 'onreboot':
+                cfg['on_poweroff'] = 'destroy'
+                cfg['on_reboot'] = 'restart'
+                cfg['on_crash'] = 'destroy'
+            elif restart == 'always':
+                for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
+                    cfg[opt] = 'restart'
+            elif restart == 'never':
+                for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
+                    cfg[opt] = 'never'                
+            else:
+                log.warn('Ignoring unrecognised value for deprecated option:'
+                         'restart = \'%s\'', restart)
+
+        # Only extract options we know about.
+        all_params = VM_CONFIG_ENTRIES + ROUNDTRIPPING_CONFIG_ENTRIES + \
+                     STATIC_CONFIG_ENTRIES
+                     
+        for key, typeconv in all_params:
+            val = sxp.child_value(parsed, key)
+            if val:
+                try:
+                    cfg[key] = typeconv(val)
+                except ValueError:
+                    pass
+
+        # Manually extract other complex configuration
+        # options.
+
+        cfg['backend'] = []
+        for c in sxp.children(parsed, 'backend'):
+            cfg['backend'].append(sxp.name(sxp.child0(c)))
+
+        cfg['device'] = {}
+        for dev in sxp.children(parsed, 'device'):
+            config = sxp.child0(dev)
+            dev_type = sxp.name(config)
+            dev_info = {}
+            for opt, val in config[1:]:
+                dev_info[opt] = val
+
+            # create uuid if it doesn't
+            dev_uuid = dev_info.get('uuid', uuid.createString())
+            dev_info['uuid'] = dev_uuid
+            cfg['device'][dev_uuid] = (dev_type, dev_info)
+            
+            #cfg['device'].append((sxp.name(config), config))
+
+
+        # Extract missing data from configuration entries
+        if 'image' in cfg:
+            image_vcpus = sxp.child_value(cfg['image'], 'vcpus')
+            if image_vcpus is not None:
+                try:
+                    if 'vcpus' not in cfg:
+                        cfg['vcpus'] = int(image_vcpus)
+                    elif cfg['vcpus'] != int(image_vcpus):
+                        cfg['vcpus'] = int(image_vcpus)
+                        log.warn('Overriding vcpus from %d to %d using image'
+                                 'vcpus value.', cfg['vcpus'])
+                except ValueError, e:
+                    raise XendConfigError('integer expeceted: %s: %s' %
+                                        str(cfg['image']), e)
+
+
+        # Deprecated cpu configuration
+        if 'cpu' in cfg:
+            if 'cpus' in cfg:
+                cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
+            else:
+                cfg['cpus'] = str(cfg['cpu'])
+
+        # convert 'cpus' string to list of ints
+        # 'cpus' supports a list of ranges (0-3), seperated by
+        # commas, and negation, (^1).  
+        # Precedence is settled by  order of the string:
+        #     "0-3,^1"   -> [0,2,3]
+        #     "0-3,^1,1" -> [0,1,2,3]
+        try:
+            if 'cpus' in cfg:
+                cpus = []
+                for c in cfg['cpus'].split(','):
+                    if c.find('-') != -1:             
+                        (x, y) = c.split('-')
+                        for i in range(int(x), int(y)+1):
+                            cpus.append(int(i))
+                    else:
+                        # remove this element from the list 
+                        if c[0] == '^':
+                            cpus = [x for x in cpus if x != int(c[1:])]
+                        else:
+                            cpus.append(int(c))
+
+                cfg['cpus'] = cpus
+        except ValueError, e:
+            raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
+
+        # Parse image SXP outside of image.py
+        # - used to be only done in image.py
+        if 'image' in cfg:
+            cfg['kernel_kernel'] = sxp.child_value(cfg['image'], 'kernel','')
+            cfg['kernel_initrd'] = sxp.child_value(cfg['image'], 'ramdisk','')
+            kernel_args = sxp.child_value(cfg['image'], 'args', '')
+
+            # attempt to extract extra arguments from SXP config
+            arg_ip = sxp.child_value(cfg['image'], 'ip')
+            if arg_ip: kernel_args += ' ip=%s' % arg_ip
+            arg_root = sxp.child_value(cfg['image'], 'root')
+            if arg_root: kernel_args += ' root=%s' % arg_root
+            
+            cfg['kernel_args'] = kernel_args
+
+        # TODO: get states
+        old_state = sxp.child_value(parsed, 'state')
+        if old_state:
+            for i in range(len(CONFIG_OLD_DOM_STATES)):
+                cfg[CONFIG_OLD_DOM_STATES[i]] = (old_state[i] != '-')
+
+        # Xen API extra cfgs
+        # ------------------
+        cfg['vif_refs'] = []
+        cfg['vbd_refs'] = []
+        for dev_uuid, (dev_type, dev_info) in cfg['device'].items():
+            if dev_type == 'vif':
+                cfg['vif_refs'].append(dev_uuid)
+            elif dev_type == 'vbd':
+                cfg['vbd_refs'].append(dev_uuid)
+                
+        return cfg
+
+
+    def _populate_from_xenapi_vm(self, xenapi_vm):
+        cfg = {}
+
+        for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
+            try:
+                cfg[cfgkey] = xenapi_vm[apikey]
+            except KeyError:
+                pass
+
+        # Reconstruct image SXP 
+        # TODO: get rid of SXP altogether from here
+        sxp_image = ['linux']
+        if xenapi_vm['kernel_kernel']:
+            sxp_image.append(['kernel', xenapi_vm['kernel_kernel']])
+        if xenapi_vm['kernel_initrd']:
+            sxp_image.append(['ramdisk', xenapi_vm['kernel_initrd']])
+        if xenapi_vm['kernel_args']:
+            sxp_image.append(['args', xenapi_vm['kernel_args']])
+        cfg['image'] = prettyprintstring(sxp_image)
+
+        # make sure device structures are there.
+        if 'device' not in cfg:
+            cfg['device'] = {}
+        if 'vif_refs' not in cfg:
+            cfg['vif_refs'] = []
+        if 'vbd_refs' not in cfg:
+            cfg['vbd_refs'] = []
+
+        return cfg
+
+
+    def _sync_xen_api_from_legacy_api(self):
+        """ Sync all the attributes that is supported by the Xen API
+        from the legacy API configuration.
+        """
+        for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():        
+            if cfgkey in self:
+                self.xenapi[apikey] = self[cfgkey]
+
+    def _sync_legacy_api_from_xen_api(self):
+        for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
+            if apikey in self.xenapi:
+                self[cfgkey] = self.xenapi[apikey]
+
+
+    def _populate_from_xml(self, parsed_xml):
+        raise NotImplementedError
+
+    def _populate_from_python_config(self, parsed_py):
+        raise NotImplementedError
+        
+
+    def get_sxp(self, domain = None, ignore_devices = False, ignore = []):
+        """ Get SXP representation of this config object.
+
+        Incompat: removed store_mfn, console_mfn
+
+        @keyword domain: (optional) XendDomainInfo to get extra information
+                         from such as domid and running devices.
+        @type    domain: XendDomainInfo
+        @keyword ignore: (optional) list of 'keys' that we do not want
+                         to export.
+        @type    ignore: list of strings
+        @rtype: list of list (SXP representation)
+        """
+        sxpr = ['domain']
+
+        # TODO: domid/dom is the same thing but called differently
+        #       depending if it is from xenstore or sxpr.
+
+        if domain.getDomid() != None:
+            sxpr.append(['domid', domain.getDomid()])
+
+        for cfg, typefunc in ROUNDTRIPPING_CONFIG_ENTRIES:
+            if cfg in self:
+                if self[cfg] != None:
+                    sxpr.append([cfg, self[cfg]])
+
+        if 'image' in self:
+            sxpr.append(['image', self['image']])
+        if 'security' in self:
+            sxpr.append(['security', self['security']])
+        if 'shutdown_reason' in self:
+            sxpr.append(['shutdown_reason', self['shutdown_reason']])
+        if 'cpu_time' in self:
+            sxpr.append(['cpu_time', self['cpu_time']/1e9])
+
+        sxpr.append(['online_vcpus', self['online_vcpus']])
+
+        if 'start_time' in self:
+            uptime = time.time() - self['start_time']
+            sxpr.append(['up_time', str(uptime)])
+            sxpr.append(['start_time', str(self['start_time'])])
+
+        sxpr.append(['autostart', self.get('autostart', 0)])
+        sxpr.append(['autostop', self.get('autostop', 0)])
+        sxpr.append(['on_xend_stop', self.get('on_xend_stop', 'shutdown')])
+
+        sxpr.append(['status', domain.state])
+
+        # Marshall devices (running or from configuration)
+        if not ignore_devices:
+            for cls in XendDevices.valid_devices():
+                found = False
+                
+                # figure if there is a device that is running
+                if domain:
+                    try:
+                        controller = domain.getDeviceController(cls)
+                        configs = controller.configurations()
+                        for config in configs:
+                            sxpr.append(['device', config])
+                            found = True
+                    except:
+                        log.exception("dumping sxp from device controllers")
+                        pass
+                        
+                # if we didn't find that device, check the existing config
+                # for a device in the same class
+                if not found:
+                    for dev_type, dev_info in self.all_devices_sxpr():
+                        if dev_type == cls:
+                            sxpr.append(['device', dev_info])
+
+        return sxpr
+
+    def validate(self):
+        """ Validate the configuration and fill in missing configuration
+        with defaults.
+        """
+
+        # Fill in default values
+        for key, default_func in DEFAULT_CONFIGURATION:
+            if key not in self:
+                self[key] = default_func(self)
+
+        # Basic sanity checks
+        if 'image' in self and isinstance(self['image'], str):
+            self['image'] = sxp.from_string(self['image'])
+        if 'security' in self and isinstance(self['security'], str):
+            self['security'] = sxp.from_string(self['security'])
+        if self['memory'] == 0 and 'mem_kb' in self:
+            self['memory'] = (self['mem_kb'] + 1023)/1024
+        if self['memory'] <= 0:
+            raise XendConfigError('Invalid memory size: %s' %
+                                  str(self['memory']))
+
+        self['maxmem'] = max(self['memory'], self['maxmem'])
+
+        # Verify devices
+        for d_uuid, (d_type, d_info) in self['device'].items():
+            if d_type not in XendDevices.valid_devices():
+                raise XendConfigError('Invalid device (%s)' % d_type)
+
+        # Verify restart modes
+        for event in ('on_poweroff', 'on_reboot', 'on_crash'):
+            if self[event] not in CONFIG_RESTART_MODES:
+                raise XendConfigError('Invalid restart event: %s = %s' % \
+                                      (event, str(self[event])))
+
+    def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
+        if dev_type not in XendDevices.valid_devices():
+            raise XendConfigError("XendConfig: %s not a valid device type" %
+                            dev_type)
+
+        if cfg_sxp == None and cfg_xenapi == None:
+            raise XendConfigError("XendConfig: device_add requires some "
+                                  "config.")
+
+        if cfg_sxp:
+            config = sxp.child0(cfg_sxp)
+            dev_type = sxp.name(config)
+            dev_info = {}
+
+            try:
+                for opt, val in config[1:]:
+                    dev_info[opt] = val
+            except ValueError:
+                log.debug('XendConfig.device_add: %s' % config)
+                pass # SXP has no options for this device
+
+            # create uuid if it doesn't exist
+            dev_uuid = dev_info.get('uuid', uuid.createString())
+            dev_info['uuid'] = dev_uuid
+            self['device'][dev_uuid] = (dev_type, dev_info)
+            return dev_uuid
+
+        if cfg_xenapi:
+            dev_info = {}            
+            if dev_type == 'vif':
+                if cfg_xenapi.get('MAC'): # don't add if blank
+                    dev_info['mac'] = cfg_xenapi.get('MAC')
+                # vifname is the name on the guest, not dom0
+                # TODO: we don't have the ability to find that out or
+                #       change it from dom0
+                #if cfg_xenapi.get('device'):  # don't add if blank
+                #    dev_info['vifname'] = cfg_xenapi.get('device')
+                if cfg_xenapi.get('type'):
+                    dev_info['type'] = cfg_xenapi.get('type')
+                
+                dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+                dev_info['uuid'] = dev_uuid
+                self['device'][dev_uuid] = (dev_type, dev_info)
+                return dev_uuid
+            
+            elif dev_type == 'vbd':
+                dev_info['uname'] = cfg_xenapi.get('image', None)
+                dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+                if cfg_xenapi.get('mode') == 'RW':
+                    dev_info['mode'] = 'w'
+                else:
+                    dev_info['mode'] = 'r'
+
+                dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+                dev_info['uuid'] = dev_uuid
+                self['device'][dev_uuid] = (dev_type, dev_info)
+                return dev_uuid
+                
+                
+        return ''
+
+    def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
+        """Get Device SXPR by either giving the device UUID or (type, config).
+
+        @rtype: list of lists
+        @return: device config sxpr
+        """
+        sxpr = []
+        if dev_uuid != None and dev_uuid in self['device']:
+            dev_type, dev_info = self['device']
+
+        if dev_type == None or dev_info == None:
+            raise XendConfigError("Required either UUID or device type and "
+                                  "configuration dictionary.")
+            
+        sxpr.append(dev_type)
+        config = [(opt, val) for opt, val in dev_info.items() \
+                  if opt != 'type']
+        sxpr += config
+
+        return sxpr
+
+    def all_devices_sxpr(self):
+        sxprs = []
+        for dev_type, dev_info in self['device'].values():
+            sxpr =  self.device_sxpr(dev_type = dev_type, dev_info = dev_info)
+            sxprs.append((dev_type, sxpr))
+        return sxprs
+
+                     
+#
+# debugging 
+#
+
+if __name__ == "__main__":
+    pass
+    

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.