ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 12725:36fe7ca48e54

Tidy up the creation of directories that Xend needs. This avoids potential
races in this creation.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Fri Dec 01 11:32:32 2006 +0000 (2006-12-01)
parents 6cbe0449dc85
children d0ade847f886
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
20 import types
22 from xen.xend import sxp
23 from xen.xend import uuid
24 from xen.xend.XendError import VmError
25 from xen.xend.XendDevices import XendDevices
26 from xen.xend.XendLogging import log
27 from xen.xend.PrettyPrint import prettyprintstring
28 from xen.xend.XendConstants import DOM_STATE_HALTED
30 """
31 XendConfig API
33 XendConfig will try to mirror as closely the Xen API VM Struct
34 with extra parameters for those options that are not supported.
36 """
38 def reverse_dict(adict):
39 """Return the reverse mapping of a dictionary."""
40 return dict([(v, k) for k, v in adict.items()])
42 # Mapping from XendConfig configuration keys to the old
43 # legacy configuration keys that map directly.
45 XENAPI_CFG_TO_LEGACY_CFG = {
46 'uuid': 'uuid',
47 'vcpus_number': 'vcpus',
48 'memory_static_min': 'memory',
49 'memory_static_max': 'maxmem',
50 'name_label': 'name',
51 'actions_after_shutdown': 'on_poweroff',
52 'actions_after_reboot': 'on_reboot',
53 'actions_after_crash': 'on_crash',
54 'platform_localtime': 'localtime',
55 }
57 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
59 # Mapping from XendConfig configuration keys to the old
60 # legacy configuration keys that are found in the 'image'
61 # SXP object.
62 XENAPI_HVM_CFG = {
63 'platform_std_vga': 'std-vga',
64 'platform_serial' : 'serial',
65 'platform_localtime': 'localtime',
66 'platform_enable_audio': 'soundhw',
67 'platform_keymap' : 'keymap',
68 }
70 # List of XendConfig configuration keys that have no equivalent
71 # in the old world.
73 XENAPI_UNSUPPORTED_BY_LEGACY_CFG = [
74 'name_description',
75 'user_version',
76 'is_a_template',
77 'memory_dynamic_min',
78 'memory_dynamic_max',
79 'memory_actual',
80 'vcpus_policy',
81 'vcpus_params',
82 'vcpus_features_required',
83 'vcpus_features_can_use',
84 'vcpus_features_force_on',
85 'vcpus_features_force_off',
86 'actions_after_suspend',
87 'bios_boot',
88 'platform_std_vga',
89 'platform_serial',
90 'platform_localtime',
91 'platform_clock_offset',
92 'platform_enable_audio',
93 'platform_keymap',
94 'boot_method',
95 'builder',
96 'grub_cmdline',
97 'pci_bus',
98 'otherconfig'
99 ]
101 # List of legacy configuration keys that have no equivalent in the
102 # Xen API, but are still stored in XendConfig.
104 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
105 # roundtripped (dynamic, unmodified)
106 'shadow_memory',
107 'security',
108 'vcpu_avail',
109 'cpu_weight',
110 'cpu_cap',
111 'bootloader',
112 'bootloader_args',
113 'features',
114 # read/write
115 'on_xend_start',
116 'on_xend_stop',
117 # read-only
118 'domid',
119 'start_time',
120 'cpu_time',
121 'online_vcpus',
122 # write-once
123 'cpu',
124 'cpus',
125 ]
127 LEGACY_CFG_TYPES = {
128 'uuid': str,
129 'name': str,
130 'vcpus': int,
131 'vcpu_avail': int,
132 'memory': int,
133 'shadow_memory': int,
134 'maxmem': int,
135 'start_time': float,
136 'cpu_cap': int,
137 'cpu_weight': int,
138 'cpu_time': float,
139 'bootloader': str,
140 'bootloader_args': str,
141 'features': str,
142 'localtime': int,
143 'name': str,
144 'on_poweroff': str,
145 'on_reboot': str,
146 'on_crash': str,
147 'on_xend_stop': str,
148 'on_xend_start': str,
149 }
151 # Values that should be stored in xenstore's /vm/<uuid> that is used
152 # by Xend. Used in XendDomainInfo to restore running VM state from
153 # xenstore.
154 LEGACY_XENSTORE_VM_PARAMS = [
155 'uuid',
156 'name',
157 'vcpus',
158 'vcpu_avail',
159 'memory',
160 'shadow_memory',
161 'maxmem',
162 'start_time',
163 'name',
164 'on_poweroff',
165 'on_crash',
166 'on_reboot',
167 'on_xend_start',
168 'on_xend_stop',
169 ]
171 LEGACY_IMAGE_CFG = [
172 ('root', str),
173 ('ip', str),
174 ('nographic', int),
175 ('vnc', int),
176 ('sdl', int),
177 ('vncdisplay', int),
178 ('vncunused', int),
179 ]
181 LEGACY_IMAGE_HVM_CFG = [
182 ('device_model', str),
183 ('display', str),
184 ('xauthority', str),
185 ('vncconsole', int),
186 ('pae', int),
187 ('apic', int),
188 ]
190 LEGACY_IMAGE_HVM_DEVICES_CFG = [
191 ('acpi', int),
192 ('boot', str),
193 ('fda', str),
194 ('fdb', str),
195 ('isa', str),
196 ('keymap', str),
197 ('localtime', str),
198 ('serial', str),
199 ('stdvga', int),
200 ('soundhw', str),
201 ('usb', str),
202 ('usbdevice', str),
203 ('vcpus', int),
204 ]
208 # configuration params that need to be converted to ints
209 # since the XMLRPC transport for Xen API does not use
210 # 32 bit ints but string representation of 64 bit ints.
211 XENAPI_INT_CFG = [
212 'user_version',
213 'vcpus_number',
214 'memory_static_min',
215 'memory_static_max',
216 'memory_dynamic_min',
217 'memory_dynamic_max',
218 'memory_actual',
219 'tpm_instance',
220 'tpm_backend',
221 ]
223 ##
224 ## Config Choices
225 ##
227 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
228 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
229 'crashed', 'dying')
231 class XendConfigError(VmError):
232 def __str__(self):
233 return 'Invalid Configuration: %s' % str(self.value)
235 ##
236 ## XendConfig Class (an extended dictionary)
237 ##
239 class XendConfig(dict):
240 """ The new Xend VM Configuration.
242 Stores the configuration in xenapi compatible format but retains
243 import and export functions for SXP.
244 """
245 def __init__(self, filename = None, sxp_obj = None,
246 xapi = None, dominfo = None):
248 dict.__init__(self)
249 self.update(self._defaults())
251 if filename:
252 try:
253 sxp_obj = sxp.parse(open(filename,'r'))
254 sxp_obj = sxp_obj[0]
255 except IOError, e:
256 raise XendConfigError("Unable to read file: %s" % filename)
258 if sxp_obj:
259 self._sxp_to_xapi(sxp_obj)
260 self._sxp_to_xapi_unsupported(sxp_obj)
261 elif xapi:
262 self.update(xapi)
263 self._add_xapi_unsupported()
264 elif dominfo:
265 # output from xc.domain_getinfo
266 self._dominfo_to_xapi(dominfo)
268 log.debug('XendConfig.init: %s' % self)
270 # validators go here
271 self.validate()
273 def _defaults(self):
274 defaults = {
275 'uuid': uuid.createString(),
276 'name_label': 'Domain-Unnamed',
277 'actions_after_shutdown': 'destroy',
278 'actions_after_reboot': 'restart',
279 'actions_after_crash': 'restart',
280 'actions_after_suspend': '',
281 'features': '',
282 'builder': 'linux',
283 'memory_static_min': 0,
284 'memory_dynamic_min': 0,
285 'shadow_memory': 0,
286 'memory_static_max': 0,
287 'memory_dynamic_max': 0,
288 'memory_actual': 0,
289 'boot_method': None,
290 'bootloader': None,
291 'bootloader_args': None,
292 'devices': {},
293 'image': {},
294 'security': None,
295 'on_xend_start': 'ignore',
296 'on_xend_stop': 'ignore',
297 'cpus': [],
298 'cpu_weight': 256,
299 'cpu_cap': 0,
300 'vcpus_number': 1,
301 'online_vcpus': 1,
302 'max_vcpu_id': 0,
303 'vcpu_avail': 1,
304 'vif_refs': [],
305 'vbd_refs': [],
306 'vtpm_refs': [],
307 }
309 defaults['name_label'] = 'Domain-' + defaults['uuid']
310 return defaults
312 def _memory_sanity_check(self):
313 if self['memory_static_min'] == 0:
314 self['memory_static_min'] = self['memory_dynamic_min']
316 # If the static max is not set, let's set it to dynamic max.
317 # If the static max is smaller than static min, then fix it!
318 self['memory_static_max'] = max(self['memory_static_max'],
319 self['memory_dynamic_max'],
320 self['memory_static_min'])
322 for mem_type in ('memory_static_min', 'memory_static_max'):
323 if self[mem_type] <= 0:
324 raise XendConfigError('Memory value too low for %s: %d' %
325 (mem_type, self[mem_type]))
327 def _actions_sanity_check(self):
328 for event in ['shutdown', 'reboot', 'crash']:
329 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
330 raise XendConfigError('Invalid event handling mode: ' +
331 event)
333 def _builder_sanity_check(self):
334 if self['builder'] not in ('hvm', 'linux'):
335 raise XendConfigError('Invalid builder configuration')
337 def validate(self):
338 self._memory_sanity_check()
339 self._actions_sanity_check()
340 self._builder_sanity_check()
342 def _dominfo_to_xapi(self, dominfo):
343 self['domid'] = dominfo['domid']
344 self['online_vcpus'] = dominfo['online_vcpus']
345 self['max_vcpu_id'] = dominfo['max_vcpu_id']
346 self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
347 self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
348 self['cpu_time'] = dominfo['cpu_time']/1e9
349 # TODO: i don't know what the security stuff expects here
350 if dominfo.get('ssidref'):
351 self['security'] = [['ssidref', dominfo['ssidref']]]
352 self['shutdown_reason'] = dominfo['shutdown_reason']
354 # parse state into Xen API states
355 self['running'] = dominfo['running']
356 self['crashed'] = dominfo['crashed']
357 self['dying'] = dominfo['dying']
358 self['shutdown'] = dominfo['shutdown']
359 self['paused'] = dominfo['paused']
360 self['blocked'] = dominfo['blocked']
362 if 'name' in dominfo:
363 self['name_label'] = dominfo['name']
365 if 'handle' in dominfo:
366 self['uuid'] = uuid.toString(dominfo['handle'])
368 def _parse_sxp(self, sxp_cfg):
369 """ Populate this XendConfig using the parsed SXP.
371 @param sxp_cfg: Parsed SXP Configuration
372 @type sxp_cfg: list of lists
373 @rtype: dictionary
374 @return: A dictionary containing the parsed options of the SXP.
375 """
376 cfg = {}
378 # First step is to convert deprecated options to
379 # current equivalents.
381 restart = sxp.child_value(sxp_cfg, 'restart')
382 if restart:
383 if restart == 'onreboot':
384 cfg['on_poweroff'] = 'destroy'
385 cfg['on_reboot'] = 'restart'
386 cfg['on_crash'] = 'destroy'
387 elif restart == 'always':
388 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
389 cfg[opt] = 'restart'
390 elif restart == 'never':
391 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
392 cfg[opt] = 'never'
393 else:
394 log.warn('Ignoring unrecognised value for deprecated option:'
395 'restart = \'%s\'', restart)
397 # Only extract options we know about.
398 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
399 extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
401 for key in extract_keys:
402 val = sxp.child_value(sxp_cfg, key)
403 if val != None:
404 try:
405 cfg[key] = LEGACY_CFG_TYPES[key](val)
406 except KeyError:
407 cfg[key] = val
408 except (TypeError, ValueError), e:
409 log.warn("Unable to parse key %s: %s: %s" %
410 (key, str(val), e))
412 # Parsing the device SXP's. In most cases, the SXP looks
413 # like this:
414 #
415 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
416 #
417 # However, for PCI devices it looks like this:
418 #
419 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
420 #
421 # It seems the reasoning for this difference is because
422 # pciif.py needs all the PCI device configurations at
423 # the same time when creating the devices.
424 #
425 # To further complicate matters, Xen 2.0 configuration format
426 # uses the following for pci device configuration:
427 #
428 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
429 #
430 # Hence we deal with pci device configurations outside of
431 # the regular device parsing.
433 cfg['devices'] = {}
434 for dev in sxp.children(sxp_cfg, 'device'):
435 config = sxp.child0(dev)
436 dev_type = sxp.name(config)
437 dev_info = {}
439 if dev_type == 'pci':
440 pci_devs_uuid = sxp.child_value(config, 'uuid',
441 uuid.createString())
442 pci_devs = []
443 for pci_dev in sxp.children(config, 'dev'):
444 pci_dev_info = {}
445 for opt, val in pci_dev[1:]:
446 pci_dev_info[opt] = val
447 pci_devs.append(pci_dev_info)
449 cfg['devices'][pci_devs_uuid] = (dev_type,
450 {'devs': pci_devs,
451 'uuid': pci_devs_uuid})
453 log.debug("XendConfig: reading device: %s" % pci_devs)
454 else:
455 for opt, val in config[1:]:
456 dev_info[opt] = val
457 log.debug("XendConfig: reading device: %s" % dev_info)
458 # create uuid if it doesn't
459 dev_uuid = dev_info.get('uuid', uuid.createString())
460 dev_info['uuid'] = dev_uuid
461 cfg['devices'][dev_uuid] = (dev_type, dev_info)
464 # Extract missing data from configuration entries
465 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
466 if image_sxp:
467 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
468 if image_vcpus != None:
469 try:
470 if 'vcpus_number' not in cfg:
471 cfg['vcpus_number'] = int(image_vcpus)
472 elif cfg['vcpus_number'] != int(image_vcpus):
473 cfg['vcpus_number'] = int(image_vcpus)
474 log.warn('Overriding vcpus from %d to %d using image'
475 'vcpus value.', cfg['vcpus_number'])
476 except ValueError, e:
477 raise XendConfigError('integer expeceted: %s: %s' %
478 image_sxp, e)
480 # Deprecated cpu configuration
481 if 'cpu' in cfg:
482 if 'cpus' in cfg:
483 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
484 else:
485 cfg['cpus'] = str(cfg['cpu'])
487 # convert 'cpus' string to list of ints
488 # 'cpus' supports a list of ranges (0-3), seperated by
489 # commas, and negation, (^1).
490 # Precedence is settled by order of the string:
491 # "0-3,^1" -> [0,2,3]
492 # "0-3,^1,1" -> [0,1,2,3]
493 try:
494 if 'cpus' in cfg:
495 cpus = []
496 for c in cfg['cpus'].split(','):
497 if c.find('-') != -1:
498 (x, y) = c.split('-')
499 for i in range(int(x), int(y)+1):
500 cpus.append(int(i))
501 else:
502 # remove this element from the list
503 if c[0] == '^':
504 cpus = [x for x in cpus if x != int(c[1:])]
505 else:
506 cpus.append(int(c))
508 cfg['cpus'] = cpus
509 except ValueError, e:
510 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
512 if 'security' in cfg and isinstance(cfg['security'], str):
513 cfg['security'] = sxp.from_string(cfg['security'])
515 # TODO: get states
516 old_state = sxp.child_value(sxp_cfg, 'state')
517 if old_state:
518 for i in range(len(CONFIG_OLD_DOM_STATES)):
519 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
521 return cfg
524 def _sxp_to_xapi(self, sxp_cfg):
525 """Read in an SXP Configuration object and
526 populate at much of the Xen API with valid values.
527 """
528 cfg = self._parse_sxp(sxp_cfg)
530 # Convert parameters that can be directly mapped from
531 # the Legacy Config to Xen API Config
533 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
534 try:
535 self[apikey] = LEGACY_CFG_TYPES[cfgkey](cfg[cfgkey])
536 except KeyError:
537 pass
539 # Convert Legacy "image" config to Xen API kernel_*
540 # configuration
541 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
542 if image_sxp:
543 self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','')
544 self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','')
545 kernel_args = sxp.child_value(image_sxp, 'args', '')
547 # attempt to extract extra arguments from SXP config
548 arg_ip = sxp.child_value(image_sxp, 'ip')
549 if arg_ip and not re.search(r'ip=[0-9\.]+', kernel_args):
550 kernel_args += ' ip=%s' % arg_ip
551 arg_root = sxp.child_value(image_sxp, 'root')
552 if arg_root and not re.search(r'root=[^ ]+', kernel_args):
553 kernel_args += ' root=%s' % arg_root
555 self['kernel_args'] = kernel_args
557 # Convert Legacy HVM parameters to Xen API configuration
558 self['platform_std_vga'] = cfg.get('std-vga', 0)
559 self['platform_serial'] = cfg.get('serial', '')
560 self['platform_localtime'] = cfg.get('localtime', 0)
561 self['platform_enable_audio'] = cfg.get('soundhw', 0)
563 # Convert path to bootloader to boot_method
564 if not cfg.get('bootloader'):
565 if self.get('kernel_kernel','').endswith('hvmloader'):
566 self['boot_method'] = 'bios'
567 else:
568 self['boot_method'] = 'kernel_external'
569 else:
570 self['boot_method'] = 'grub'
572 # make sure a sane maximum is set
573 if self['memory_static_max'] <= 0:
574 self['memory_static_max'] = self['memory_static_min']
576 self['memory_dynamic_max'] = self['memory_static_max']
577 self['memory_dynamic_min'] = self['memory_static_min']
579 # set device references in the configuration
580 self['devices'] = cfg.get('devices', {})
582 self['vif_refs'] = []
583 self['vbd_refs'] = []
584 self['vtpm_refs'] = []
585 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
586 if dev_type == 'vif':
587 self['vif_refs'].append(dev_uuid)
588 elif dev_type in ('vbd','tap'):
589 self['vbd_refs'].append(dev_uuid)
590 elif dev_type in ('vtpm',):
591 self['vtpm_refs'].append(dev_uuid)
594 def _sxp_to_xapi_unsupported(self, sxp_cfg):
595 """Read in an SXP configuration object and populate
596 values are that not related directly supported in
597 the Xen API.
598 """
600 # Parse and convert parameters used to configure
601 # the image (as well as HVM images)
602 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
603 if image_sxp:
604 image = {}
605 image['type'] = sxp.name(image_sxp)
606 for arg, conv in LEGACY_IMAGE_CFG:
607 val = sxp.child_value(image_sxp, arg, None)
608 if val != None:
609 image[arg] = conv(val)
611 image_hvm = {}
612 for arg, conv in LEGACY_IMAGE_HVM_CFG:
613 val = sxp.child_value(image_sxp, arg, None)
614 if val != None:
615 image_hvm[arg] = conv(val)
617 image_hvm_devices = {}
618 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
619 val = sxp.child_value(image_sxp, arg, None)
620 if val != None:
621 image_hvm_devices[arg] = conv(val)
623 if image_hvm or image_hvm_devices:
624 image['hvm'] = image_hvm
625 image['hvm']['devices'] = image_hvm_devices
627 self['image'] = image
629 for apikey, imgkey in XENAPI_HVM_CFG.items():
630 val = sxp.child_value(image_sxp, imgkey, None)
631 if val != None:
632 self[apikey] = val
634 # extract backend value
636 backend = []
637 for c in sxp.children(sxp_cfg, 'backend'):
638 backend.append(sxp.name(sxp.child0(c)))
639 if backend:
640 self['backend'] = backend
642 if self['image'].has_key('hvm'):
643 self['builder'] = 'hvm'
645 # Parse and convert other Non Xen API parameters.
646 def _set_cfg_if_exists(sxp_arg):
647 val = sxp.child_value(sxp_cfg, sxp_arg)
648 if val != None:
649 if LEGACY_CFG_TYPES.get(sxp_arg):
650 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
651 else:
652 self[sxp_arg] = val
654 _set_cfg_if_exists('shadow_memory')
655 _set_cfg_if_exists('security')
656 _set_cfg_if_exists('features')
657 _set_cfg_if_exists('on_xend_stop')
658 _set_cfg_if_exists('on_xend_start')
659 _set_cfg_if_exists('vcpu_avail')
660 _set_cfg_if_exists('max_vcpu_id') # TODO, deprecated?
662 # Parse and store runtime configuration
663 _set_cfg_if_exists('start_time')
664 _set_cfg_if_exists('online_vcpus')
665 _set_cfg_if_exists('cpu_time')
666 _set_cfg_if_exists('shutdown_reason')
667 _set_cfg_if_exists('up_time')
668 _set_cfg_if_exists('status') # TODO, deprecated
670 def _add_xapi_unsupported(self):
671 """Updates the configuration object with entries that are not
672 officially supported by the Xen API but is required for
673 the rest of Xend to function.
674 """
676 # populate image
677 self['image']['type'] = self['builder']
678 if self['builder'] == 'hvm':
679 self['image']['hvm'] = {}
680 for xapi, cfgapi in XENAPI_HVM_CFG.items():
681 self['image']['hvm'][cfgapi] = self[xapi]
684 def _get_old_state_string(self):
685 """Returns the old xm state string.
686 @rtype: string
687 @return: old state string
688 """
689 state_string = ''
690 for state_name in CONFIG_OLD_DOM_STATES:
691 on_off = self.get(state_name, 0)
692 if on_off:
693 state_string += state_name[0]
694 else:
695 state_string += '-'
697 return state_string
700 def update_config(self, dominfo):
701 """Update configuration with the output from xc.domain_getinfo().
703 @param dominfo: Domain information via xc.domain_getinfo()
704 @type dominfo: dict
705 """
706 self._dominfo_to_xapi(dominfo)
707 self.validate()
709 def to_xml(self):
710 """Return an XML string representing the configuration."""
711 pass
713 def to_sxp(self, domain = None, ignore_devices = False, ignore = []):
714 """ Get SXP representation of this config object.
716 Incompat: removed store_mfn, console_mfn
718 @keyword domain: (optional) XendDomainInfo to get extra information
719 from such as domid and running devices.
720 @type domain: XendDomainInfo
721 @keyword ignore: (optional) list of 'keys' that we do not want
722 to export.
723 @type ignore: list of strings
724 @rtype: list of list (SXP representation)
725 """
726 sxpr = ['domain']
728 # TODO: domid/dom is the same thing but called differently
729 # depending if it is from xenstore or sxpr.
731 if domain.getDomid() is not None:
732 sxpr.append(['domid', domain.getDomid()])
734 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
735 if self.has_key(xenapi) and self[xenapi] not in (None, []):
736 sxpr.append([legacy, self[xenapi]])
738 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
739 if legacy in ('domid', 'uuid'): # skip these
740 continue
741 if self.has_key(legacy) and self[legacy] not in (None, []):
742 sxpr.append([legacy, self[legacy]])
744 if 'image' in self and self['image']:
745 sxpr.append(['image', self.image_sxpr()])
747 sxpr.append(['status', domain.state])
748 sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
749 sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
751 if domain.getDomid() is not None:
752 sxpr.append(['state', self._get_old_state_string()])
754 if domain:
755 if domain.store_mfn:
756 sxpr.append(['store_mfn', domain.store_mfn])
757 if domain.console_mfn:
758 sxpr.append(['console_mfn', domain.console_mfn])
761 # Marshall devices (running or from configuration)
762 if not ignore_devices:
763 for cls in XendDevices.valid_devices():
764 found = False
766 # figure if there is a device that is running
767 if domain:
768 try:
769 controller = domain.getDeviceController(cls)
770 configs = controller.configurations()
771 for config in configs:
772 sxpr.append(['device', config])
773 found = True
774 except:
775 log.exception("dumping sxp from device controllers")
776 pass
778 # if we didn't find that device, check the existing config
779 # for a device in the same class
780 if not found:
781 for dev_type, dev_info in self.all_devices_sxpr():
782 if dev_type == cls:
783 sxpr.append(['device', dev_info])
785 return sxpr
787 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
788 """Add a device configuration in SXP format or XenAPI struct format.
790 For SXP, it could be either:
792 [device, [vbd, [uname ...]]
794 or:
796 [vbd, [uname ..]]
798 @type cfg_sxp: list of lists (parsed sxp object)
799 @param cfg_sxp: SXP configuration object
800 @type cfg_xenapi: dict
801 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
802 @rtype: string
803 @return: Assigned UUID of the device.
804 """
805 if dev_type not in XendDevices.valid_devices() and \
806 dev_type not in XendDevices.pseudo_devices():
807 raise XendConfigError("XendConfig: %s not a valid device type" %
808 dev_type)
810 if cfg_sxp == None and cfg_xenapi == None:
811 raise XendConfigError("XendConfig: device_add requires some "
812 "config.")
814 if cfg_sxp:
815 log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
816 if cfg_xenapi:
817 log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
819 if cfg_sxp:
820 if sxp.child0(cfg_sxp) == 'device':
821 config = sxp.child0(cfg_sxp)
822 else:
823 config = cfg_sxp
825 dev_type = sxp.name(config)
826 dev_info = {}
828 try:
829 for opt, val in config[1:]:
830 dev_info[opt] = val
831 except ValueError:
832 pass # SXP has no options for this device
835 def _get_config_ipaddr(config):
836 val = []
837 for ipaddr in sxp.children(config, elt='ip'):
838 val.append(sxp.child0(ipaddr))
839 return val
841 if dev_type == 'vif' and 'ip' in dev_info:
842 dev_info['ip'] = _get_config_ipaddr(config)
844 if dev_type == 'vbd':
845 if dev_info.get('dev', '').startswith('ioemu:'):
846 dev_info['driver'] = 'ioemu'
847 else:
848 dev_info['driver'] = 'paravirtualised'
851 # create uuid if it doesn't exist
852 dev_uuid = dev_info.get('uuid', uuid.createString())
853 dev_info['uuid'] = dev_uuid
855 # store dev references by uuid for certain device types
856 self['devices'][dev_uuid] = (dev_type, dev_info)
857 if dev_type in ('vif', 'vbd', 'vtpm'):
858 self['%s_refs' % dev_type].append(dev_uuid)
859 elif dev_type in ('tap',):
860 self['vbd_refs'].append(dev_uuid)
862 return dev_uuid
864 if cfg_xenapi:
865 dev_info = {}
866 if dev_type == 'vif':
867 if cfg_xenapi.get('MAC'): # don't add if blank
868 dev_info['mac'] = cfg_xenapi.get('MAC')
869 # vifname is the name on the guest, not dom0
870 # TODO: we don't have the ability to find that out or
871 # change it from dom0
872 #if cfg_xenapi.get('device'): # don't add if blank
873 # dev_info['vifname'] = cfg_xenapi.get('device')
874 if cfg_xenapi.get('type'):
875 dev_info['type'] = cfg_xenapi.get('type')
877 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
878 dev_info['uuid'] = dev_uuid
879 self['devices'][dev_uuid] = (dev_type, dev_info)
880 self['vif_refs'].append(dev_uuid)
881 return dev_uuid
883 elif dev_type in ('vbd', 'tap'):
884 if dev_type == 'vbd':
885 dev_info['uname'] = cfg_xenapi.get('image', '')
886 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
887 elif dev_type == 'tap':
888 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
889 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
891 dev_info['driver'] = cfg_xenapi.get('driver')
892 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
894 if cfg_xenapi.get('mode') == 'RW':
895 dev_info['mode'] = 'w'
896 else:
897 dev_info['mode'] = 'r'
899 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
900 dev_info['uuid'] = dev_uuid
901 self['devices'][dev_uuid] = (dev_type, dev_info)
902 self['vbd_refs'].append(dev_uuid)
903 return dev_uuid
905 return ''
907 def device_update(self, dev_uuid, cfg_sxp):
908 """Update an existing device with the new configuration.
910 @rtype: boolean
911 @return: Returns True if succesfully found and updated a device conf
912 """
913 if dev_uuid in self['devices']:
914 config = sxp.child0(cfg_sxp)
915 dev_type = sxp.name(config)
916 dev_info = {}
918 try:
919 for opt, val in config[1:]:
920 self['devices'][opt] = val
921 except ValueError:
922 pass # SXP has no options for this device
924 return True
926 return False
929 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
930 """Get Device SXPR by either giving the device UUID or (type, config).
932 @rtype: list of lists
933 @return: device config sxpr
934 """
935 sxpr = []
936 if dev_uuid != None and dev_uuid in self['devices']:
937 dev_type, dev_info = self['devices'][dev_uuid]
939 if dev_type == None or dev_info == None:
940 raise XendConfigError("Required either UUID or device type and "
941 "configuration dictionary.")
943 sxpr.append(dev_type)
944 config = [(opt, val) for opt, val in dev_info.items()]
945 sxpr += config
947 return sxpr
949 def all_devices_sxpr(self):
950 """Returns the SXPR for all devices in the current configuration."""
951 sxprs = []
952 pci_devs = []
954 if 'devices' in self:
955 return sxprs
957 for dev_type, dev_info in self['devices'].values():
958 if dev_type == 'pci': # special case for pci devices
959 sxpr = [['uuid', dev_info['uuid']]]
960 for pci_dev_info in dev_info['devs']:
961 pci_dev_sxpr = ['dev']
962 for opt, val in pci_dev_info.items():
963 pci_dev_sxpr.append([opt, val])
964 sxpr.append(pci_dev_sxpr)
965 sxprs.append((dev_type, sxpr))
966 else:
967 sxpr = self.device_sxpr(dev_type = dev_type,
968 dev_info = dev_info)
969 sxprs.append((dev_type, sxpr))
971 return sxprs
973 def image_sxpr(self):
974 """Returns a backwards compatible image SXP expression that is
975 used in xenstore's /vm/<uuid>/image value and xm list."""
976 image = [self['image'].get('type', 'linux')]
977 if self.has_key('kernel_kernel'):
978 image.append(['kernel', self['kernel_kernel']])
979 if self.has_key('kernel_initrd') and self['kernel_initrd']:
980 image.append(['ramdisk', self['kernel_initrd']])
981 if self.has_key('kernel_args') and self['kernel_args']:
982 image.append(['args', self['kernel_args']])
984 for arg, conv in LEGACY_IMAGE_CFG:
985 if self['image'].has_key(arg):
986 image.append([arg, self['image'][arg]])
988 if 'hvm' in self['image']:
989 for arg, conv in LEGACY_IMAGE_HVM_CFG:
990 if self['image']['hvm'].get(arg):
991 image.append([arg, self['image']['hvm'][arg]])
993 if 'hvm' in self['image'] and 'devices' in self['image']['hvm']:
994 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
995 if self['image']['hvm']['devices'].get(arg):
996 image.append([arg,
997 self['image']['hvm']['devices'][arg]])
999 return image
1001 def update_with_image_sxp(self, image_sxp):
1002 # Convert Legacy "image" config to Xen API kernel_*
1003 # configuration
1004 self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1005 self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','')
1006 kernel_args = sxp.child_value(image_sxp, 'args', '')
1008 # attempt to extract extra arguments from SXP config
1009 arg_ip = sxp.child_value(image_sxp, 'ip')
1010 if arg_ip and not re.search(r'ip=[0-9\.]', kernel_args):
1011 kernel_args += ' ip=%s' % arg_ip
1012 arg_root = sxp.child_value(image_sxp, 'root')
1013 if arg_root and not re.search(r'root=', kernel_args):
1014 kernel_args += ' root=%s' % arg_root
1015 self['kernel_args'] = kernel_args
1017 # Store image SXP in python dictionary format
1018 image = {}
1019 image['type'] = sxp.name(image_sxp)
1020 for arg, conv in LEGACY_IMAGE_CFG:
1021 val = sxp.child_value(image_sxp, arg, None)
1022 if val != None:
1023 image[arg] = conv(val)
1025 image_hvm = {}
1026 for arg, conv in LEGACY_IMAGE_HVM_CFG:
1027 val = sxp.child_value(image_sxp, arg, None)
1028 if val != None:
1029 image_hvm[arg] = conv(val)
1031 image_hvm_devices = {}
1032 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
1033 val = sxp.child_value(image_sxp, arg, None)
1034 if val != None:
1035 image_hvm_devices[arg] = conv(val)
1037 if image_hvm or image_hvm_devices:
1038 image['hvm'] = image_hvm
1039 image['hvm']['devices'] = image_hvm_devices
1041 self['image'] = image
1043 for apikey, imgkey in XENAPI_HVM_CFG.items():
1044 val = sxp.child_value(image_sxp, imgkey, None)
1045 if val != None:
1046 self[apikey] = val
1050 # debugging
1053 if __name__ == "__main__":
1054 pass