# 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
|