ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 14360:620212e48908

Remove obsolete tpm_backend entry.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Sat Mar 10 21:43:07 2007 +0000 (2007-03-10)
parents 64d80037e524
children 0affe03ee985
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 'PV_bootloader': str,
155 'PV_kernel': str,
156 'PV_ramdisk': str,
157 'PV_args': str,
158 'PV_bootloader_args': str,
159 'HVM_boot_policy': str,
160 'HVM_boot_params': dict,
161 'platform_std_vga': bool0,
162 'platform_serial': str,
163 'platform_localtime': bool0,
164 'platform_clock_offset': bool0,
165 'platform_enable_audio': bool0,
166 'platform_keymap': str,
167 'pci_bus': str,
168 'tools_version': dict,
169 'otherconfig': dict,
170 }
172 # List of legacy configuration keys that have no equivalent in the
173 # Xen API, but are still stored in XendConfig.
175 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
176 # roundtripped (dynamic, unmodified)
177 'shadow_memory',
178 'security',
179 'vcpu_avail',
180 'cpu_weight',
181 'cpu_cap',
182 'features',
183 # read/write
184 'on_xend_start',
185 'on_xend_stop',
186 # read-only
187 'domid',
188 'start_time',
189 'cpu_time',
190 'online_vcpus',
191 # write-once
192 'cpu',
193 'cpus',
194 ]
196 LEGACY_CFG_TYPES = {
197 'uuid': str,
198 'name': str,
199 'vcpus': int,
200 'vcpu_avail': long,
201 'memory': int,
202 'shadow_memory': int,
203 'maxmem': int,
204 'start_time': float,
205 'cpu_cap': int,
206 'cpu_weight': int,
207 'cpu_time': float,
208 'features': str,
209 'localtime': int,
210 'name': str,
211 'on_poweroff': str,
212 'on_reboot': str,
213 'on_crash': str,
214 'on_xend_stop': str,
215 'on_xend_start': str,
216 'online_vcpus': int,
217 }
219 # Values that should be stored in xenstore's /vm/<uuid> that is used
220 # by Xend. Used in XendDomainInfo to restore running VM state from
221 # xenstore.
222 LEGACY_XENSTORE_VM_PARAMS = [
223 'uuid',
224 'name',
225 'vcpus',
226 'vcpu_avail',
227 'memory',
228 'shadow_memory',
229 'maxmem',
230 'start_time',
231 'name',
232 'on_poweroff',
233 'on_crash',
234 'on_reboot',
235 'on_xend_start',
236 'on_xend_stop',
237 ]
239 LEGACY_IMAGE_CFG = [
240 ('root', str),
241 ('ip', str),
242 ('nographic', int),
243 ('vnc', int),
244 ('sdl', int),
245 ('vncdisplay', int),
246 ('vncunused', int),
247 ('vncpasswd', str),
248 ('vnclisten', str),
249 ]
251 LEGACY_IMAGE_HVM_CFG = [
252 ('device_model', str),
253 ('display', str),
254 ('xauthority', str),
255 ('vncconsole', int),
256 ('pae', int),
257 ('apic', int),
258 ]
260 LEGACY_IMAGE_HVM_DEVICES_CFG = [
261 ('acpi', int),
262 ('boot', str),
263 ('fda', str),
264 ('fdb', str),
265 ('isa', int),
266 ('keymap', str),
267 ('localtime', int),
268 ('serial', str),
269 ('stdvga', int),
270 ('soundhw', str),
271 ('usb', int),
272 ('usbdevice', str),
273 ('vcpus', int),
274 ]
276 LEGACY_DM = '/usr/lib/xen/bin/qemu-dm'
278 ##
279 ## Config Choices
280 ##
282 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
283 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
284 'crashed', 'dying')
286 class XendConfigError(VmError):
287 def __str__(self):
288 return 'Invalid Configuration: %s' % str(self.value)
290 ##
291 ## XendConfig Class (an extended dictionary)
292 ##
294 class XendConfig(dict):
295 """ The new Xend VM Configuration.
297 Stores the configuration in xenapi compatible format but retains
298 import and export functions for SXP.
299 """
300 def __init__(self, filename = None, sxp_obj = None,
301 xapi = None, dominfo = None):
303 dict.__init__(self)
304 self.update(self._defaults())
306 if filename:
307 try:
308 sxp_obj = sxp.parse(open(filename,'r'))
309 sxp_obj = sxp_obj[0]
310 except IOError, e:
311 raise XendConfigError("Unable to read file: %s" % filename)
313 if sxp_obj:
314 self._sxp_to_xapi(sxp_obj)
315 self._sxp_to_xapi_unsupported(sxp_obj)
316 elif xapi:
317 self.update_with_xenapi_config(xapi)
318 self._add_xapi_unsupported(xapi)
319 elif dominfo:
320 # output from xc.domain_getinfo
321 self._dominfo_to_xapi(dominfo)
323 log.debug('XendConfig.init: %s' % scrub_password(self))
325 # validators go here
326 self.validate()
328 """ In time, we should enable this type checking addition. It is great
329 also for tracking bugs and unintended writes to XendDomainInfo.info
330 def __setitem__(self, key, value):
331 type_conv = XENAPI_CFG_TYPES.get(key)
332 if callable(type_conv):
333 try:
334 dict.__setitem__(self, key, type_conv(value))
335 except (ValueError, TypeError):
336 raise XendConfigError("Wrong type for configuration value " +
337 "%s. Expected %s" %
338 (key, type_conv.__name__))
339 else:
340 dict.__setitem__(self, key, value)
341 """
343 def _defaults(self):
344 defaults = {
345 'name_label': 'Domain-Unnamed',
346 'actions_after_shutdown': 'destroy',
347 'actions_after_reboot': 'restart',
348 'actions_after_crash': 'restart',
349 'actions_after_suspend': '',
350 'features': '',
351 'PV_bootloader': '',
352 'PV_kernel': '',
353 'PV_ramdisk': '',
354 'PV_args': '',
355 'PV_bootloader_args': '',
356 'HVM_boot_policy': '',
357 'HVM_boot_params': {},
358 'memory_static_min': 0,
359 'memory_dynamic_min': 0,
360 'shadow_memory': 0,
361 'memory_static_max': 0,
362 'memory_dynamic_max': 0,
363 'memory_actual': 0,
364 'devices': {},
365 'image': {},
366 'security': None,
367 'on_xend_start': 'ignore',
368 'on_xend_stop': 'ignore',
369 'cpus': [],
370 'cpu_weight': 256,
371 'cpu_cap': 0,
372 'vcpus_number': 1,
373 'vcpus_params': {},
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 notes = sxp.children(image_sxp, 'notes')
732 if notes:
733 image['notes'] = self.notes_from_sxp(notes[0])
735 self['image'] = image
737 for apikey, imgkey in XENAPI_HVM_CFG.items():
738 val = sxp.child_value(image_sxp, imgkey, None)
739 if val != None:
740 self[apikey] = val
741 self._hvm_boot_params_from_sxp(image_sxp)
743 # extract backend value
745 backend = []
746 for c in sxp.children(sxp_cfg, 'backend'):
747 backend.append(sxp.name(sxp.child0(c)))
748 if backend:
749 self['backend'] = backend
751 # Parse and convert other Non Xen API parameters.
752 def _set_cfg_if_exists(sxp_arg):
753 val = sxp.child_value(sxp_cfg, sxp_arg)
754 if val != None:
755 if LEGACY_CFG_TYPES.get(sxp_arg):
756 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
757 else:
758 self[sxp_arg] = val
760 _set_cfg_if_exists('shadow_memory')
761 _set_cfg_if_exists('security')
762 _set_cfg_if_exists('features')
763 _set_cfg_if_exists('on_xend_stop')
764 _set_cfg_if_exists('on_xend_start')
765 _set_cfg_if_exists('vcpu_avail')
766 _set_cfg_if_exists('cpu_weight')
767 _set_cfg_if_exists('cpu_cap')
769 # Parse and store runtime configuration
770 _set_cfg_if_exists('start_time')
771 _set_cfg_if_exists('cpu_time')
772 _set_cfg_if_exists('shutdown_reason')
773 _set_cfg_if_exists('up_time')
774 _set_cfg_if_exists('status') # TODO, deprecated
776 def _add_xapi_unsupported(self, xapi_dict):
777 """Updates the configuration object with entries that are not
778 officially supported by the Xen API but is required for
779 the rest of Xend to function.
780 """
782 # populate image
783 if 'image' in xapi_dict:
784 self['image'].update(xapi_dict['image'])
785 else:
786 hvm = self['HVM_boot_policy'] != ''
787 self['image']['type'] = hvm and 'hvm' or 'linux'
788 if hvm:
789 self['image']['hvm'] = {'devices': {}}
790 for xapi, cfgapi in XENAPI_HVM_CFG.items():
791 if xapi in self:
792 self['image']['hvm']['devices'][cfgapi] = self[xapi]
794 # currently unsupported options
795 self['image']['hvm']['device_model'] = LEGACY_DM
796 self['image']['vnc'] = 0
797 self['image']['hvm']['pae'] = 1
799 if self['platform_enable_audio']:
800 self['image']['hvm']['devices']['soundhw'] = 'sb16'
803 def _get_old_state_string(self):
804 """Returns the old xm state string.
805 @rtype: string
806 @return: old state string
807 """
808 state_string = ''
809 for state_name in CONFIG_OLD_DOM_STATES:
810 on_off = self.get(state_name, 0)
811 if on_off:
812 state_string += state_name[0]
813 else:
814 state_string += '-'
816 return state_string
819 def update_config(self, dominfo):
820 """Update configuration with the output from xc.domain_getinfo().
822 @param dominfo: Domain information via xc.domain_getinfo()
823 @type dominfo: dict
824 """
825 self._dominfo_to_xapi(dominfo)
826 self.validate()
828 def update_with_xenapi_config(self, xapi):
829 """Update configuration with a Xen API VM struct
831 @param xapi: Xen API VM Struct
832 @type xapi: dict
833 """
835 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
837 for key, val in xapi.items():
838 type_conv = XENAPI_CFG_TYPES.get(key)
839 if type_conv is None:
840 key = key.lower()
841 type_conv = XENAPI_CFG_TYPES.get(key)
842 if callable(type_conv):
843 self[key] = type_conv(val)
844 else:
845 self[key] = val
847 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
848 legacy_only = True):
849 """ Get SXP representation of this config object.
851 Incompat: removed store_mfn, console_mfn
853 @keyword domain: (optional) XendDomainInfo to get extra information
854 from such as domid and running devices.
855 @type domain: XendDomainInfo
856 @keyword ignore: (optional) list of 'keys' that we do not want
857 to export.
858 @type ignore: list of strings
859 @rtype: list of list (SXP representation)
860 """
861 sxpr = ['domain']
863 # TODO: domid/dom is the same thing but called differently
864 # depending if it is from xenstore or sxpr.
866 if domain.getDomid() is not None:
867 sxpr.append(['domid', domain.getDomid()])
869 if not legacy_only:
870 for name, typ in XENAPI_CFG_TYPES.items():
871 if name in self and self[name] not in (None, []):
872 if typ == dict:
873 s = self[name].items()
874 else:
875 s = str(self[name])
876 sxpr.append([name, s])
878 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
879 if self.has_key(xenapi) and self[xenapi] not in (None, []):
880 if type(self[xenapi]) == bool:
881 # convert booleans to ints before making an sxp item
882 sxpr.append([legacy, int(self[xenapi])])
883 else:
884 sxpr.append([legacy, self[xenapi]])
886 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
887 if legacy in ('domid', 'uuid'): # skip these
888 continue
889 if self.has_key(legacy) and self[legacy] not in (None, []):
890 sxpr.append([legacy, self[legacy]])
892 if 'image' in self and self['image']:
893 sxpr.append(['image', self.image_sxpr()])
895 sxpr.append(['status', domain.state])
896 sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
897 sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
899 if domain.getDomid() is not None:
900 sxpr.append(['state', self._get_old_state_string()])
902 if domain:
903 if domain.store_mfn:
904 sxpr.append(['store_mfn', domain.store_mfn])
905 if domain.console_mfn:
906 sxpr.append(['console_mfn', domain.console_mfn])
909 # Marshall devices (running or from configuration)
910 if not ignore_devices:
911 for cls in XendDevices.valid_devices():
912 found = False
914 # figure if there is a dev controller is valid and running
915 if domain and domain.getDomid() != None:
916 try:
917 controller = domain.getDeviceController(cls)
918 configs = controller.configurations()
919 for config in configs:
920 if sxp.name(config) in ('vbd', 'tap'):
921 # The bootable flag is never written to the
922 # store as part of the device config.
923 dev_uuid = sxp.child_value(config, 'uuid')
924 dev_type, dev_cfg = self['devices'][dev_uuid]
925 is_bootable = dev_cfg.get('bootable', 0)
926 config.append(['bootable', int(is_bootable)])
928 sxpr.append(['device', config])
930 found = True
931 except:
932 log.exception("dumping sxp from device controllers")
933 pass
935 # if we didn't find that device, check the existing config
936 # for a device in the same class
937 if not found:
938 for dev_type, dev_info in self.all_devices_sxpr():
939 if dev_type == cls:
940 sxpr.append(['device', dev_info])
942 return sxpr
944 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
945 target = None):
946 """Add a device configuration in SXP format or XenAPI struct format.
948 For SXP, it could be either:
950 [device, [vbd, [uname ...]]
952 or:
954 [vbd, [uname ..]]
956 @type cfg_sxp: list of lists (parsed sxp object)
957 @param cfg_sxp: SXP configuration object
958 @type cfg_xenapi: dict
959 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
960 @param target: write device information to
961 @type target: None or a dictionary
962 @rtype: string
963 @return: Assigned UUID of the device.
964 """
965 if target == None:
966 target = self
968 if dev_type not in XendDevices.valid_devices():
969 raise XendConfigError("XendConfig: %s not a valid device type" %
970 dev_type)
972 if cfg_sxp == None and cfg_xenapi == None:
973 raise XendConfigError("XendConfig: device_add requires some "
974 "config.")
976 #if cfg_sxp:
977 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
978 #if cfg_xenapi:
979 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
981 if cfg_sxp:
982 if sxp.child0(cfg_sxp) == 'device':
983 config = sxp.child0(cfg_sxp)
984 else:
985 config = cfg_sxp
987 dev_type = sxp.name(config)
988 dev_info = {}
990 for opt_val in config[1:]:
991 try:
992 opt, val = opt_val
993 dev_info[opt] = val
994 except (TypeError, ValueError): # unpack error
995 pass
997 if dev_type == 'vbd':
998 dev_info['bootable'] = 0
999 if dev_info.get('dev', '').startswith('ioemu:'):
1000 dev_info['driver'] = 'ioemu'
1001 else:
1002 dev_info['driver'] = 'paravirtualised'
1004 # create uuid if it doesn't exist
1005 dev_uuid = dev_info.get('uuid', None)
1006 if not dev_uuid:
1007 dev_uuid = uuid.createString()
1008 dev_info['uuid'] = dev_uuid
1010 # store dev references by uuid for certain device types
1011 target['devices'][dev_uuid] = (dev_type, dev_info)
1012 if dev_type in ('vif', 'vbd', 'vtpm'):
1013 param = '%s_refs' % dev_type
1014 if param not in target:
1015 target[param] = []
1016 if dev_uuid not in target[param]:
1017 if dev_type == 'vbd' and not target[param]:
1018 # Compat hack -- this is the first disk, so mark it
1019 # bootable.
1020 dev_info['bootable'] = 1
1021 target[param].append(dev_uuid)
1022 elif dev_type == 'tap':
1023 if 'vbd_refs' not in target:
1024 target['vbd_refs'] = []
1025 if dev_uuid not in target['vbd_refs']:
1026 if not target['vbd_refs']:
1027 # Compat hack -- this is the first disk, so mark it
1028 # bootable.
1029 dev_info['bootable'] = 1
1030 target['vbd_refs'].append(dev_uuid)
1032 elif dev_type == 'vfb':
1033 # Populate other config with aux data that is associated
1034 # with vfb
1036 other_config = {}
1037 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1038 'vncpasswd', 'type', 'display', 'xauthority',
1039 'keymap']:
1040 if key in dev_info:
1041 other_config[key] = dev_info[key]
1042 target['devices'][dev_uuid][1]['other_config'] = other_config
1045 if 'console_refs' not in target:
1046 target['console_refs'] = []
1048 # Treat VFB devices as console devices so they are found
1049 # through Xen API
1050 if dev_uuid not in target['console_refs']:
1051 target['console_refs'].append(dev_uuid)
1053 elif dev_type == 'console':
1054 if 'console_refs' not in target:
1055 target['console_refs'] = []
1056 if dev_uuid not in target['console_refs']:
1057 target['console_refs'].append(dev_uuid)
1059 return dev_uuid
1061 if cfg_xenapi:
1062 dev_info = {}
1063 dev_uuid = ''
1064 if dev_type == 'vif':
1065 if cfg_xenapi.get('MAC'): # don't add if blank
1066 dev_info['mac'] = cfg_xenapi.get('MAC')
1067 # vifname is the name on the guest, not dom0
1068 # TODO: we don't have the ability to find that out or
1069 # change it from dom0
1070 #if cfg_xenapi.get('device'): # don't add if blank
1071 # dev_info['vifname'] = cfg_xenapi.get('device')
1072 if cfg_xenapi.get('type'):
1073 dev_info['type'] = cfg_xenapi.get('type')
1074 if cfg_xenapi.get('name'):
1075 dev_info['name'] = cfg_xenapi.get('name')
1077 dev_uuid = cfg_xenapi.get('uuid', None)
1078 if not dev_uuid:
1079 dev_uuid = uuid.createString()
1080 dev_info['uuid'] = dev_uuid
1081 target['devices'][dev_uuid] = (dev_type, dev_info)
1082 target['vif_refs'].append(dev_uuid)
1084 elif dev_type in ('vbd', 'tap'):
1085 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1086 if dev_info['type'] == 'CD':
1087 old_vbd_type = 'cdrom'
1088 else:
1089 old_vbd_type = 'disk'
1091 dev_info['uname'] = cfg_xenapi.get('image', '')
1092 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1093 old_vbd_type)
1094 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1095 dev_info['driver'] = cfg_xenapi.get('driver', '')
1096 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1098 if cfg_xenapi.get('mode') == 'RW':
1099 dev_info['mode'] = 'w'
1100 else:
1101 dev_info['mode'] = 'r'
1103 dev_uuid = cfg_xenapi.get('uuid', None)
1104 if not dev_uuid:
1105 dev_uuid = uuid.createString()
1106 dev_info['uuid'] = dev_uuid
1107 target['devices'][dev_uuid] = (dev_type, dev_info)
1108 target['vbd_refs'].append(dev_uuid)
1110 elif dev_type == 'vtpm':
1111 if cfg_xenapi.get('type'):
1112 dev_info['type'] = cfg_xenapi.get('type')
1114 dev_uuid = cfg_xenapi.get('uuid', None)
1115 if not dev_uuid:
1116 dev_uuid = uuid.createString()
1117 dev_info['uuid'] = dev_uuid
1118 target['devices'][dev_uuid] = (dev_type, dev_info)
1119 target['vtpm_refs'].append(dev_uuid)
1121 elif dev_type == 'console':
1122 dev_uuid = cfg_xenapi.get('uuid', None)
1123 if not dev_uuid:
1124 dev_uuid = uuid.createString()
1125 dev_info['uuid'] = dev_uuid
1126 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1127 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1128 if dev_info['protocol'] == 'rfb':
1129 # collapse other config into devinfo for things
1130 # such as vncpasswd, vncunused, etc.
1131 dev_info.update(cfg_xenapi.get('other_config', {}))
1132 dev_info['type'] = 'vnc'
1133 target['devices'][dev_uuid] = ('vfb', dev_info)
1134 target['console_refs'].append(dev_uuid)
1136 # Finally, if we are a pvfb, we need to make a vkbd
1137 # as well that is not really exposed to Xen API
1138 vkbd_uuid = uuid.createString()
1139 target['devices'][vkbd_uuid] = ('vkbd', {})
1141 elif dev_info['protocol'] == 'vt100':
1142 # if someone tries to create a VT100 console
1143 # via the Xen API, we'll have to ignore it
1144 # because we create one automatically in
1145 # XendDomainInfo._update_consoles
1146 raise XendConfigError('Creating vt100 consoles via '
1147 'Xen API is unsupported')
1149 return dev_uuid
1151 # no valid device to add
1152 return ''
1154 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1155 target = None):
1156 """Add a phantom tap device configuration in XenAPI struct format.
1157 """
1159 if target == None:
1160 target = self
1162 if dev_type not in XendDevices.valid_devices() and \
1163 dev_type not in XendDevices.pseudo_devices():
1164 raise XendConfigError("XendConfig: %s not a valid device type" %
1165 dev_type)
1167 if cfg_xenapi == None:
1168 raise XendConfigError("XendConfig: device_add requires some "
1169 "config.")
1171 if cfg_xenapi:
1172 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1174 if cfg_xenapi:
1175 dev_info = {}
1176 if dev_type in ('vbd', 'tap'):
1177 if dev_type == 'vbd':
1178 dev_info['uname'] = cfg_xenapi.get('image', '')
1179 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1180 elif dev_type == 'tap':
1181 if cfg_xenapi.get('image').find('tap:') == -1:
1182 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1183 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1184 dev_info['uname'] = cfg_xenapi.get('image')
1185 dev_info['mode'] = cfg_xenapi.get('mode')
1186 dev_info['backend'] = '0'
1187 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1188 dev_info['uuid'] = dev_uuid
1189 self['devices'][dev_uuid] = (dev_type, dev_info)
1190 self['vbd_refs'].append(dev_uuid)
1191 return dev_uuid
1193 return ''
1195 def console_add(self, protocol, location, other_config = {}):
1196 dev_uuid = uuid.createString()
1197 if protocol == 'vt100':
1198 dev_info = {
1199 'uuid': dev_uuid,
1200 'protocol': protocol,
1201 'location': location,
1202 'other_config': other_config,
1205 if 'devices' not in self:
1206 self['devices'] = {}
1208 self['devices'][dev_uuid] = ('console', dev_info)
1209 self['console_refs'].append(dev_uuid)
1210 return dev_info
1212 return {}
1214 def console_update(self, console_uuid, key, value):
1215 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1216 if dev_uuid == console_uuid:
1217 dev_info[key] = value
1218 break
1220 def console_get_all(self, protocol):
1221 if protocol == 'vt100':
1222 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1223 if dtype == 'console']
1224 return [c for c in consoles if c.get('protocol') == protocol]
1226 elif protocol == 'rfb':
1227 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1228 if dtype == 'vfb']
1230 # move all non-console key values to other_config before
1231 # returning console config
1232 valid_keys = ['uuid', 'location']
1233 for vfb in vfbs:
1234 other_config = {}
1235 for key, val in vfb.items():
1236 if key not in valid_keys:
1237 other_config[key] = vfb[key]
1238 del vfb[key]
1239 vfb['other_config'] = other_config
1240 vfb['protocol'] = 'rfb'
1242 return vfbs
1244 else:
1245 return []
1247 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1248 """Update an existing device with the new configuration.
1250 @rtype: boolean
1251 @return: Returns True if succesfully found and updated a device conf
1252 """
1253 if dev_uuid in self['devices'] and cfg_sxp:
1254 if sxp.child0(cfg_sxp) == 'device':
1255 config = sxp.child0(cfg_sxp)
1256 else:
1257 config = cfg_sxp
1259 dev_type, dev_info = self['devices'][dev_uuid]
1260 for opt_val in config[1:]:
1261 try:
1262 opt, val = opt_val
1263 dev_info[opt] = val
1264 except (TypeError, ValueError):
1265 pass # no value for this config option
1267 self['devices'][dev_uuid] = (dev_type, dev_info)
1268 return True
1270 elif dev_uuid in self['devices'] and cfg_xenapi:
1271 dev_type, dev_info = self['devices'][dev_uuid]
1272 for key, val in cfg_xenapi.items():
1273 dev_info[key] = val
1274 self['devices'][dev_uuid] = (dev_type, dev_info)
1276 return False
1279 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
1280 """Get Device SXPR by either giving the device UUID or (type, config).
1282 @rtype: list of lists
1283 @return: device config sxpr
1284 """
1285 sxpr = []
1286 if dev_uuid != None and dev_uuid in self['devices']:
1287 dev_type, dev_info = self['devices'][dev_uuid]
1289 if dev_type == None or dev_info == None:
1290 raise XendConfigError("Required either UUID or device type and "
1291 "configuration dictionary.")
1293 sxpr.append(dev_type)
1294 if dev_type in ('console', 'vfb'):
1295 config = [(opt, val) for opt, val in dev_info.items()
1296 if opt != 'other_config']
1297 else:
1298 config = [(opt, val) for opt, val in dev_info.items()]
1300 sxpr += config
1302 return sxpr
1304 def ordered_device_refs(self):
1305 result = (self['console_refs'] +
1306 self['vbd_refs'] +
1307 self['vif_refs'] +
1308 self['vtpm_refs'])
1309 result.extend([u for u in self['devices'].keys() if u not in result])
1310 return result
1312 def all_devices_sxpr(self):
1313 """Returns the SXPR for all devices in the current configuration."""
1314 sxprs = []
1315 pci_devs = []
1317 if 'devices' not in self:
1318 return sxprs
1320 ordered_refs = self.ordered_device_refs()
1321 for dev_uuid in ordered_refs:
1322 dev_type, dev_info = self['devices'][dev_uuid]
1323 if dev_type == 'pci': # special case for pci devices
1324 sxpr = [['uuid', dev_info['uuid']]]
1325 for pci_dev_info in dev_info['devs']:
1326 pci_dev_sxpr = ['dev']
1327 for opt, val in pci_dev_info.items():
1328 pci_dev_sxpr.append([opt, val])
1329 sxpr.append(pci_dev_sxpr)
1330 sxprs.append((dev_type, sxpr))
1331 else:
1332 sxpr = self.device_sxpr(dev_type = dev_type,
1333 dev_info = dev_info)
1334 sxprs.append((dev_type, sxpr))
1336 return sxprs
1338 def image_sxpr(self):
1339 """Returns a backwards compatible image SXP expression that is
1340 used in xenstore's /vm/<uuid>/image value and xm list."""
1341 image = [self['image'].get('type', 'linux')]
1342 if self.has_key('PV_kernel'):
1343 image.append(['kernel', self['PV_kernel']])
1344 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1345 image.append(['ramdisk', self['PV_ramdisk']])
1346 if self.has_key('PV_args') and self['PV_args']:
1347 image.append(['args', self['PV_args']])
1349 for arg, conv in LEGACY_IMAGE_CFG:
1350 if self['image'].has_key(arg):
1351 image.append([arg, self['image'][arg]])
1353 if 'hvm' in self['image']:
1354 for arg, conv in LEGACY_IMAGE_HVM_CFG:
1355 if self['image']['hvm'].get(arg):
1356 image.append([arg, conv(self['image']['hvm'][arg])])
1358 if 'hvm' in self['image'] and 'devices' in self['image']['hvm']:
1359 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
1360 val = self['image']['hvm']['devices'].get(arg)
1361 if val != None:
1362 try:
1363 if conv: val = conv(val)
1364 except (ValueError, TypeError):
1365 if type(val) == bool: val = int(val)
1367 image.append([arg, val])
1369 if 'notes' in self['image']:
1370 image.append(self.notes_sxp(self['image']['notes']))
1372 return image
1374 def update_with_image_sxp(self, image_sxp, bootloader = False):
1375 # Convert Legacy "image" config to Xen API PV_*
1376 # configuration
1377 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1379 # user-specified args must come last: previous releases did this and
1380 # some domU kernels rely upon the ordering.
1381 kernel_args = sxp.child_value(image_sxp, 'args', '')
1383 # attempt to extract extra arguments from SXP config
1384 arg_ip = sxp.child_value(image_sxp, 'ip')
1385 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1386 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1387 arg_root = sxp.child_value(image_sxp, 'root')
1388 if arg_root and not re.search(r'root=', kernel_args):
1389 kernel_args = 'root=%s ' % arg_root + kernel_args
1391 if bootloader:
1392 self['_temp_using_bootloader'] = '1'
1393 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1394 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1395 self['_temp_args'] = kernel_args
1396 else:
1397 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1398 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1399 self['PV_args'] = kernel_args
1401 # Store image SXP in python dictionary format
1402 image = {}
1403 image['type'] = sxp.name(image_sxp)
1404 for arg, conv in LEGACY_IMAGE_CFG:
1405 val = sxp.child_value(image_sxp, arg, None)
1406 if val != None:
1407 image[arg] = conv(val)
1409 image_hvm = {}
1410 for arg, conv in LEGACY_IMAGE_HVM_CFG:
1411 val = sxp.child_value(image_sxp, arg, None)
1412 if val != None:
1413 image_hvm[arg] = conv(val)
1415 image_hvm_devices = {}
1416 for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
1417 val = sxp.child_value(image_sxp, arg, None)
1418 if val != None:
1419 try:
1420 image_hvm_devices[arg] = conv(val)
1421 except (ValueError, TypeError):
1422 image_hvm_devices[arg] = val
1425 if image_hvm or image_hvm_devices:
1426 image['hvm'] = image_hvm
1427 image['hvm']['devices'] = image_hvm_devices
1429 notes = sxp.children(image_sxp, 'notes')
1430 if notes:
1431 image['notes'] = self.notes_from_sxp(notes[0])
1433 self['image'] = image
1435 for apikey, imgkey in XENAPI_HVM_CFG.items():
1436 val = sxp.child_value(image_sxp, imgkey, None)
1437 if val != None:
1438 type_conv = XENAPI_CFG_TYPES[apikey]
1439 if callable(type_conv):
1440 self[apikey] = type_conv(val)
1441 else:
1442 self[apikey] = val
1443 self._hvm_boot_params_from_sxp(image_sxp)
1445 def set_notes(self, notes):
1446 'Add parsed elfnotes to image'
1447 self['image']['notes'] = notes
1449 def get_notes(self):
1450 try:
1451 return self['image']['notes'] or {}
1452 except KeyError:
1453 return {}
1455 def notes_from_sxp(self, nsxp):
1456 notes = {}
1457 for note in sxp.children(nsxp):
1458 notes[note[0]] = note[1]
1459 return notes
1461 def notes_sxp(self, notes):
1462 nsxp = ['notes']
1463 for k, v in notes.iteritems():
1464 nsxp.append([k, str(v)])
1465 return nsxp
1467 def _hvm_boot_params_from_sxp(self, image_sxp):
1468 boot = sxp.child_value(image_sxp, 'boot', None)
1469 if boot is not None:
1470 self['HVM_boot_policy'] = 'BIOS order'
1471 self['HVM_boot_params'] = { 'order' : boot }
1475 # debugging
1478 if __name__ == "__main__":
1479 pass