ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 13821:23bf61e72279

Clean up some cruft.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Thu Feb 01 18:45:50 2007 +0000 (2007-02-01)
parents e0b7ab2a1d56
children 5c6f94192698
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 logging
19 import re
20 import time
21 import types
23 from xen.xend import sxp
24 from xen.xend import uuid
25 from xen.xend.XendError import VmError
26 from xen.xend.XendDevices import XendDevices
27 from xen.xend.PrettyPrint import prettyprintstring
28 from xen.xend.XendConstants import DOM_STATE_HALTED
30 log = logging.getLogger("xend.XendConfig")
31 log.setLevel(logging.DEBUG)
34 """
35 XendConfig API
37 XendConfig will try to mirror as closely the Xen API VM Struct
38 with extra parameters for those options that are not supported.
40 """
42 def reverse_dict(adict):
43 """Return the reverse mapping of a dictionary."""
44 return dict([(v, k) for k, v in adict.items()])
46 def bool0(v):
47 return v != '0' and bool(v)
49 # Recursively copy a data struct, scrubbing out VNC passwords.
50 # Will scrub any dict entry with a key of 'vncpasswd' or any
51 # 2-element list whose first member is 'vncpasswd'. It will
52 # also scrub a string matching '(vncpasswd XYZ)'. Everything
53 # else is no-op passthrough
54 def scrub_password(data):
55 if type(data) == dict or type(data) == XendConfig:
56 scrubbed = {}
57 for key in data.keys():
58 if key == "vncpasswd":
59 scrubbed[key] = "XXXXXXXX"
60 else:
61 scrubbed[key] = scrub_password(data[key])
62 return scrubbed
63 elif type(data) == list:
64 if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd':
65 return ['vncpasswd', 'XXXXXXXX']
66 else:
67 scrubbed = []
68 for entry in data:
69 scrubbed.append(scrub_password(entry))
70 return scrubbed
71 elif type(data) == tuple:
72 scrubbed = []
73 for entry in data:
74 scrubbed.append(scrub_password(entry))
75 return tuple(scrubbed)
76 elif type(data) == str:
77 return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data)
78 else:
79 return data
81 #
82 # CPU fields:
83 #
84 # vcpus_number -- the maximum number of vcpus that this domain may ever have.
85 # aka XendDomainInfo.getVCpuCount().
86 # vcpus -- the legacy configuration name for above.
87 # max_vcpu_id -- vcpus_number - 1. This is given to us by Xen.
88 #
89 # cpus -- the list of pCPUs available to each vCPU.
90 #
91 # vcpu_avail: a bitmap telling the guest domain whether it may use each of
92 # its VCPUs. This is translated to
93 # <dompath>/cpu/<id>/availability = {online,offline} for use
94 # by the guest domain.
95 # online_vpcus -- the number of VCPUs currently up, as reported by Xen. This
96 # is changed by changing vcpu_avail, and waiting for the
97 # domain to respond.
98 #
101 # Mapping from XendConfig configuration keys to the old
102 # legacy configuration keys that map directly.
104 XENAPI_CFG_TO_LEGACY_CFG = {
105 'uuid': 'uuid',
106 'vcpus_number': 'vcpus',
107 'cpus': 'cpus',
108 'memory_static_min': 'memory',
109 'memory_static_max': 'maxmem',
110 'name_label': 'name',
111 'actions_after_shutdown': 'on_poweroff',
112 'actions_after_reboot': 'on_reboot',
113 'actions_after_crash': 'on_crash',
114 'platform_localtime': 'localtime',
115 'PV_bootloader': 'bootloader',
116 'PV_bootloader_args': 'bootloader_args',
117 }
119 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
121 # Mapping from XendConfig configuration keys to the old
122 # legacy configuration keys that are found in the 'image'
123 # SXP object.
124 XENAPI_HVM_CFG = {
125 'platform_std_vga': 'stdvga',
126 'platform_serial' : 'serial',
127 'platform_localtime': 'localtime',
128 'platform_keymap' : 'keymap'
129 }
131 # List of XendConfig configuration keys that have no direct equivalent
132 # in the old world.
134 XENAPI_CFG_TYPES = {
135 'uuid': str,
136 'power_state': str,
137 'name_label': str,
138 'name_description': str,
139 'user_version': str,
140 'is_a_template': bool0,
141 'resident_on': str,
142 'memory_static_min': int,
143 'memory_static_max': int,
144 'memory_dynamic_min': int,
145 'memory_dynamic_max': int,
146 'memory_actual': int,
147 'cpus': list,
148 'vcpus_policy': str,
149 'vcpus_params': dict,
150 'vcpus_number': int,
151 'actions_after_shutdown': str,
152 'actions_after_reboot': str,
153 'actions_after_crash': str,
154 'tpm_backend': int,
155 'PV_bootloader': str,
156 'PV_kernel': str,
157 'PV_ramdisk': str,
158 'PV_args': str,
159 'PV_bootloader_args': str,
160 'HVM_boot_policy': str,
161 'HVM_boot_params': dict,
162 'platform_std_vga': bool0,
163 'platform_serial': str,
164 'platform_localtime': bool0,
165 'platform_clock_offset': bool0,
166 'platform_enable_audio': bool0,
167 'platform_keymap': str,
168 'pci_bus': str,
169 'tools_version': dict,
170 'otherconfig': dict,
171 }
173 # List of legacy configuration keys that have no equivalent in the
174 # Xen API, but are still stored in XendConfig.
176 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
177 # roundtripped (dynamic, unmodified)
178 'shadow_memory',
179 'security',
180 'vcpu_avail',
181 'cpu_weight',
182 'cpu_cap',
183 'features',
184 # read/write
185 'on_xend_start',
186 'on_xend_stop',
187 # read-only
188 'domid',
189 'start_time',
190 'cpu_time',
191 'online_vcpus',
192 # write-once
193 'cpu',
194 'cpus',
195 ]
197 LEGACY_CFG_TYPES = {
198 'uuid': str,
199 'name': str,
200 'vcpus': int,
201 'vcpu_avail': long,
202 'memory': int,
203 'shadow_memory': int,
204 'maxmem': int,
205 'start_time': float,
206 'cpu_cap': int,
207 'cpu_weight': int,
208 'cpu_time': float,
209 'features': str,
210 'localtime': int,
211 'name': str,
212 'on_poweroff': str,
213 'on_reboot': str,
214 'on_crash': str,
215 'on_xend_stop': str,
216 'on_xend_start': str,
217 'online_vcpus': int,
218 }
220 # Values that should be stored in xenstore's /vm/<uuid> that is used
221 # by Xend. Used in XendDomainInfo to restore running VM state from
222 # xenstore.
223 LEGACY_XENSTORE_VM_PARAMS = [
224 'uuid',
225 'name',
226 'vcpus',
227 'vcpu_avail',
228 'memory',
229 'shadow_memory',
230 'maxmem',
231 'start_time',
232 'name',
233 'on_poweroff',
234 'on_crash',
235 'on_reboot',
236 'on_xend_start',
237 'on_xend_stop',
238 ]
240 LEGACY_IMAGE_CFG = [
241 ('root', str),
242 ('ip', str),
243 ('nographic', int),
244 ('vnc', int),
245 ('sdl', int),
246 ('vncdisplay', int),
247 ('vncunused', int),
248 ('vncpasswd', str),
249 ('vnclisten', str),
250 ]
252 LEGACY_IMAGE_HVM_CFG = [
253 ('device_model', str),
254 ('display', str),
255 ('xauthority', str),
256 ('vncconsole', int),
257 ('pae', int),
258 ('apic', int),
259 ]
261 LEGACY_IMAGE_HVM_DEVICES_CFG = [
262 ('acpi', int),
263 ('boot', str),
264 ('fda', str),
265 ('fdb', str),
266 ('isa', int),
267 ('keymap', str),
268 ('localtime', int),
269 ('serial', str),
270 ('stdvga', int),
271 ('soundhw', str),
272 ('usb', int),
273 ('usbdevice', str),
274 ('vcpus', int),
275 ]
277 LEGACY_DM = '/usr/lib/xen/bin/qemu-dm'
279 ##
280 ## Config Choices
281 ##
283 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
284 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
285 'crashed', 'dying')
287 class XendConfigError(VmError):
288 def __str__(self):
289 return 'Invalid Configuration: %s' % str(self.value)
291 ##
292 ## XendConfig Class (an extended dictionary)
293 ##
295 class XendConfig(dict):
296 """ The new Xend VM Configuration.
298 Stores the configuration in xenapi compatible format but retains
299 import and export functions for SXP.
300 """
301 def __init__(self, filename = None, sxp_obj = None,
302 xapi = None, dominfo = None):
304 dict.__init__(self)
305 self.update(self._defaults())
307 if filename:
308 try:
309 sxp_obj = sxp.parse(open(filename,'r'))
310 sxp_obj = sxp_obj[0]
311 except IOError, e:
312 raise XendConfigError("Unable to read file: %s" % filename)
314 if sxp_obj:
315 self._sxp_to_xapi(sxp_obj)
316 self._sxp_to_xapi_unsupported(sxp_obj)
317 elif xapi:
318 self.update_with_xenapi_config(xapi)
319 self._add_xapi_unsupported(xapi)
320 elif dominfo:
321 # output from xc.domain_getinfo
322 self._dominfo_to_xapi(dominfo)
324 log.debug('XendConfig.init: %s' % scrub_password(self))
326 # validators go here
327 self.validate()
329 """ In time, we should enable this type checking addition. It is great
330 also for tracking bugs and unintended writes to XendDomainInfo.info
331 def __setitem__(self, key, value):
332 type_conv = XENAPI_CFG_TYPES.get(key)
333 if callable(type_conv):
334 try:
335 dict.__setitem__(self, key, type_conv(value))
336 except (ValueError, TypeError):
337 raise XendConfigError("Wrong type for configuration value " +
338 "%s. Expected %s" %
339 (key, type_conv.__name__))
340 else:
341 dict.__setitem__(self, key, value)
342 """
344 def _defaults(self):
345 defaults = {
346 'name_label': 'Domain-Unnamed',
347 'actions_after_shutdown': 'destroy',
348 'actions_after_reboot': 'restart',
349 'actions_after_crash': 'restart',
350 'actions_after_suspend': '',
351 'features': '',
352 'PV_bootloader': '',
353 'PV_kernel': '',
354 'PV_ramdisk': '',
355 'PV_args': '',
356 'PV_bootloader_args': '',
357 'HVM_boot_policy': '',
358 'HVM_boot_params': {},
359 'memory_static_min': 0,
360 'memory_dynamic_min': 0,
361 'shadow_memory': 0,
362 'memory_static_max': 0,
363 'memory_dynamic_max': 0,
364 'memory_actual': 0,
365 'devices': {},
366 'image': {},
367 'security': None,
368 'on_xend_start': 'ignore',
369 'on_xend_stop': 'ignore',
370 'cpus': [],
371 'cpu_weight': 256,
372 'cpu_cap': 0,
373 'vcpus_number': 1,
374 'console_refs': [],
375 'vif_refs': [],
376 'vbd_refs': [],
377 'vtpm_refs': [],
378 'other_config': {},
379 }
381 return defaults
383 def _memory_sanity_check(self):
384 if self['memory_static_min'] == 0:
385 self['memory_static_min'] = self['memory_dynamic_min']
387 # If the static max is not set, let's set it to dynamic max.
388 # If the static max is smaller than static min, then fix it!
389 self['memory_static_max'] = max(self['memory_static_max'],
390 self['memory_dynamic_max'],
391 self['memory_static_min'])
393 for mem_type in ('memory_static_min', 'memory_static_max'):
394 if self[mem_type] <= 0:
395 raise XendConfigError('Memory value too low for %s: %d' %
396 (mem_type, self[mem_type]))
398 def _actions_sanity_check(self):
399 for event in ['shutdown', 'reboot', 'crash']:
400 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
401 raise XendConfigError('Invalid event handling mode: ' +
402 event)
404 def _vcpus_sanity_check(self):
405 if 'vcpus_number' in self and 'vcpu_avail' not in self:
406 self['vcpu_avail'] = (1 << self['vcpus_number']) - 1
408 def _uuid_sanity_check(self):
409 """Make sure UUID is in proper string format with hyphens."""
410 if 'uuid' not in self or not self['uuid']:
411 self['uuid'] = uuid.createString()
412 else:
413 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
415 def _name_sanity_check(self):
416 if 'name_label' not in self:
417 self['name_label'] = 'Domain-' + self['uuid']
419 def validate(self):
420 self._uuid_sanity_check()
421 self._name_sanity_check()
422 self._memory_sanity_check()
423 self._actions_sanity_check()
424 self._vcpus_sanity_check()
426 def _dominfo_to_xapi(self, dominfo):
427 self['domid'] = dominfo['domid']
428 self['online_vcpus'] = dominfo['online_vcpus']
429 self['vcpus_number'] = dominfo['max_vcpu_id'] + 1
430 self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
431 self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
432 self['cpu_time'] = dominfo['cpu_time']/1e9
433 # TODO: i don't know what the security stuff expects here
434 if dominfo.get('ssidref'):
435 self['security'] = [['ssidref', dominfo['ssidref']]]
436 self['shutdown_reason'] = dominfo['shutdown_reason']
438 # parse state into Xen API states
439 self['running'] = dominfo['running']
440 self['crashed'] = dominfo['crashed']
441 self['dying'] = dominfo['dying']
442 self['shutdown'] = dominfo['shutdown']
443 self['paused'] = dominfo['paused']
444 self['blocked'] = dominfo['blocked']
446 if 'name' in dominfo:
447 self['name_label'] = dominfo['name']
449 if 'handle' in dominfo:
450 self['uuid'] = uuid.toString(dominfo['handle'])
452 def _parse_sxp(self, sxp_cfg):
453 """ Populate this XendConfig using the parsed SXP.
455 @param sxp_cfg: Parsed SXP Configuration
456 @type sxp_cfg: list of lists
457 @rtype: dictionary
458 @return: A dictionary containing the parsed options of the SXP.
459 """
460 cfg = {}
462 for key, typ in XENAPI_CFG_TYPES.items():
463 val = sxp.child_value(sxp_cfg, key)
464 if val is not None:
465 cfg[key] = typ(val)
467 # Convert deprecated options to current equivalents.
469 restart = sxp.child_value(sxp_cfg, 'restart')
470 if restart:
471 if restart == 'onreboot':
472 cfg['on_poweroff'] = 'destroy'
473 cfg['on_reboot'] = 'restart'
474 cfg['on_crash'] = 'destroy'
475 elif restart == 'always':
476 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
477 cfg[opt] = 'restart'
478 elif restart == 'never':
479 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
480 cfg[opt] = 'never'
481 else:
482 log.warn('Ignoring unrecognised value for deprecated option:'
483 'restart = \'%s\'', restart)
485 # Only extract options we know about.
486 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
487 extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
489 for key in extract_keys:
490 val = sxp.child_value(sxp_cfg, key)
491 if val != None:
492 try:
493 cfg[key] = LEGACY_CFG_TYPES[key](val)
494 except KeyError:
495 cfg[key] = val
496 except (TypeError, ValueError), e:
497 log.warn("Unable to parse key %s: %s: %s" %
498 (key, str(val), e))
500 # Compatibility hack -- can go soon.
501 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
502 if boot_order:
503 cfg['HVM_boot_policy'] = 'BIOS order'
504 cfg['HVM_boot_params'] = { 'order' : boot_order }
506 # Parsing the device SXP's. In most cases, the SXP looks
507 # like this:
508 #
509 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
510 #
511 # However, for PCI devices it looks like this:
512 #
513 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
514 #
515 # It seems the reasoning for this difference is because
516 # pciif.py needs all the PCI device configurations at
517 # the same time when creating the devices.
518 #
519 # To further complicate matters, Xen 2.0 configuration format
520 # uses the following for pci device configuration:
521 #
522 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
523 #
524 # Hence we deal with pci device configurations outside of
525 # the regular device parsing.
527 cfg['devices'] = {}
528 for dev in sxp.children(sxp_cfg, 'device'):
529 config = sxp.child0(dev)
530 dev_type = sxp.name(config)
531 dev_info = {}
533 if dev_type == 'pci':
534 pci_devs_uuid = sxp.child_value(config, 'uuid',
535 uuid.createString())
536 pci_devs = []
537 for pci_dev in sxp.children(config, 'dev'):
538 pci_dev_info = {}
539 for opt_val in pci_dev[1:]:
540 try:
541 opt, val = opt_val
542 pci_dev_info[opt] = val
543 except TypeError:
544 pass
545 pci_devs.append(pci_dev_info)
547 cfg['devices'][pci_devs_uuid] = (dev_type,
548 {'devs': pci_devs,
549 'uuid': pci_devs_uuid})
551 log.debug("XendConfig: reading device: %s" % pci_devs)
552 else:
553 self.device_add(dev_type, cfg_sxp = config, target = cfg)
554 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
556 # Extract missing data from configuration entries
557 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
558 if image_sxp:
559 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
560 if image_vcpus != None:
561 try:
562 if 'vcpus_number' not in cfg:
563 cfg['vcpus_number'] = int(image_vcpus)
564 elif cfg['vcpus_number'] != int(image_vcpus):
565 cfg['vcpus_number'] = int(image_vcpus)
566 log.warn('Overriding vcpus from %d to %d using image'
567 'vcpus value.', cfg['vcpus_number'])
568 except ValueError, e:
569 raise XendConfigError('integer expeceted: %s: %s' %
570 image_sxp, e)
572 # Deprecated cpu configuration
573 if 'cpu' in cfg:
574 if 'cpus' in cfg:
575 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
576 else:
577 cfg['cpus'] = str(cfg['cpu'])
579 # convert 'cpus' string to list of ints
580 # 'cpus' supports a list of ranges (0-3), seperated by
581 # commas, and negation, (^1).
582 # Precedence is settled by order of the string:
583 # "0-3,^1" -> [0,2,3]
584 # "0-3,^1,1" -> [0,1,2,3]
585 try:
586 if 'cpus' in cfg and type(cfg['cpus']) != list:
587 cpus = []
588 for c in cfg['cpus'].split(','):
589 if c.find('-') != -1:
590 (x, y) = c.split('-')
591 for i in range(int(x), int(y)+1):
592 cpus.append(int(i))
593 else:
594 # remove this element from the list
595 if c[0] == '^':
596 cpus = [x for x in cpus if x != int(c[1:])]
597 else:
598 cpus.append(int(c))
600 cfg['cpus'] = cpus
601 except ValueError, e:
602 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
604 if 'security' in cfg and isinstance(cfg['security'], str):
605 cfg['security'] = sxp.from_string(cfg['security'])
607 old_state = sxp.child_value(sxp_cfg, 'state')
608 if old_state:
609 for i in range(len(CONFIG_OLD_DOM_STATES)):
610 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
612 return cfg
615 def _sxp_to_xapi(self, sxp_cfg):
616 """Read in an SXP Configuration object and
617 populate at much of the Xen API with valid values.
618 """
619 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
621 cfg = self._parse_sxp(sxp_cfg)
623 for key, typ in XENAPI_CFG_TYPES.items():
624 val = cfg.get(key)
625 if val is not None:
626 self[key] = typ(val)
628 # Convert parameters that can be directly mapped from
629 # the Legacy Config to Xen API Config
631 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
632 try:
633 type_conv = XENAPI_CFG_TYPES.get(apikey)
634 if callable(type_conv):
635 self[apikey] = type_conv(cfg[cfgkey])
636 else:
637 log.warn("Unconverted key: " + apikey)
638 self[apikey] = cfg[cfgkey]
639 except KeyError:
640 pass
642 def update_with(n, o):
643 if not self.get(n):
644 self[n] = cfg.get(o, '')
646 update_with('PV_bootloader', 'bootloader')
647 update_with('PV_bootloader_args', 'bootloader_args')
649 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
650 if image_sxp:
651 self.update_with_image_sxp(image_sxp)
653 # Convert Legacy HVM parameters to Xen API configuration
654 self['platform_std_vga'] = bool0(cfg.get('stdvga', 0))
655 self['platform_serial'] = str(cfg.get('serial', ''))
656 self['platform_localtime'] = bool0(cfg.get('localtime', 0))
657 self['platform_enable_audio'] = bool0(cfg.get('soundhw', 0))
659 # make sure a sane maximum is set
660 if self['memory_static_max'] <= 0:
661 self['memory_static_max'] = self['memory_static_min']
663 self['memory_dynamic_max'] = self['memory_static_max']
664 self['memory_dynamic_min'] = self['memory_static_min']
666 # set device references in the configuration
667 self['devices'] = cfg.get('devices', {})
668 self['console_refs'] = cfg.get('console_refs', [])
669 self['vif_refs'] = cfg.get('vif_refs', [])
670 self['vbd_refs'] = cfg.get('vbd_refs', [])
671 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
673 # coalesce hvm vnc frame buffer with vfb config
674 if self['image']['type'] == 'hvm' and self['image'].get('vnc', 0):
675 # add vfb device if it isn't there already
676 has_rfb = False
677 for console_uuid in self['console_refs']:
678 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
679 has_rfb = True
680 break
681 if self['devices'][console_uuid][0] == 'vfb':
682 has_rfb = True
683 break
685 if not has_rfb:
686 dev_config = ['vfb']
687 # copy VNC related params from image config to vfb dev conf
688 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
689 'vnclisten']:
690 if key in self['image']:
691 dev_config.append([key, self['image'][key]])
693 self.device_add('vfb', cfg_sxp = dev_config)
696 def _sxp_to_xapi_unsupported(self, sxp_cfg):
697 """Read in an SXP configuration object and populate
698 values are that not related directly supported in
699 the Xen API.
700 """
702 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
704 # Parse and convert parameters used to configure
705 # the image (as well as HVM images)
706 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
707 if image_sxp:
708 image = {}
709 image['type'] = sxp.name(image_sxp)
710 for arg, conv in LEGACY_IMAGE_CFG:
711 val = sxp.child_value(image_sxp, arg, None)
712 if val != None:
713 image[arg] = conv(val)
715 image_hvm = {}
716 for arg, conv in LEGACY_IMAGE_HVM_CFG:
717 val = sxp.child_value(image_sxp, arg, None)
718 if val != None:
719 image_hvm[arg] = conv(val)
721 image_hvm_devices = {}
722 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
723 val = sxp.child_value(image_sxp, arg, None)
724 if val != None:
725 image_hvm_devices[arg] = conv(val)
727 if image_hvm or image_hvm_devices:
728 image['hvm'] = image_hvm
729 image['hvm']['devices'] = image_hvm_devices
731 self['image'] = image
733 for apikey, imgkey in XENAPI_HVM_CFG.items():
734 val = sxp.child_value(image_sxp, imgkey, None)
735 if val != None:
736 self[apikey] = val
737 self._hvm_boot_params_from_sxp(image_sxp)
739 # extract backend value
741 backend = []
742 for c in sxp.children(sxp_cfg, 'backend'):
743 backend.append(sxp.name(sxp.child0(c)))
744 if backend:
745 self['backend'] = backend
747 # Parse and convert other Non Xen API parameters.
748 def _set_cfg_if_exists(sxp_arg):
749 val = sxp.child_value(sxp_cfg, sxp_arg)
750 if val != None:
751 if LEGACY_CFG_TYPES.get(sxp_arg):
752 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
753 else:
754 self[sxp_arg] = val
756 _set_cfg_if_exists('shadow_memory')
757 _set_cfg_if_exists('security')
758 _set_cfg_if_exists('features')
759 _set_cfg_if_exists('on_xend_stop')
760 _set_cfg_if_exists('on_xend_start')
761 _set_cfg_if_exists('vcpu_avail')
762 _set_cfg_if_exists('cpu_weight')
763 _set_cfg_if_exists('cpu_cap')
765 # Parse and store runtime configuration
766 _set_cfg_if_exists('start_time')
767 _set_cfg_if_exists('cpu_time')
768 _set_cfg_if_exists('shutdown_reason')
769 _set_cfg_if_exists('up_time')
770 _set_cfg_if_exists('status') # TODO, deprecated
772 def _add_xapi_unsupported(self, xapi_dict):
773 """Updates the configuration object with entries that are not
774 officially supported by the Xen API but is required for
775 the rest of Xend to function.
776 """
778 # populate image
779 if 'image' in xapi_dict:
780 self['image'].update(xapi_dict['image'])
781 else:
782 hvm = self['HVM_boot_policy'] != ''
783 self['image']['type'] = hvm and 'hvm' or 'linux'
784 if hvm:
785 self['image']['hvm'] = {'devices': {}}
786 for xapi, cfgapi in XENAPI_HVM_CFG.items():
787 if xapi in self:
788 self['image']['hvm']['devices'][cfgapi] = self[xapi]
790 # currently unsupported options
791 self['image']['hvm']['device_model'] = LEGACY_DM
792 self['image']['vnc'] = 0
793 self['image']['hvm']['pae'] = 1
795 if self['platform_enable_audio']:
796 self['image']['hvm']['devices']['soundhw'] = 'sb16'
799 def _get_old_state_string(self):
800 """Returns the old xm state string.
801 @rtype: string
802 @return: old state string
803 """
804 state_string = ''
805 for state_name in CONFIG_OLD_DOM_STATES:
806 on_off = self.get(state_name, 0)
807 if on_off:
808 state_string += state_name[0]
809 else:
810 state_string += '-'
812 return state_string
815 def update_config(self, dominfo):
816 """Update configuration with the output from xc.domain_getinfo().
818 @param dominfo: Domain information via xc.domain_getinfo()
819 @type dominfo: dict
820 """
821 self._dominfo_to_xapi(dominfo)
822 self.validate()
824 def update_with_xenapi_config(self, xapi):
825 """Update configuration with a Xen API VM struct
827 @param xapi: Xen API VM Struct
828 @type xapi: dict
829 """
831 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
833 for key, val in xapi.items():
834 type_conv = XENAPI_CFG_TYPES.get(key)
835 if type_conv is None:
836 key = key.lower()
837 type_conv = XENAPI_CFG_TYPES.get(key)
838 if callable(type_conv):
839 self[key] = type_conv(val)
840 else:
841 self[key] = val
843 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
844 legacy_only = True):
845 """ Get SXP representation of this config object.
847 Incompat: removed store_mfn, console_mfn
849 @keyword domain: (optional) XendDomainInfo to get extra information
850 from such as domid and running devices.
851 @type domain: XendDomainInfo
852 @keyword ignore: (optional) list of 'keys' that we do not want
853 to export.
854 @type ignore: list of strings
855 @rtype: list of list (SXP representation)
856 """
857 sxpr = ['domain']
859 # TODO: domid/dom is the same thing but called differently
860 # depending if it is from xenstore or sxpr.
862 if domain.getDomid() is not None:
863 sxpr.append(['domid', domain.getDomid()])
865 if not legacy_only:
866 for name, typ in XENAPI_CFG_TYPES.items():
867 if name in self and self[name] not in (None, []):
868 if typ == dict:
869 s = self[name].items()
870 else:
871 s = str(self[name])
872 sxpr.append([name, s])
874 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
875 if self.has_key(xenapi) and self[xenapi] not in (None, []):
876 if type(self[xenapi]) == bool:
877 # convert booleans to ints before making an sxp item
878 sxpr.append([legacy, int(self[xenapi])])
879 else:
880 sxpr.append([legacy, self[xenapi]])
882 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
883 if legacy in ('domid', 'uuid'): # skip these
884 continue
885 if self.has_key(legacy) and self[legacy] not in (None, []):
886 sxpr.append([legacy, self[legacy]])
888 if 'image' in self and self['image']:
889 sxpr.append(['image', self.image_sxpr()])
891 sxpr.append(['status', domain.state])
892 sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
893 sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
895 if domain.getDomid() is not None:
896 sxpr.append(['state', self._get_old_state_string()])
898 if domain:
899 if domain.store_mfn:
900 sxpr.append(['store_mfn', domain.store_mfn])
901 if domain.console_mfn:
902 sxpr.append(['console_mfn', domain.console_mfn])
905 # Marshall devices (running or from configuration)
906 if not ignore_devices:
907 for cls in XendDevices.valid_devices():
908 found = False
910 # figure if there is a dev controller is valid and running
911 if domain and domain.getDomid() != None:
912 try:
913 controller = domain.getDeviceController(cls)
914 configs = controller.configurations()
915 for config in configs:
916 if sxp.name(config) in ('vbd', 'tap'):
917 # The bootable flag is never written to the
918 # store as part of the device config.
919 dev_uuid = sxp.child_value(config, 'uuid')
920 dev_type, dev_cfg = self['devices'][dev_uuid]
921 is_bootable = dev_cfg.get('bootable', 0)
922 config.append(['bootable', int(is_bootable)])
924 sxpr.append(['device', config])
926 found = True
927 except:
928 log.exception("dumping sxp from device controllers")
929 pass
931 # if we didn't find that device, check the existing config
932 # for a device in the same class
933 if not found:
934 for dev_type, dev_info in self.all_devices_sxpr():
935 if dev_type == cls:
936 sxpr.append(['device', dev_info])
938 return sxpr
940 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
941 target = None):
942 """Add a device configuration in SXP format or XenAPI struct format.
944 For SXP, it could be either:
946 [device, [vbd, [uname ...]]
948 or:
950 [vbd, [uname ..]]
952 @type cfg_sxp: list of lists (parsed sxp object)
953 @param cfg_sxp: SXP configuration object
954 @type cfg_xenapi: dict
955 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
956 @param target: write device information to
957 @type target: None or a dictionary
958 @rtype: string
959 @return: Assigned UUID of the device.
960 """
961 if target == None:
962 target = self
964 if dev_type not in XendDevices.valid_devices():
965 raise XendConfigError("XendConfig: %s not a valid device type" %
966 dev_type)
968 if cfg_sxp == None and cfg_xenapi == None:
969 raise XendConfigError("XendConfig: device_add requires some "
970 "config.")
972 #if cfg_sxp:
973 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
974 #if cfg_xenapi:
975 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
977 if cfg_sxp:
978 if sxp.child0(cfg_sxp) == 'device':
979 config = sxp.child0(cfg_sxp)
980 else:
981 config = cfg_sxp
983 dev_type = sxp.name(config)
984 dev_info = {}
986 for opt_val in config[1:]:
987 try:
988 opt, val = opt_val
989 dev_info[opt] = val
990 except (TypeError, ValueError): # unpack error
991 pass
993 if dev_type == 'vbd':
994 dev_info['bootable'] = 0
995 if dev_info.get('dev', '').startswith('ioemu:'):
996 dev_info['driver'] = 'ioemu'
997 else:
998 dev_info['driver'] = 'paravirtualised'
1000 # create uuid if it doesn't exist
1001 dev_uuid = dev_info.get('uuid', None)
1002 if not dev_uuid:
1003 dev_uuid = uuid.createString()
1004 dev_info['uuid'] = dev_uuid
1006 # store dev references by uuid for certain device types
1007 target['devices'][dev_uuid] = (dev_type, dev_info)
1008 if dev_type in ('vif', 'vbd', 'vtpm'):
1009 param = '%s_refs' % dev_type
1010 if param not in target:
1011 target[param] = []
1012 if dev_uuid not in target[param]:
1013 if dev_type == 'vbd' and not target[param]:
1014 # Compat hack -- this is the first disk, so mark it
1015 # bootable.
1016 dev_info['bootable'] = 1
1017 target[param].append(dev_uuid)
1018 elif dev_type == 'tap':
1019 if 'vbd_refs' not in target:
1020 target['vbd_refs'] = []
1021 if dev_uuid not in target['vbd_refs']:
1022 if not target['vbd_refs']:
1023 # Compat hack -- this is the first disk, so mark it
1024 # bootable.
1025 dev_info['bootable'] = 1
1026 target['vbd_refs'].append(dev_uuid)
1028 elif dev_type == 'vfb':
1029 # Populate other config with aux data that is associated
1030 # with vfb
1032 other_config = {}
1033 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1034 'vncpasswd', 'type', 'display', 'xauthority',
1035 'keymap']:
1036 if key in dev_info:
1037 other_config[key] = dev_info[key]
1038 target['devices'][dev_uuid][1]['other_config'] = other_config
1041 if 'console_refs' not in target:
1042 target['console_refs'] = []
1044 # Treat VFB devices as console devices so they are found
1045 # through Xen API
1046 if dev_uuid not in target['console_refs']:
1047 target['console_refs'].append(dev_uuid)
1049 elif dev_type == 'console':
1050 if 'console_refs' not in target:
1051 target['console_refs'] = []
1052 if dev_uuid not in target['console_refs']:
1053 target['console_refs'].append(dev_uuid)
1055 return dev_uuid
1057 if cfg_xenapi:
1058 dev_info = {}
1059 dev_uuid = ''
1060 if dev_type == 'vif':
1061 if cfg_xenapi.get('MAC'): # don't add if blank
1062 dev_info['mac'] = cfg_xenapi.get('MAC')
1063 # vifname is the name on the guest, not dom0
1064 # TODO: we don't have the ability to find that out or
1065 # change it from dom0
1066 #if cfg_xenapi.get('device'): # don't add if blank
1067 # dev_info['vifname'] = cfg_xenapi.get('device')
1068 if cfg_xenapi.get('type'):
1069 dev_info['type'] = cfg_xenapi.get('type')
1070 if cfg_xenapi.get('name'):
1071 dev_info['name'] = cfg_xenapi.get('name')
1073 dev_uuid = cfg_xenapi.get('uuid', None)
1074 if not dev_uuid:
1075 dev_uuid = uuid.createString()
1076 dev_info['uuid'] = dev_uuid
1077 target['devices'][dev_uuid] = (dev_type, dev_info)
1078 target['vif_refs'].append(dev_uuid)
1080 elif dev_type in ('vbd', 'tap'):
1081 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1082 if dev_info['type'] == 'CD':
1083 old_vbd_type = 'cdrom'
1084 else:
1085 old_vbd_type = 'disk'
1087 dev_info['uname'] = cfg_xenapi.get('image', '')
1088 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1089 old_vbd_type)
1090 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1091 dev_info['driver'] = cfg_xenapi.get('driver', '')
1092 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1094 if cfg_xenapi.get('mode') == 'RW':
1095 dev_info['mode'] = 'w'
1096 else:
1097 dev_info['mode'] = 'r'
1099 dev_uuid = cfg_xenapi.get('uuid', None)
1100 if not dev_uuid:
1101 dev_uuid = uuid.createString()
1102 dev_info['uuid'] = dev_uuid
1103 target['devices'][dev_uuid] = (dev_type, dev_info)
1104 target['vbd_refs'].append(dev_uuid)
1106 elif dev_type == 'vtpm':
1107 if cfg_xenapi.get('type'):
1108 dev_info['type'] = cfg_xenapi.get('type')
1110 dev_uuid = cfg_xenapi.get('uuid', None)
1111 if not dev_uuid:
1112 dev_uuid = uuid.createString()
1113 dev_info['uuid'] = dev_uuid
1114 target['devices'][dev_uuid] = (dev_type, dev_info)
1115 target['vtpm_refs'].append(dev_uuid)
1117 elif dev_type == 'console':
1118 dev_uuid = cfg_xenapi.get('uuid', None)
1119 if not dev_uuid:
1120 dev_uuid = uuid.createString()
1121 dev_info['uuid'] = dev_uuid
1122 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1123 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1124 if dev_info['protocol'] == 'rfb':
1125 # collapse other config into devinfo for things
1126 # such as vncpasswd, vncunused, etc.
1127 dev_info.update(cfg_xenapi.get('other_config', {}))
1128 dev_info['type'] = 'vnc'
1129 target['devices'][dev_uuid] = ('vfb', dev_info)
1130 target['console_refs'].append(dev_uuid)
1132 # Finally, if we are a pvfb, we need to make a vkbd
1133 # as well that is not really exposed to Xen API
1134 vkbd_uuid = uuid.createString()
1135 target['devices'][vkbd_uuid] = ('vkbd', {})
1137 elif dev_info['protocol'] == 'vt100':
1138 # if someone tries to create a VT100 console
1139 # via the Xen API, we'll have to ignore it
1140 # because we create one automatically in
1141 # XendDomainInfo._update_consoles
1142 raise XendConfigError('Creating vt100 consoles via '
1143 'Xen API is unsupported')
1145 return dev_uuid
1147 # no valid device to add
1148 return ''
1150 def console_add(self, protocol, location, other_config = {}):
1151 dev_uuid = uuid.createString()
1152 if protocol == 'vt100':
1153 dev_info = {
1154 'uuid': dev_uuid,
1155 'protocol': protocol,
1156 'location': location,
1157 'other_config': other_config,
1160 if 'devices' not in self:
1161 self['devices'] = {}
1163 self['devices'][dev_uuid] = ('console', dev_info)
1164 self['console_refs'].append(dev_uuid)
1165 return dev_info
1167 return {}
1169 def console_update(self, console_uuid, key, value):
1170 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1171 if dev_uuid == console_uuid:
1172 dev_info[key] = value
1173 break
1175 def console_get_all(self, protocol):
1176 if protocol == 'vt100':
1177 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1178 if dtype == 'console']
1179 return [c for c in consoles if c.get('protocol') == protocol]
1181 elif protocol == 'rfb':
1182 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1183 if dtype == 'vfb']
1185 # move all non-console key values to other_config before
1186 # returning console config
1187 valid_keys = ['uuid', 'location']
1188 for vfb in vfbs:
1189 other_config = {}
1190 for key, val in vfb.items():
1191 if key not in valid_keys:
1192 other_config[key] = vfb[key]
1193 del vfb[key]
1194 vfb['other_config'] = other_config
1195 vfb['protocol'] = 'rfb'
1197 return vfbs
1199 else:
1200 return []
1202 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1203 """Update an existing device with the new configuration.
1205 @rtype: boolean
1206 @return: Returns True if succesfully found and updated a device conf
1207 """
1208 if dev_uuid in self['devices'] and cfg_sxp:
1209 if sxp.child0(cfg_sxp) == 'device':
1210 config = sxp.child0(cfg_sxp)
1211 else:
1212 config = cfg_sxp
1214 dev_type, dev_info = self['devices'][dev_uuid]
1215 for opt_val in config[1:]:
1216 try:
1217 opt, val = opt_val
1218 dev_info[opt] = val
1219 except (TypeError, ValueError):
1220 pass # no value for this config option
1222 self['devices'][dev_uuid] = (dev_type, dev_info)
1223 return True
1225 elif dev_uuid in self['devices'] and cfg_xenapi:
1226 dev_type, dev_info = self['devices'][dev_uuid]
1227 for key, val in cfg_xenapi.items():
1228 dev_info[key] = val
1229 self['devices'][dev_uuid] = (dev_type, dev_info)
1231 return False
1234 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
1235 """Get Device SXPR by either giving the device UUID or (type, config).
1237 @rtype: list of lists
1238 @return: device config sxpr
1239 """
1240 sxpr = []
1241 if dev_uuid != None and dev_uuid in self['devices']:
1242 dev_type, dev_info = self['devices'][dev_uuid]
1244 if dev_type == None or dev_info == None:
1245 raise XendConfigError("Required either UUID or device type and "
1246 "configuration dictionary.")
1248 sxpr.append(dev_type)
1249 if dev_type in ('console', 'vfb'):
1250 config = [(opt, val) for opt, val in dev_info.items()
1251 if opt != 'other_config']
1252 else:
1253 config = [(opt, val) for opt, val in dev_info.items()]
1255 sxpr += config
1257 return sxpr
1259 def ordered_device_refs(self):
1260 result = (self['console_refs'] +
1261 self['vbd_refs'] +
1262 self['vif_refs'] +
1263 self['vtpm_refs'])
1264 result.extend([u for u in self['devices'].keys() if u not in result])
1265 return result
1267 def all_devices_sxpr(self):
1268 """Returns the SXPR for all devices in the current configuration."""
1269 sxprs = []
1270 pci_devs = []
1272 if 'devices' not in self:
1273 return sxprs
1275 ordered_refs = self.ordered_device_refs()
1276 for dev_uuid in ordered_refs:
1277 dev_type, dev_info = self['devices'][dev_uuid]
1278 if dev_type == 'pci': # special case for pci devices
1279 sxpr = [['uuid', dev_info['uuid']]]
1280 for pci_dev_info in dev_info['devs']:
1281 pci_dev_sxpr = ['dev']
1282 for opt, val in pci_dev_info.items():
1283 pci_dev_sxpr.append([opt, val])
1284 sxpr.append(pci_dev_sxpr)
1285 sxprs.append((dev_type, sxpr))
1286 else:
1287 sxpr = self.device_sxpr(dev_type = dev_type,
1288 dev_info = dev_info)
1289 sxprs.append((dev_type, sxpr))
1291 return sxprs
1293 def image_sxpr(self):
1294 """Returns a backwards compatible image SXP expression that is
1295 used in xenstore's /vm/<uuid>/image value and xm list."""
1296 image = [self['image'].get('type', 'linux')]
1297 if self.has_key('PV_kernel'):
1298 image.append(['kernel', self['PV_kernel']])
1299 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1300 image.append(['ramdisk', self['PV_ramdisk']])
1301 if self.has_key('PV_args') and self['PV_args']:
1302 image.append(['args', self['PV_args']])
1304 for arg, conv in LEGACY_IMAGE_CFG:
1305 if self['image'].has_key(arg):
1306 image.append([arg, self['image'][arg]])
1308 if 'hvm' in self['image']:
1309 for arg, conv in LEGACY_IMAGE_HVM_CFG:
1310 if self['image']['hvm'].get(arg):
1311 image.append([arg, conv(self['image']['hvm'][arg])])
1313 if 'hvm' in self['image'] and 'devices' in self['image']['hvm']:
1314 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
1315 val = self['image']['hvm']['devices'].get(arg)
1316 if val != None:
1317 try:
1318 if conv: val = conv(val)
1319 except (ValueError, TypeError):
1320 if type(val) == bool: val = int(val)
1322 image.append([arg, val])
1324 return image
1326 def update_with_image_sxp(self, image_sxp, bootloader = False):
1327 # Convert Legacy "image" config to Xen API PV_*
1328 # configuration
1329 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1331 # user-specified args must come last: previous releases did this and
1332 # some domU kernels rely upon the ordering.
1333 kernel_args = sxp.child_value(image_sxp, 'args', '')
1335 # attempt to extract extra arguments from SXP config
1336 arg_ip = sxp.child_value(image_sxp, 'ip')
1337 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1338 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1339 arg_root = sxp.child_value(image_sxp, 'root')
1340 if arg_root and not re.search(r'root=', kernel_args):
1341 kernel_args = 'root=%s ' % arg_root + kernel_args
1343 if bootloader:
1344 self['_temp_using_bootloader'] = '1'
1345 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1346 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1347 self['_temp_args'] = kernel_args
1348 else:
1349 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1350 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1351 self['PV_args'] = kernel_args
1353 # Store image SXP in python dictionary format
1354 image = {}
1355 image['type'] = sxp.name(image_sxp)
1356 for arg, conv in LEGACY_IMAGE_CFG:
1357 val = sxp.child_value(image_sxp, arg, None)
1358 if val != None:
1359 image[arg] = conv(val)
1361 image_hvm = {}
1362 for arg, conv in LEGACY_IMAGE_HVM_CFG:
1363 val = sxp.child_value(image_sxp, arg, None)
1364 if val != None:
1365 image_hvm[arg] = conv(val)
1367 image_hvm_devices = {}
1368 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
1369 val = sxp.child_value(image_sxp, arg, None)
1370 if val != None:
1371 try:
1372 image_hvm_devices[arg] = conv(val)
1373 except (ValueError, TypeError):
1374 image_hvm_devices[arg] = val
1377 if image_hvm or image_hvm_devices:
1378 image['hvm'] = image_hvm
1379 image['hvm']['devices'] = image_hvm_devices
1381 self['image'] = image
1383 for apikey, imgkey in XENAPI_HVM_CFG.items():
1384 val = sxp.child_value(image_sxp, imgkey, None)
1385 if val != None:
1386 type_conv = XENAPI_CFG_TYPES[apikey]
1387 if callable(type_conv):
1388 self[apikey] = type_conv(val)
1389 else:
1390 self[apikey] = val
1391 self._hvm_boot_params_from_sxp(image_sxp)
1394 def _hvm_boot_params_from_sxp(self, image_sxp):
1395 boot = sxp.child_value(image_sxp, 'boot', None)
1396 if boot is not None:
1397 self['HVM_boot_policy'] = 'BIOS order'
1398 self['HVM_boot_params'] = { 'order' : boot }
1402 # debugging
1405 if __name__ == "__main__":
1406 pass