ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 12128:e6162aeb0f89

[XEND] Remove extra tap: prefix for device uname.

Signed-off-by: Alastair Tse <atse@xensource.com>
author Alastair Tse <atse@xensource.com>
date Fri Oct 13 17:33:34 2006 +0100 (2006-10-13)
parents 91c7ee18c978
children c4df5f0a41f3
line source
1 #===========================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2006 XenSource Ltd
16 #============================================================================
18 import re
19 import time
21 from xen.xend import sxp
22 from xen.xend import uuid
23 from xen.xend.XendError import VmError
24 from xen.xend.XendDevices import XendDevices
25 from xen.xend.XendLogging import log
26 from xen.xend.PrettyPrint import prettyprintstring
28 """
29 XendConfig API
31 XendConfig will try to mirror as closely the Xen API VM Struct
32 providing a backwards compatibility mode for SXP dumping, loading.
34 XendConfig is a subclass of the python dict in order to emulate the
35 previous behaviour of the XendDomainInfo.info dictionary. However,
36 the new dictionary also exposes a set of attributes that implement
37 the Xen API VM configuration interface.
39 Example:
41 >>> cfg = XendConfig(cfg = dict_from_xc_domain_getinfo)
42 >>> cfg.name_label
43 Domain-0
44 >>> cfg['name']
45 Domain-0
46 >>> cfg.kernel_kernel
47 /boot/vmlinuz-xen
48 >>> cfg.kernel_initrd
49 /root/initrd
50 >>> cfg.kernel_args
51 root=/dev/sda1 ro
52 >>> cfg['image']
53 (linux
54 (kernel /boot/vmlinuz-xen)
55 (ramdisk /root/initrd)
56 (root '/dev/sda1 ro'))
57 >>>
59 Internally, XendConfig will make sure changes via the old 'dict'
60 interface get reflected, if possible, to the attribute store.
62 It does this by overriding __setitem__, __getitem__, __hasitem__,
63 __getattr__, __setattr__, __hasattr__.
65 What this means is that as code is moved from the SXP interface to
66 the Xen API interface, we can spot unported code by tracing calls
67 to __getitem__ and __setitem__.
69 """
72 LEGACY_CFG_TO_XENAPI_CFG = {
73 'uuid': 'uuid',
74 'vcpus': 'vcpus_number',
75 'maxmem': 'memory_static_max',
76 'memory': 'memory_static_min',
77 'name': 'name_label',
78 'on_poweroff': 'actions_after_shutdown',
79 'on_reboot': 'actions_after_reboot',
80 'on_crash': 'actions_after_crash',
81 'bootloader': 'boot_method',
82 'kernel_kernel': 'kernel_kernel',
83 'kernel_initrd': 'kernel_initrd',
84 'kernel_args': 'kernel_args',
85 }
87 XENAPI_CFG_CUSTOM_TRANSLATE = [
88 'vifs',
89 'vbds',
90 ]
92 XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [
93 'name_description',
94 'user_version',
95 'is_a_template',
96 'memory_dynamic_min',
97 'memory_dynamic_max',
98 'memory_actual',
99 'vcpus_policy',
100 'vcpus_params',
101 'vcpus_features_required',
102 'vcpus_features_can_use',
103 'vcpus_features_force_on',
104 'vcpus_features_force_off',
105 'actions_after_suspend',
106 'tpm_instance',
107 'tpm_backends',
108 'bios_boot',
109 'platform_std_vga',
110 'platform_serial',
111 'platform_localtime',
112 'platform_clock_offset',
113 'platform_enable_audio',
114 'builder',
115 'grub_cmdline',
116 'pci_bus',
117 'otherconfig'
118 ]
120 # configuration params that need to be converted to ints
121 # since the XMLRPC transport for Xen API does not use
122 # 32 bit ints but string representation of 64 bit ints.
123 XENAPI_INT_CFG = [
124 'user_version',
125 'vcpus_number',
126 'memory_static_min',
127 'memory_static_max',
128 'memory_dynamic_min',
129 'memory_dynamic_max',
130 'tpm_instance',
131 'tpm_backend',
132 ]
134 ##
135 ## Xend Configuration Parameters
136 ##
139 # All parameters of VMs that may be configured on-the-fly, or at start-up.
140 VM_CONFIG_ENTRIES = [
141 ('name', str),
142 ('on_crash', str),
143 ('on_poweroff', str),
144 ('on_reboot', str),
145 ('on_xend_start', str),
146 ('on_xend_stop', str),
147 ]
149 # All entries written to the store. This is VM_CONFIG_ENTRIES, plus those
150 # entries written to the store that cannot be reconfigured on-the-fly.
151 VM_STORE_ENTRIES = [
152 ('uuid', str),
153 ('vcpus', int),
154 ('vcpu_avail', int),
155 ('memory', int),
156 ('maxmem', int),
157 ('start_time', float),
158 ]
160 VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES
162 # Configuration entries that we expect to round-trip -- be read from the
163 # config file or xc, written to save-files (i.e. through sxpr), and reused as
164 # config on restart or restore, all without munging. Some configuration
165 # entries are munged for backwards compatibility reasons, or because they
166 # don't come out of xc in the same form as they are specified in the config
167 # file, so those are handled separately.
169 ROUNDTRIPPING_CONFIG_ENTRIES = [
170 ('uuid', str),
171 ('vcpus', int),
172 ('vcpu_avail', int),
173 ('cpu_weight', float),
174 ('memory', int),
175 ('shadow_memory', int),
176 ('maxmem', int),
177 ('bootloader', str),
178 ('bootloader_args', str),
179 ('features', str),
180 ('localtime', int),
181 ]
182 ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES
184 ## Static Configuration
186 STATIC_CONFIG_ENTRIES = [
187 ('cpu', int),
188 ('cpus', str),
189 ('image', list),
190 ('security', list), # TODO: what if null?
191 ]
193 DEPRECATED_ENTRIES = [
194 ('restart', str),
195 ]
197 ##
198 ## Config Choices
199 ##
201 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
202 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
203 'crashed', 'dying')
205 ##
206 ## Defaults
207 ##
209 def DEFAULT_VCPUS(info):
210 if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1
211 else: return 1
213 DEFAULT_CONFIGURATION = (
214 ('uuid', lambda info: uuid.createString()),
215 ('name', lambda info: 'Domain-' + info['uuid']),
217 ('on_poweroff', lambda info: 'destroy'),
218 ('on_reboot', lambda info: 'restart'),
219 ('on_crash', lambda info: 'restart'),
220 ('features', lambda info: ''),
223 ('memory', lambda info: 0),
224 ('shadow_memory',lambda info: 0),
225 ('maxmem', lambda info: 0),
226 ('bootloader', lambda info: None),
227 ('bootloader_args', lambda info: None),
228 ('backend', lambda info: []),
229 ('device', lambda info: {}),
230 ('image', lambda info: None),
231 ('security', lambda info: []),
232 ('on_xend_start', lambda info: 'ignore'),
233 ('on_xend_stop', lambda info: 'ignore'),
235 ('cpus', lambda info: []),
236 ('cpu_weight', lambda info: 1.0),
237 ('vcpus', lambda info: DEFAULT_VCPUS(info)),
238 ('online_vcpus', lambda info: info['vcpus']),
239 ('max_vcpu_id', lambda info: info['vcpus']-1),
240 ('vcpu_avail', lambda info: (1<<info['vcpus'])-1),
242 # New for Xen API
243 ('kernel_kernel', lambda info: ''),
244 ('kernel_initrd', lambda info: ''),
245 ('kernel_args', lambda info: ''),
247 )
249 class XendConfigError(VmError):
250 def __str__(self):
251 return 'Invalid Configuration: %s' % str(self.value)
253 ##
254 ## XendConfig SXP Config Compat
255 ##
257 class XendSXPConfig:
258 def get_domid(self):
259 pass
260 def get_handle(self):
261 return self['uuid']
264 ##
265 ## XendConfig Class (an extended dictionary)
266 ##
268 class XendConfig(dict):
269 """ Generic Configuration Parser accepting SXP, Python or XML.
270 This is a dictionary-like object that is populated.
272 @ivar legacy: dictionary holding legacy xen domain info
273 @ivar xenapi: dictionary holding xen api config info
274 """
276 def __init__(self, filename = None, fd = None,
277 sxp = None, xml = None, pycfg = None, xenapi_vm = None,
278 cfg = {}):
279 """Constructor. Provide either the filename, fd or sxp.
281 @keyword filename: filename of an SXP file
282 @keyword fd: file descriptor of an SXP file
283 @keyword sxp: a list of list of a parsed SXP
284 @keyword xml: an XML tree object
285 @keyword xenapi_vm: a struct passed from an XMLRPC call (Xen API)
286 @keyword cfg: a dictionary of configuration (eg. from xc)
287 """
288 format = 'unknown'
290 self.xenapi = {}
292 if filename and not fd:
293 fd = open(filename, 'r')
295 if fd:
296 format = self._detect_format(fd)
298 if fd:
299 if format == 'sxp':
300 sxp = self._read_sxp(fd)
301 elif format == 'python' and filename != None:
302 pycfg = self._read_python(filename)
303 elif format == 'python' and filename == None:
304 raise XendConfigError("Python files must be passed as a "
305 "filename rather than file descriptor.")
306 elif format == 'xml':
307 xml = self._read_xml(fd)
308 else:
309 raise XendConfigError("Unable to determine format of file")
311 if sxp:
312 cfg = self._populate_from_sxp(sxp)
313 if xml:
314 cfg = self._populate_from_xml(xml)
315 if pycfg:
316 cfg = self._populate_from_python_config(pycfg)
317 if xenapi_vm:
318 cfg = self._populate_from_xenapi_vm(xenapi_vm)
320 if cfg:
321 self.update(cfg)
323 if xenapi_vm:
324 self.xenapi.update(xenapi_vm)
326 log.debug('XendConfig: %s' % str(self))
327 self.validate()
329 #
330 # Xen API Attribute Access
331 #
333 def __getattr__(self, name):
334 try:
335 return dict.__getattr__(self, name)
336 except AttributeError:
337 try:
338 return self.__dict__['xenapi'][name]
339 except KeyError:
340 raise AttributeError("XendConfig Xen API has no attribute "
341 "'%s'" % name)
344 def __setattr__(self, name, value):
345 try:
346 return dict.__setattr__(self, name, value)
347 except AttributeError:
348 self.xenapi[name] = value
349 #self.set_legacy_api_with_xen_api_value(name, value)
351 def __delattr__(self, name):
352 try:
353 dict.__delattr__(self, name)
354 except AttributeError:
355 del self.xenapi[name]
356 #self.del_legacy_api_with_xen_api_key(name)
359 """
360 #
361 # Legacy API Attribute Access
362 #
364 def __getitem__(self, key):
365 try:
366 return self.legacy[key]
367 except KeyError:
368 raise AttributeError, "XendConfig Legacy has no attribute '%s'"\
369 % key
371 def __setitem__(self, key, value):
372 self.legacy[key] = value
373 self.set_xen_api_with_legacy_api_value(key, value)
375 def __delitem__(self, key):
376 del self.legacy[key]
377 self.del_xen_api_with_legacy_api_key(key)
378 """
381 def _detect_format(self, fd):
382 """Detect the format of the configuration passed.
384 @param fd: file descriptor of contents to detect
385 @rtype: string, 'sxp', 'xml', 'python' or 'unknown'
386 """
387 format = 'unknown'
389 fd.seek(0)
390 for line in fd:
391 stripped = line.strip()
392 if stripped:
393 if re.search(r'^\(', stripped):
394 format = 'sxp'
395 elif re.search(r'^\<?xml', stripped):
396 format = 'xml'
397 else:
398 format = 'python'
399 break
401 fd.seek(0)
402 return format
404 def _read_sxp(self, fd):
405 """ Read and parse SXP (from SXP to list of lists)
407 @rtype: list of lists.
408 """
409 try:
410 parsed = sxp.parse(fd)[0]
411 return parsed
412 except:
413 raise
414 return None
416 def _read_xml(self, fd):
417 """TODO: Read and parse XML (from XML to dict)
419 @rtype: dict
420 """
421 raise NotImplementedError
423 def _read_python(self, filename):
424 """Read and parse python module that represents the config.
426 @rtype: dict
427 """
428 cfg_globals = {}
429 execfile(filename, cfg_globals, {})
430 return cfg_globals
432 def _populate_from_sxp(self, parsed):
433 """ Populate this XendConfig using the parsed SXP.
435 @rtype: dictionary
436 """
437 cfg = {}
439 # First step is to convert deprecated options to
440 # current equivalents.
442 restart = sxp.child_value(parsed, 'restart')
443 if restart:
444 if restart == 'onreboot':
445 cfg['on_poweroff'] = 'destroy'
446 cfg['on_reboot'] = 'restart'
447 cfg['on_crash'] = 'destroy'
448 elif restart == 'always':
449 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
450 cfg[opt] = 'restart'
451 elif restart == 'never':
452 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
453 cfg[opt] = 'never'
454 else:
455 log.warn('Ignoring unrecognised value for deprecated option:'
456 'restart = \'%s\'', restart)
458 # Only extract options we know about.
459 all_params = VM_CONFIG_ENTRIES + ROUNDTRIPPING_CONFIG_ENTRIES + \
460 STATIC_CONFIG_ENTRIES
462 for key, typeconv in all_params:
463 val = sxp.child_value(parsed, key)
464 if val:
465 try:
466 cfg[key] = typeconv(val)
467 except ValueError:
468 pass
470 # Manually extract other complex configuration
471 # options.
473 cfg['backend'] = []
474 for c in sxp.children(parsed, 'backend'):
475 cfg['backend'].append(sxp.name(sxp.child0(c)))
477 cfg['device'] = {}
478 for dev in sxp.children(parsed, 'device'):
479 config = sxp.child0(dev)
480 dev_type = sxp.name(config)
481 dev_info = {}
482 for opt, val in config[1:]:
483 dev_info[opt] = val
484 log.debug("XendConfig: reading device: %s" % dev_info)
485 # create uuid if it doesn't
486 dev_uuid = dev_info.get('uuid', uuid.createString())
487 dev_info['uuid'] = dev_uuid
488 cfg['device'][dev_uuid] = (dev_type, dev_info)
490 #cfg['device'].append((sxp.name(config), config))
493 # Extract missing data from configuration entries
494 if 'image' in cfg:
495 image_vcpus = sxp.child_value(cfg['image'], 'vcpus')
496 if image_vcpus is not None:
497 try:
498 if 'vcpus' not in cfg:
499 cfg['vcpus'] = int(image_vcpus)
500 elif cfg['vcpus'] != int(image_vcpus):
501 cfg['vcpus'] = int(image_vcpus)
502 log.warn('Overriding vcpus from %d to %d using image'
503 'vcpus value.', cfg['vcpus'])
504 except ValueError, e:
505 raise XendConfigError('integer expeceted: %s: %s' %
506 str(cfg['image']), e)
509 # Deprecated cpu configuration
510 if 'cpu' in cfg:
511 if 'cpus' in cfg:
512 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
513 else:
514 cfg['cpus'] = str(cfg['cpu'])
516 # convert 'cpus' string to list of ints
517 # 'cpus' supports a list of ranges (0-3), seperated by
518 # commas, and negation, (^1).
519 # Precedence is settled by order of the string:
520 # "0-3,^1" -> [0,2,3]
521 # "0-3,^1,1" -> [0,1,2,3]
522 try:
523 if 'cpus' in cfg:
524 cpus = []
525 for c in cfg['cpus'].split(','):
526 if c.find('-') != -1:
527 (x, y) = c.split('-')
528 for i in range(int(x), int(y)+1):
529 cpus.append(int(i))
530 else:
531 # remove this element from the list
532 if c[0] == '^':
533 cpus = [x for x in cpus if x != int(c[1:])]
534 else:
535 cpus.append(int(c))
537 cfg['cpus'] = cpus
538 except ValueError, e:
539 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
541 # Parse image SXP outside of image.py
542 # - used to be only done in image.py
543 if 'image' in cfg:
544 cfg['kernel_kernel'] = sxp.child_value(cfg['image'], 'kernel','')
545 cfg['kernel_initrd'] = sxp.child_value(cfg['image'], 'ramdisk','')
546 kernel_args = sxp.child_value(cfg['image'], 'args', '')
548 # attempt to extract extra arguments from SXP config
549 arg_ip = sxp.child_value(cfg['image'], 'ip')
550 if arg_ip: kernel_args += ' ip=%s' % arg_ip
551 arg_root = sxp.child_value(cfg['image'], 'root')
552 if arg_root: kernel_args += ' root=%s' % arg_root
554 cfg['kernel_args'] = kernel_args
556 # TODO: get states
557 old_state = sxp.child_value(parsed, 'state')
558 if old_state:
559 for i in range(len(CONFIG_OLD_DOM_STATES)):
560 cfg[CONFIG_OLD_DOM_STATES[i]] = (old_state[i] != '-')
562 # Xen API extra cfgs
563 # ------------------
564 cfg['vif_refs'] = []
565 cfg['vbd_refs'] = []
566 for dev_uuid, (dev_type, dev_info) in cfg['device'].items():
567 if dev_type == 'vif':
568 cfg['vif_refs'].append(dev_uuid)
569 elif dev_type in ('vbd','tap'):
570 cfg['vbd_refs'].append(dev_uuid)
572 return cfg
575 def _populate_from_xenapi_vm(self, xenapi_vm):
576 cfg = {}
578 for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
579 try:
580 if apikey in XENAPI_INT_CFG:
581 cfg[cfgkey] = int(xenapi_vm[apikey])
582 else:
583 cfg[cfgkey] = xenapi_vm[apikey]
584 except KeyError:
585 pass
587 # Reconstruct image SXP
588 # TODO: get rid of SXP altogether from here
589 sxp_image = ['linux']
590 if xenapi_vm['kernel_kernel']:
591 sxp_image.append(['kernel', xenapi_vm['kernel_kernel']])
592 if xenapi_vm['kernel_initrd']:
593 sxp_image.append(['ramdisk', xenapi_vm['kernel_initrd']])
594 if xenapi_vm['kernel_args']:
595 sxp_image.append(['args', xenapi_vm['kernel_args']])
596 cfg['image'] = prettyprintstring(sxp_image)
598 # make sure device structures are there.
599 if 'device' not in cfg:
600 cfg['device'] = {}
601 if 'vif_refs' not in cfg:
602 cfg['vif_refs'] = []
603 if 'vbd_refs' not in cfg:
604 cfg['vbd_refs'] = []
606 return cfg
609 def _sync_xen_api_from_legacy_api(self):
610 """ Sync all the attributes that is supported by the Xen API
611 from the legacy API configuration.
612 """
613 for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
614 if cfgkey in self:
615 self.xenapi[apikey] = self[cfgkey]
617 def _sync_legacy_api_from_xen_api(self):
618 for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
619 if apikey in self.xenapi:
620 self[cfgkey] = self.xenapi[apikey]
623 def _populate_from_xml(self, parsed_xml):
624 raise NotImplementedError
626 def _populate_from_python_config(self, parsed_py):
627 raise NotImplementedError
630 def get_sxp(self, domain = None, ignore_devices = False, ignore = []):
631 """ Get SXP representation of this config object.
633 Incompat: removed store_mfn, console_mfn
635 @keyword domain: (optional) XendDomainInfo to get extra information
636 from such as domid and running devices.
637 @type domain: XendDomainInfo
638 @keyword ignore: (optional) list of 'keys' that we do not want
639 to export.
640 @type ignore: list of strings
641 @rtype: list of list (SXP representation)
642 """
643 sxpr = ['domain']
645 # TODO: domid/dom is the same thing but called differently
646 # depending if it is from xenstore or sxpr.
648 if domain.getDomid() != None:
649 sxpr.append(['domid', domain.getDomid()])
651 for cfg, typefunc in ROUNDTRIPPING_CONFIG_ENTRIES:
652 if cfg in self:
653 if self[cfg] != None:
654 sxpr.append([cfg, self[cfg]])
656 if 'image' in self:
657 sxpr.append(['image', self['image']])
658 if 'security' in self:
659 sxpr.append(['security', self['security']])
660 if 'shutdown_reason' in self:
661 sxpr.append(['shutdown_reason', self['shutdown_reason']])
662 if 'cpu_time' in self:
663 sxpr.append(['cpu_time', self['cpu_time']/1e9])
665 sxpr.append(['online_vcpus', self['online_vcpus']])
667 if 'start_time' in self:
668 uptime = time.time() - self['start_time']
669 sxpr.append(['up_time', str(uptime)])
670 sxpr.append(['start_time', str(self['start_time'])])
672 sxpr.append(['on_xend_start', self.get('on_xend_start', 'ignore')])
673 sxpr.append(['on_xend_stop', self.get('on_xend_stop', 'ignore')])
675 sxpr.append(['status', domain.state])
677 # Marshall devices (running or from configuration)
678 if not ignore_devices:
679 for cls in XendDevices.valid_devices():
680 found = False
682 # figure if there is a device that is running
683 if domain:
684 try:
685 controller = domain.getDeviceController(cls)
686 configs = controller.configurations()
687 for config in configs:
688 sxpr.append(['device', config])
689 found = True
690 except:
691 log.exception("dumping sxp from device controllers")
692 pass
694 # if we didn't find that device, check the existing config
695 # for a device in the same class
696 if not found:
697 for dev_type, dev_info in self.all_devices_sxpr():
698 if dev_type == cls:
699 sxpr.append(['device', dev_info])
701 return sxpr
703 def validate(self):
704 """ Validate the configuration and fill in missing configuration
705 with defaults.
706 """
708 # Fill in default values
709 for key, default_func in DEFAULT_CONFIGURATION:
710 if key not in self:
711 self[key] = default_func(self)
713 # Basic sanity checks
714 if 'image' in self and isinstance(self['image'], str):
715 self['image'] = sxp.from_string(self['image'])
716 if 'security' in self and isinstance(self['security'], str):
717 self['security'] = sxp.from_string(self['security'])
718 if self['memory'] == 0 and 'mem_kb' in self:
719 self['memory'] = (self['mem_kb'] + 1023)/1024
720 if self['memory'] <= 0:
721 raise XendConfigError('Invalid memory size: %s' %
722 str(self['memory']))
724 self['maxmem'] = max(self['memory'], self['maxmem'])
726 # Verify devices
727 for d_uuid, (d_type, d_info) in self['device'].items():
728 if d_type not in XendDevices.valid_devices():
729 raise XendConfigError('Invalid device (%s)' % d_type)
731 # Verify restart modes
732 for event in ('on_poweroff', 'on_reboot', 'on_crash'):
733 if self[event] not in CONFIG_RESTART_MODES:
734 raise XendConfigError('Invalid restart event: %s = %s' % \
735 (event, str(self[event])))
737 # Verify that {vif,vbd}_refs are here too
738 if 'vif_refs' not in self:
739 self['vif_refs'] = []
740 if 'vbd_refs' not in self:
741 self['vbd_refs'] = []
743 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
744 if dev_type not in XendDevices.valid_devices():
745 raise XendConfigError("XendConfig: %s not a valid device type" %
746 dev_type)
748 if cfg_sxp == None and cfg_xenapi == None:
749 raise XendConfigError("XendConfig: device_add requires some "
750 "config.")
752 if cfg_sxp:
753 log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
754 if cfg_xenapi:
755 log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
757 if cfg_sxp:
758 config = sxp.child0(cfg_sxp)
759 dev_type = sxp.name(config)
760 dev_info = {}
762 try:
763 for opt, val in config[1:]:
764 dev_info[opt] = val
765 except ValueError:
766 pass # SXP has no options for this device
768 # create uuid if it doesn't exist
769 dev_uuid = dev_info.get('uuid', uuid.createString())
770 dev_info['uuid'] = dev_uuid
771 self['device'][dev_uuid] = (dev_type, dev_info)
772 if dev_type in ('vif', 'vbd'):
773 self['%s_refs' % dev_type].append(dev_uuid)
774 elif dev_type in ('tap',):
775 self['vbd_refs'].append(dev_uuid)
776 return dev_uuid
778 if cfg_xenapi:
779 dev_info = {}
780 if dev_type == 'vif':
781 if cfg_xenapi.get('MAC'): # don't add if blank
782 dev_info['mac'] = cfg_xenapi.get('MAC')
783 # vifname is the name on the guest, not dom0
784 # TODO: we don't have the ability to find that out or
785 # change it from dom0
786 #if cfg_xenapi.get('device'): # don't add if blank
787 # dev_info['vifname'] = cfg_xenapi.get('device')
788 if cfg_xenapi.get('type'):
789 dev_info['type'] = cfg_xenapi.get('type')
791 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
792 dev_info['uuid'] = dev_uuid
793 self['device'][dev_uuid] = (dev_type, dev_info)
794 self['vif_refs'].append(dev_uuid)
795 return dev_uuid
797 elif dev_type == 'vbd':
798 dev_info['uname'] = cfg_xenapi.get('image', None)
799 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
800 if cfg_xenapi.get('mode') == 'RW':
801 dev_info['mode'] = 'w'
802 else:
803 dev_info['mode'] = 'r'
805 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
806 dev_info['uuid'] = dev_uuid
807 self['device'][dev_uuid] = (dev_type, dev_info)
808 self['vbd_refs'].append(dev_uuid)
809 return dev_uuid
811 elif dev_type == 'tap':
812 dev_info['uname'] = 'qcow:%s' % cfg_xenapi.get('image')
813 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
815 if cfg_xenapi.get('mode') == 'RW':
816 dev_info['mode'] = 'w'
817 else:
818 dev_info['mode'] = 'r'
820 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
821 dev_info['uuid'] = dev_uuid
822 self['device'][dev_uuid] = (dev_type, dev_info)
823 self['vbd_refs'].append(dev_uuid)
824 return dev_uuid
826 return ''
828 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
829 """Get Device SXPR by either giving the device UUID or (type, config).
831 @rtype: list of lists
832 @return: device config sxpr
833 """
834 sxpr = []
835 if dev_uuid != None and dev_uuid in self['device']:
836 dev_type, dev_info = self['device']
838 if dev_type == None or dev_info == None:
839 raise XendConfigError("Required either UUID or device type and "
840 "configuration dictionary.")
842 sxpr.append(dev_type)
843 config = [(opt, val) for opt, val in dev_info.items() \
844 if opt != 'type']
845 sxpr += config
847 return sxpr
849 def all_devices_sxpr(self):
850 sxprs = []
851 for dev_type, dev_info in self['device'].values():
852 sxpr = self.device_sxpr(dev_type = dev_type, dev_info = dev_info)
853 sxprs.append((dev_type, sxpr))
854 return sxprs
857 #
858 # debugging
859 #
861 if __name__ == "__main__":
862 pass