WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [XEND] XendConfig is an extended python d

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [XEND] XendConfig is an extended python dictionary that is used to exchange
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 02 Nov 2006 22:08:26 +0000
Delivery-date: Thu, 02 Nov 2006 21:41:20 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [XEND] XendConfig is an extended python dictionary that is used to exchange, Xen patchbot-unstable <=