direct-io.hg

view tools/python/xen/xend/XendConfig.py @ 14588:681ed46676a6

Fix 'xm list' long output to skip legacy 'cpus'.
Fixes bugzilla report #935.
Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Tue Mar 27 16:45:37 2007 +0100 (2007-03-27)
parents 2c1556c893e7
children ea68ae90fc10
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-2007 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.WARN)
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 v != 'False' 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_max -- 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 # VCPUs_live -- 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_max': 'vcpus',
107 'cpus': 'cpus',
108 'name_label': 'name',
109 'actions_after_shutdown': 'on_poweroff',
110 'actions_after_reboot': 'on_reboot',
111 'actions_after_crash': 'on_crash',
112 'PV_bootloader': 'bootloader',
113 'PV_bootloader_args': 'bootloader_args',
114 }
116 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
118 # Platform configuration keys.
119 XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display',
120 'fda', 'fdb', 'keymap', 'isa', 'localtime',
121 'nographic', 'pae', 'serial', 'sdl',
122 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc',
123 'vncconsole', 'vncdisplay', 'vnclisten',
124 'vncpasswd', 'vncunused', 'xauthority']
126 # List of XendConfig configuration keys that have no direct equivalent
127 # in the old world.
129 XENAPI_CFG_TYPES = {
130 'uuid': str,
131 'name_label': str,
132 'name_description': str,
133 'user_version': str,
134 'is_a_template': bool0,
135 'resident_on': str,
136 'memory_static_min': int, # note these are stored in bytes, not KB!
137 'memory_static_max': int,
138 'memory_dynamic_min': int,
139 'memory_dynamic_max': int,
140 'cpus': list,
141 'vcpus_params': dict,
142 'VCPUs_max': int,
143 'VCPUs_at_startup': int,
144 'VCPUs_live': int,
145 'actions_after_shutdown': str,
146 'actions_after_reboot': str,
147 'actions_after_crash': str,
148 'PV_bootloader': str,
149 'PV_kernel': str,
150 'PV_ramdisk': str,
151 'PV_args': str,
152 'PV_bootloader_args': str,
153 'HVM_boot_policy': str,
154 'HVM_boot_params': dict,
155 'PCI_bus': str,
156 'platform': dict,
157 'tools_version': dict,
158 'other_config': dict,
159 }
161 # List of legacy configuration keys that have no equivalent in the
162 # Xen API, but are still stored in XendConfig.
164 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
165 # roundtripped (dynamic, unmodified)
166 'shadow_memory',
167 'security',
168 'vcpu_avail',
169 'cpu_weight',
170 'cpu_cap',
171 'features',
172 # read/write
173 'on_xend_start',
174 'on_xend_stop',
175 # read-only
176 'domid',
177 'start_time',
178 'cpu_time',
179 'online_vcpus',
180 # write-once
181 'cpu',
182 'cpus',
183 ]
185 LEGACY_CFG_TYPES = {
186 'uuid': str,
187 'name': str,
188 'vcpus': int,
189 'vcpu_avail': long,
190 'memory': int,
191 'shadow_memory': int,
192 'maxmem': int,
193 'start_time': float,
194 'cpu_cap': int,
195 'cpu_weight': int,
196 'cpu_time': float,
197 'features': str,
198 'localtime': int,
199 'name': str,
200 'on_poweroff': str,
201 'on_reboot': str,
202 'on_crash': str,
203 'on_xend_stop': str,
204 'on_xend_start': str,
205 'online_vcpus': int,
206 }
208 # Values that should be stored in xenstore's /vm/<uuid> that is used
209 # by Xend. Used in XendDomainInfo to restore running VM state from
210 # xenstore.
211 LEGACY_XENSTORE_VM_PARAMS = [
212 'uuid',
213 'name',
214 'vcpus',
215 'vcpu_avail',
216 'memory',
217 'shadow_memory',
218 'maxmem',
219 'start_time',
220 'name',
221 'on_poweroff',
222 'on_crash',
223 'on_reboot',
224 'on_xend_start',
225 'on_xend_stop',
226 ]
228 DEFAULT_DM = '/usr/lib/xen/bin/qemu-dm'
230 ##
231 ## Config Choices
232 ##
234 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
235 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
236 'crashed', 'dying')
238 class XendConfigError(VmError):
239 def __str__(self):
240 return 'Invalid Configuration: %s' % str(self.value)
242 ##
243 ## XendConfig Class (an extended dictionary)
244 ##
246 class XendConfig(dict):
247 """ The new Xend VM Configuration.
249 Stores the configuration in xenapi compatible format but retains
250 import and export functions for SXP.
251 """
252 def __init__(self, filename = None, sxp_obj = None,
253 xapi = None, dominfo = None):
255 dict.__init__(self)
256 self.update(self._defaults())
258 if filename:
259 try:
260 sxp_obj = sxp.parse(open(filename,'r'))
261 sxp_obj = sxp_obj[0]
262 except IOError, e:
263 raise XendConfigError("Unable to read file: %s" % filename)
265 if sxp_obj:
266 self._sxp_to_xapi(sxp_obj)
267 self._sxp_to_xapi_unsupported(sxp_obj)
268 elif xapi:
269 self.update_with_xenapi_config(xapi)
270 elif dominfo:
271 # output from xc.domain_getinfo
272 self._dominfo_to_xapi(dominfo, update_mem = True)
274 log.debug('XendConfig.init: %s' % scrub_password(self))
276 # validators go here
277 self.validate()
279 """ In time, we should enable this type checking addition. It is great
280 also for tracking bugs and unintended writes to XendDomainInfo.info
281 def __setitem__(self, key, value):
282 type_conv = XENAPI_CFG_TYPES.get(key)
283 if callable(type_conv):
284 try:
285 dict.__setitem__(self, key, type_conv(value))
286 except (ValueError, TypeError):
287 raise XendConfigError("Wrong type for configuration value " +
288 "%s. Expected %s" %
289 (key, type_conv.__name__))
290 else:
291 dict.__setitem__(self, key, value)
292 """
294 def _defaults(self):
295 defaults = {
296 'name_label': 'Domain-Unnamed',
297 'actions_after_shutdown': 'destroy',
298 'actions_after_reboot': 'restart',
299 'actions_after_crash': 'restart',
300 'actions_after_suspend': '',
301 'is_a_template': False,
302 'is_control_domain': False,
303 'features': '',
304 'PV_bootloader': '',
305 'PV_kernel': '',
306 'PV_ramdisk': '',
307 'PV_args': '',
308 'PV_bootloader_args': '',
309 'HVM_boot_policy': '',
310 'HVM_boot_params': {},
311 'memory_static_min': 0,
312 'memory_dynamic_min': 0,
313 'shadow_memory': 0,
314 'memory_static_max': 0,
315 'memory_dynamic_max': 0,
316 'devices': {},
317 'security': None,
318 'on_xend_start': 'ignore',
319 'on_xend_stop': 'ignore',
320 'cpus': [],
321 'cpu_weight': 256,
322 'cpu_cap': 0,
323 'VCPUs_max': 1,
324 'VCPUs_live': 1,
325 'VCPUs_at_startup': 1,
326 'vcpus_params': {},
327 'console_refs': [],
328 'vif_refs': [],
329 'vbd_refs': [],
330 'vtpm_refs': [],
331 'other_config': {},
332 'platform': {}
333 }
335 return defaults
337 #
338 # Here we assume these values exist in the dict.
339 # If they don't we have a bigger problem, lets not
340 # try and 'fix it up' but acutually fix the cause ;-)
341 #
342 def _memory_sanity_check(self):
343 log.debug("_memory_sanity_check memory_static_min: %s, "
344 "memory_static_max: %i, "
345 "memory_dynamic_min: %i, "
346 "memory_dynamic_max: %i",
347 self["memory_static_min"],
348 self["memory_static_max"],
349 self["memory_dynamic_min"],
350 self["memory_dynamic_max"])
352 if not self["memory_static_min"] <= self["memory_static_max"]:
353 raise XendConfigError("memory_static_min must be less " \
354 "than or equal to memory_static_max")
355 if not self["memory_dynamic_min"] <= self["memory_dynamic_max"]:
356 raise XendConfigError("memory_dynamic_min must be less " \
357 "than or equal to memory_dynamic_max")
358 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
359 raise XendConfigError("memory_static_min must be less " \
360 "than or equal to memory_dynamic_min")
361 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
362 raise XendConfigError("memory_dynamic_max must be less " \
363 "than or equal to memory_static_max")
364 if not self["memory_dynamic_max"] > 0:
365 raise XendConfigError("memory_dynamic_max must be greater " \
366 "than zero")
367 if not self["memory_static_max"] > 0:
368 raise XendConfigError("memory_static_max must be greater " \
369 "than zero")
371 def _actions_sanity_check(self):
372 for event in ['shutdown', 'reboot', 'crash']:
373 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
374 raise XendConfigError('Invalid event handling mode: ' +
375 event)
377 def _vcpus_sanity_check(self):
378 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
379 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
381 def _uuid_sanity_check(self):
382 """Make sure UUID is in proper string format with hyphens."""
383 if 'uuid' not in self or not self['uuid']:
384 self['uuid'] = uuid.createString()
385 else:
386 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
388 def _name_sanity_check(self):
389 if 'name_label' not in self:
390 self['name_label'] = 'Domain-' + self['uuid']
392 def _platform_sanity_check(self):
393 if self.is_hvm():
394 if 'device_model' not in self['platform']:
395 self['platform']['device_model'] = DEFAULT_DM
397 # Compatibility hack, can go away soon.
398 if 'soundhw' not in self['platform'] and \
399 self['platform'].get('enable_audio'):
400 self['platform']['soundhw'] = 'sb16'
402 def validate(self):
403 self._uuid_sanity_check()
404 self._name_sanity_check()
405 self._memory_sanity_check()
406 self._actions_sanity_check()
407 self._vcpus_sanity_check()
408 self._platform_sanity_check()
410 def _dominfo_to_xapi(self, dominfo, update_mem = False):
411 self['domid'] = dominfo['domid']
412 self['online_vcpus'] = dominfo['online_vcpus']
413 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
415 if update_mem:
416 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
417 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
418 self['memory_static_min'] = 0
419 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
420 self._memory_sanity_check()
422 self['cpu_time'] = dominfo['cpu_time']/1e9
423 # TODO: i don't know what the security stuff expects here
424 if dominfo.get('ssidref'):
425 self['security'] = [['ssidref', dominfo['ssidref']]]
426 self['shutdown_reason'] = dominfo['shutdown_reason']
428 # parse state into Xen API states
429 self['running'] = dominfo['running']
430 self['crashed'] = dominfo['crashed']
431 self['dying'] = dominfo['dying']
432 self['shutdown'] = dominfo['shutdown']
433 self['paused'] = dominfo['paused']
434 self['blocked'] = dominfo['blocked']
436 if 'name' in dominfo:
437 self['name_label'] = dominfo['name']
439 if 'handle' in dominfo:
440 self['uuid'] = uuid.toString(dominfo['handle'])
442 def _parse_sxp(self, sxp_cfg):
443 """ Populate this XendConfig using the parsed SXP.
445 @param sxp_cfg: Parsed SXP Configuration
446 @type sxp_cfg: list of lists
447 @rtype: dictionary
448 @return: A dictionary containing the parsed options of the SXP.
449 """
450 cfg = {}
452 for key, typ in XENAPI_CFG_TYPES.items():
453 val = sxp.child_value(sxp_cfg, key)
454 if val is not None:
455 cfg[key] = typ(val)
457 # Convert deprecated options to current equivalents.
459 restart = sxp.child_value(sxp_cfg, 'restart')
460 if restart:
461 if restart == 'onreboot':
462 cfg['on_poweroff'] = 'destroy'
463 cfg['on_reboot'] = 'restart'
464 cfg['on_crash'] = 'destroy'
465 elif restart == 'always':
466 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
467 cfg[opt] = 'restart'
468 elif restart == 'never':
469 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
470 cfg[opt] = 'never'
471 else:
472 log.warn('Ignoring unrecognised value for deprecated option:'
473 'restart = \'%s\'', restart)
475 # Handle memory, passed in as MiB
477 if sxp.child_value(sxp_cfg, "memory") != None:
478 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
479 if sxp.child_value(sxp_cfg, "maxmem") != None:
480 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
482 # Only extract options we know about.
483 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
484 extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
486 for key in extract_keys:
487 val = sxp.child_value(sxp_cfg, key)
488 if val != None:
489 try:
490 cfg[key] = LEGACY_CFG_TYPES[key](val)
491 except KeyError:
492 cfg[key] = val
493 except (TypeError, ValueError), e:
494 log.warn("Unable to parse key %s: %s: %s" %
495 (key, str(val), e))
497 if 'platform' not in cfg:
498 cfg['platform'] = {}
499 localtime = sxp.child_value(sxp_cfg, 'localtime')
500 if localtime is not None:
501 cfg['platform']['localtime'] = localtime
503 # Compatibility hack -- can go soon.
504 for key in XENAPI_PLATFORM_CFG:
505 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
506 if val is not None:
507 self['platform'][key] = val
509 # Compatibility hack -- can go soon.
510 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
511 if boot_order:
512 cfg['HVM_boot_policy'] = 'BIOS order'
513 cfg['HVM_boot_params'] = { 'order' : boot_order }
515 # Parsing the device SXP's. In most cases, the SXP looks
516 # like this:
517 #
518 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
519 #
520 # However, for PCI devices it looks like this:
521 #
522 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
523 #
524 # It seems the reasoning for this difference is because
525 # pciif.py needs all the PCI device configurations at
526 # the same time when creating the devices.
527 #
528 # To further complicate matters, Xen 2.0 configuration format
529 # uses the following for pci device configuration:
530 #
531 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
532 #
533 # Hence we deal with pci device configurations outside of
534 # the regular device parsing.
536 cfg['devices'] = {}
537 for dev in sxp.children(sxp_cfg, 'device'):
538 config = sxp.child0(dev)
539 dev_type = sxp.name(config)
540 dev_info = {}
542 if dev_type == 'pci':
543 pci_devs_uuid = sxp.child_value(config, 'uuid',
544 uuid.createString())
545 pci_devs = []
546 for pci_dev in sxp.children(config, 'dev'):
547 pci_dev_info = {}
548 for opt_val in pci_dev[1:]:
549 try:
550 opt, val = opt_val
551 pci_dev_info[opt] = val
552 except TypeError:
553 pass
554 pci_devs.append(pci_dev_info)
556 cfg['devices'][pci_devs_uuid] = (dev_type,
557 {'devs': pci_devs,
558 'uuid': pci_devs_uuid})
560 log.debug("XendConfig: reading device: %s" % pci_devs)
561 else:
562 self.device_add(dev_type, cfg_sxp = config, target = cfg)
563 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
565 # Extract missing data from configuration entries
566 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
567 if image_sxp:
568 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
569 if image_vcpus != None:
570 try:
571 if 'VCPUs_max' not in cfg:
572 cfg['VCPUs_max'] = int(image_vcpus)
573 elif cfg['VCPUs_max'] != int(image_vcpus):
574 cfg['VCPUs_max'] = int(image_vcpus)
575 log.warn('Overriding vcpus from %d to %d using image'
576 'vcpus value.', cfg['VCPUs_max'])
577 except ValueError, e:
578 raise XendConfigError('integer expeceted: %s: %s' %
579 image_sxp, e)
581 # Deprecated cpu configuration
582 if 'cpu' in cfg:
583 if 'cpus' in cfg:
584 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
585 else:
586 cfg['cpus'] = str(cfg['cpu'])
588 # convert 'cpus' string to list of ints
589 # 'cpus' supports a list of ranges (0-3), seperated by
590 # commas, and negation, (^1).
591 # Precedence is settled by order of the string:
592 # "0-3,^1" -> [0,2,3]
593 # "0-3,^1,1" -> [0,1,2,3]
594 try:
595 if 'cpus' in cfg and type(cfg['cpus']) != list:
596 cpus = []
597 for c in cfg['cpus'].split(','):
598 if c.find('-') != -1:
599 (x, y) = c.split('-')
600 for i in range(int(x), int(y)+1):
601 cpus.append(int(i))
602 else:
603 # remove this element from the list
604 if c[0] == '^':
605 cpus = [x for x in cpus if x != int(c[1:])]
606 else:
607 cpus.append(int(c))
609 cfg['cpus'] = cpus
610 except ValueError, e:
611 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
613 if 'security' in cfg and isinstance(cfg['security'], str):
614 cfg['security'] = sxp.from_string(cfg['security'])
616 old_state = sxp.child_value(sxp_cfg, 'state')
617 if old_state:
618 for i in range(len(CONFIG_OLD_DOM_STATES)):
619 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
621 return cfg
624 def _sxp_to_xapi(self, sxp_cfg):
625 """Read in an SXP Configuration object and
626 populate at much of the Xen API with valid values.
627 """
628 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
630 cfg = self._parse_sxp(sxp_cfg)
632 for key, typ in XENAPI_CFG_TYPES.items():
633 val = cfg.get(key)
634 if val is not None:
635 self[key] = typ(val)
637 # Convert parameters that can be directly mapped from
638 # the Legacy Config to Xen API Config
640 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
641 try:
642 type_conv = XENAPI_CFG_TYPES.get(apikey)
643 if callable(type_conv):
644 self[apikey] = type_conv(cfg[cfgkey])
645 else:
646 log.warn("Unconverted key: " + apikey)
647 self[apikey] = cfg[cfgkey]
648 except KeyError:
649 pass
651 # Lets try and handle memory correctly
653 MiB = 1024 * 1024
655 if "memory" in cfg:
656 self["memory_static_min"] = 0
657 self["memory_static_max"] = int(cfg["memory"]) * MiB
658 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
659 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
661 if "maxmem" in cfg:
662 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
664 self._memory_sanity_check()
666 def update_with(n, o):
667 if not self.get(n):
668 self[n] = cfg.get(o, '')
670 update_with('PV_bootloader', 'bootloader')
671 update_with('PV_bootloader_args', 'bootloader_args')
673 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
674 if image_sxp:
675 self.update_with_image_sxp(image_sxp)
677 # Convert Legacy HVM parameters to Xen API configuration
678 for key in XENAPI_PLATFORM_CFG:
679 if key in cfg:
680 self['platform'][key] = cfg[key]
682 # set device references in the configuration
683 self['devices'] = cfg.get('devices', {})
684 self['console_refs'] = cfg.get('console_refs', [])
685 self['vif_refs'] = cfg.get('vif_refs', [])
686 self['vbd_refs'] = cfg.get('vbd_refs', [])
687 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
689 # coalesce hvm vnc frame buffer with vfb config
690 if self.is_hvm() and self['platform'].get('vnc', 0):
691 # add vfb device if it isn't there already
692 has_rfb = False
693 for console_uuid in self['console_refs']:
694 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
695 has_rfb = True
696 break
697 if self['devices'][console_uuid][0] == 'vfb':
698 has_rfb = True
699 break
701 if not has_rfb:
702 dev_config = ['vfb']
703 # copy VNC related params from platform config to vfb dev conf
704 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
705 'vnclisten']:
706 if key in self['platform']:
707 dev_config.append([key, self['platform'][key]])
709 self.device_add('vfb', cfg_sxp = dev_config)
712 def _sxp_to_xapi_unsupported(self, sxp_cfg):
713 """Read in an SXP configuration object and populate
714 values are that not related directly supported in
715 the Xen API.
716 """
718 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
720 # Parse and convert parameters used to configure
721 # the image (as well as HVM images)
722 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
723 if image_sxp:
724 image_type = sxp.name(image_sxp)
725 if image_type != 'hvm' and image_type != 'linux':
726 self['platform']['image_type'] = image_type
728 for key in XENAPI_PLATFORM_CFG:
729 val = sxp.child_value(image_sxp, key, None)
730 if val is not None:
731 self['platform'][key] = val
733 notes = sxp.children(image_sxp, 'notes')
734 if notes:
735 self['notes'] = self.notes_from_sxp(notes[0])
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 _get_old_state_string(self):
773 """Returns the old xm state string.
774 @rtype: string
775 @return: old state string
776 """
777 state_string = ''
778 for state_name in CONFIG_OLD_DOM_STATES:
779 on_off = self.get(state_name, 0)
780 if on_off:
781 state_string += state_name[0]
782 else:
783 state_string += '-'
785 return state_string
788 def update_config(self, dominfo):
789 """Update configuration with the output from xc.domain_getinfo().
791 @param dominfo: Domain information via xc.domain_getinfo()
792 @type dominfo: dict
793 """
794 self._dominfo_to_xapi(dominfo)
795 self.validate()
797 def update_with_xenapi_config(self, xapi):
798 """Update configuration with a Xen API VM struct
800 @param xapi: Xen API VM Struct
801 @type xapi: dict
802 """
804 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
806 for key, val in xapi.items():
807 type_conv = XENAPI_CFG_TYPES.get(key)
808 if type_conv is None:
809 key = key.lower()
810 type_conv = XENAPI_CFG_TYPES.get(key)
811 if callable(type_conv):
812 self[key] = type_conv(val)
813 else:
814 self[key] = val
816 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
817 legacy_only = True):
818 """ Get SXP representation of this config object.
820 Incompat: removed store_mfn, console_mfn
822 @keyword domain: (optional) XendDomainInfo to get extra information
823 from such as domid and running devices.
824 @type domain: XendDomainInfo
825 @keyword ignore: (optional) list of 'keys' that we do not want
826 to export.
827 @type ignore: list of strings
828 @rtype: list of list (SXP representation)
829 """
830 sxpr = ['domain']
832 # TODO: domid/dom is the same thing but called differently
833 # depending if it is from xenstore or sxpr.
835 if domain.getDomid() is not None:
836 sxpr.append(['domid', domain.getDomid()])
838 if not legacy_only:
839 for name, typ in XENAPI_CFG_TYPES.items():
840 if name in self and self[name] not in (None, []):
841 if typ == dict:
842 s = self[name].items()
843 else:
844 s = str(self[name])
845 sxpr.append([name, s])
847 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
848 if legacy in ('cpus'): # skip this
849 continue
850 if self.has_key(xenapi) and self[xenapi] not in (None, []):
851 if type(self[xenapi]) == bool:
852 # convert booleans to ints before making an sxp item
853 sxpr.append([legacy, int(self[xenapi])])
854 else:
855 sxpr.append([legacy, self[xenapi]])
857 MiB = 1024*1024
859 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
860 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
862 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
863 if legacy in ('domid', 'uuid', 'cpus'): # skip these
864 continue
865 if self.has_key(legacy) and self[legacy] not in (None, []):
866 sxpr.append([legacy, self[legacy]])
868 sxpr.append(['image', self.image_sxpr()])
869 sxpr.append(['status', domain.state])
871 if domain.getDomid() is not None:
872 sxpr.append(['state', self._get_old_state_string()])
874 if domain:
875 if domain.store_mfn:
876 sxpr.append(['store_mfn', domain.store_mfn])
877 if domain.console_mfn:
878 sxpr.append(['console_mfn', domain.console_mfn])
881 # Marshall devices (running or from configuration)
882 if not ignore_devices:
883 for cls in XendDevices.valid_devices():
884 found = False
886 # figure if there is a dev controller is valid and running
887 if domain and domain.getDomid() != None:
888 try:
889 controller = domain.getDeviceController(cls)
890 configs = controller.configurations()
891 for config in configs:
892 if sxp.name(config) in ('vbd', 'tap'):
893 # The bootable flag is never written to the
894 # store as part of the device config.
895 dev_uuid = sxp.child_value(config, 'uuid')
896 dev_type, dev_cfg = self['devices'][dev_uuid]
897 is_bootable = dev_cfg.get('bootable', 0)
898 config.append(['bootable', int(is_bootable)])
900 sxpr.append(['device', config])
902 found = True
903 except:
904 log.exception("dumping sxp from device controllers")
905 pass
907 # if we didn't find that device, check the existing config
908 # for a device in the same class
909 if not found:
910 for dev_type, dev_info in self.all_devices_sxpr():
911 if dev_type == cls:
912 sxpr.append(['device', dev_info])
914 return sxpr
916 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
917 target = None):
918 """Add a device configuration in SXP format or XenAPI struct format.
920 For SXP, it could be either:
922 [device, [vbd, [uname ...]]
924 or:
926 [vbd, [uname ..]]
928 @type cfg_sxp: list of lists (parsed sxp object)
929 @param cfg_sxp: SXP configuration object
930 @type cfg_xenapi: dict
931 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
932 @param target: write device information to
933 @type target: None or a dictionary
934 @rtype: string
935 @return: Assigned UUID of the device.
936 """
937 if target == None:
938 target = self
940 if dev_type not in XendDevices.valid_devices():
941 raise XendConfigError("XendConfig: %s not a valid device type" %
942 dev_type)
944 if cfg_sxp == None and cfg_xenapi == None:
945 raise XendConfigError("XendConfig: device_add requires some "
946 "config.")
948 #if cfg_sxp:
949 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
950 #if cfg_xenapi:
951 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
953 if cfg_sxp:
954 if sxp.child0(cfg_sxp) == 'device':
955 config = sxp.child0(cfg_sxp)
956 else:
957 config = cfg_sxp
959 dev_type = sxp.name(config)
960 dev_info = {}
962 for opt_val in config[1:]:
963 try:
964 opt, val = opt_val
965 dev_info[opt] = val
966 except (TypeError, ValueError): # unpack error
967 pass
969 if dev_type == 'vbd':
970 dev_info['bootable'] = 0
971 if dev_info.get('dev', '').startswith('ioemu:'):
972 dev_info['driver'] = 'ioemu'
973 else:
974 dev_info['driver'] = 'paravirtualised'
976 # create uuid if it doesn't exist
977 dev_uuid = dev_info.get('uuid', None)
978 if not dev_uuid:
979 dev_uuid = uuid.createString()
980 dev_info['uuid'] = dev_uuid
982 # store dev references by uuid for certain device types
983 target['devices'][dev_uuid] = (dev_type, dev_info)
984 if dev_type in ('vif', 'vbd', 'vtpm'):
985 param = '%s_refs' % dev_type
986 if param not in target:
987 target[param] = []
988 if dev_uuid not in target[param]:
989 if dev_type == 'vbd' and not target[param]:
990 # Compat hack -- this is the first disk, so mark it
991 # bootable.
992 dev_info['bootable'] = 1
993 target[param].append(dev_uuid)
994 elif dev_type == 'tap':
995 if 'vbd_refs' not in target:
996 target['vbd_refs'] = []
997 if dev_uuid not in target['vbd_refs']:
998 if not target['vbd_refs']:
999 # Compat hack -- this is the first disk, so mark it
1000 # bootable.
1001 dev_info['bootable'] = 1
1002 target['vbd_refs'].append(dev_uuid)
1004 elif dev_type == 'vfb':
1005 # Populate other config with aux data that is associated
1006 # with vfb
1008 other_config = {}
1009 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1010 'vncpasswd', 'type', 'display', 'xauthority',
1011 'keymap']:
1012 if key in dev_info:
1013 other_config[key] = dev_info[key]
1014 target['devices'][dev_uuid][1]['other_config'] = other_config
1017 if 'console_refs' not in target:
1018 target['console_refs'] = []
1020 # Treat VFB devices as console devices so they are found
1021 # through Xen API
1022 if dev_uuid not in target['console_refs']:
1023 target['console_refs'].append(dev_uuid)
1025 elif dev_type == 'console':
1026 if 'console_refs' not in target:
1027 target['console_refs'] = []
1028 if dev_uuid not in target['console_refs']:
1029 target['console_refs'].append(dev_uuid)
1031 return dev_uuid
1033 if cfg_xenapi:
1034 dev_info = {}
1035 dev_uuid = ''
1036 if dev_type == 'vif':
1037 if cfg_xenapi.get('MAC'): # don't add if blank
1038 dev_info['mac'] = cfg_xenapi.get('MAC')
1039 # vifname is the name on the guest, not dom0
1040 # TODO: we don't have the ability to find that out or
1041 # change it from dom0
1042 #if cfg_xenapi.get('device'): # don't add if blank
1043 # dev_info['vifname'] = cfg_xenapi.get('device')
1044 if cfg_xenapi.get('type'):
1045 dev_info['type'] = cfg_xenapi.get('type')
1046 if cfg_xenapi.get('name'):
1047 dev_info['name'] = cfg_xenapi.get('name')
1049 dev_uuid = cfg_xenapi.get('uuid', None)
1050 if not dev_uuid:
1051 dev_uuid = uuid.createString()
1052 dev_info['uuid'] = dev_uuid
1053 target['devices'][dev_uuid] = (dev_type, dev_info)
1054 target['vif_refs'].append(dev_uuid)
1056 elif dev_type in ('vbd', 'tap'):
1057 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1058 if dev_info['type'] == 'CD':
1059 old_vbd_type = 'cdrom'
1060 else:
1061 old_vbd_type = 'disk'
1063 dev_info['uname'] = cfg_xenapi.get('image', '')
1064 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1065 old_vbd_type)
1066 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1067 dev_info['driver'] = cfg_xenapi.get('driver', '')
1068 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1070 if cfg_xenapi.get('mode') == 'RW':
1071 dev_info['mode'] = 'w'
1072 else:
1073 dev_info['mode'] = 'r'
1075 dev_uuid = cfg_xenapi.get('uuid', None)
1076 if not dev_uuid:
1077 dev_uuid = uuid.createString()
1078 dev_info['uuid'] = dev_uuid
1079 target['devices'][dev_uuid] = (dev_type, dev_info)
1080 target['vbd_refs'].append(dev_uuid)
1082 elif dev_type == 'vtpm':
1083 if cfg_xenapi.get('type'):
1084 dev_info['type'] = cfg_xenapi.get('type')
1086 dev_uuid = cfg_xenapi.get('uuid', None)
1087 if not dev_uuid:
1088 dev_uuid = uuid.createString()
1089 dev_info['uuid'] = dev_uuid
1090 target['devices'][dev_uuid] = (dev_type, dev_info)
1091 target['vtpm_refs'].append(dev_uuid)
1093 elif dev_type == 'console':
1094 dev_uuid = cfg_xenapi.get('uuid', None)
1095 if not dev_uuid:
1096 dev_uuid = uuid.createString()
1097 dev_info['uuid'] = dev_uuid
1098 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1099 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1100 if dev_info['protocol'] == 'rfb':
1101 # collapse other config into devinfo for things
1102 # such as vncpasswd, vncunused, etc.
1103 dev_info.update(cfg_xenapi.get('other_config', {}))
1104 dev_info['type'] = 'vnc'
1105 target['devices'][dev_uuid] = ('vfb', dev_info)
1106 target['console_refs'].append(dev_uuid)
1108 # Finally, if we are a pvfb, we need to make a vkbd
1109 # as well that is not really exposed to Xen API
1110 vkbd_uuid = uuid.createString()
1111 target['devices'][vkbd_uuid] = ('vkbd', {})
1113 elif dev_info['protocol'] == 'vt100':
1114 # if someone tries to create a VT100 console
1115 # via the Xen API, we'll have to ignore it
1116 # because we create one automatically in
1117 # XendDomainInfo._update_consoles
1118 raise XendConfigError('Creating vt100 consoles via '
1119 'Xen API is unsupported')
1121 return dev_uuid
1123 # no valid device to add
1124 return ''
1126 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1127 target = None):
1128 """Add a phantom tap device configuration in XenAPI struct format.
1129 """
1131 if target == None:
1132 target = self
1134 if dev_type not in XendDevices.valid_devices() and \
1135 dev_type not in XendDevices.pseudo_devices():
1136 raise XendConfigError("XendConfig: %s not a valid device type" %
1137 dev_type)
1139 if cfg_xenapi == None:
1140 raise XendConfigError("XendConfig: device_add requires some "
1141 "config.")
1143 if cfg_xenapi:
1144 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1146 if cfg_xenapi:
1147 dev_info = {}
1148 if dev_type in ('vbd', 'tap'):
1149 if dev_type == 'vbd':
1150 dev_info['uname'] = cfg_xenapi.get('image', '')
1151 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1152 elif dev_type == 'tap':
1153 if cfg_xenapi.get('image').find('tap:') == -1:
1154 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1155 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1156 dev_info['uname'] = cfg_xenapi.get('image')
1157 dev_info['mode'] = cfg_xenapi.get('mode')
1158 dev_info['backend'] = '0'
1159 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1160 dev_info['uuid'] = dev_uuid
1161 self['devices'][dev_uuid] = (dev_type, dev_info)
1162 self['vbd_refs'].append(dev_uuid)
1163 return dev_uuid
1165 return ''
1167 def console_add(self, protocol, location, other_config = {}):
1168 dev_uuid = uuid.createString()
1169 if protocol == 'vt100':
1170 dev_info = {
1171 'uuid': dev_uuid,
1172 'protocol': protocol,
1173 'location': location,
1174 'other_config': other_config,
1177 if 'devices' not in self:
1178 self['devices'] = {}
1180 self['devices'][dev_uuid] = ('console', dev_info)
1181 self['console_refs'].append(dev_uuid)
1182 return dev_info
1184 return {}
1186 def console_update(self, console_uuid, key, value):
1187 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1188 if dev_uuid == console_uuid:
1189 dev_info[key] = value
1190 break
1192 def console_get_all(self, protocol):
1193 if protocol == 'vt100':
1194 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1195 if dtype == 'console']
1196 return [c for c in consoles if c.get('protocol') == protocol]
1198 elif protocol == 'rfb':
1199 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1200 if dtype == 'vfb']
1202 # move all non-console key values to other_config before
1203 # returning console config
1204 valid_keys = ['uuid', 'location']
1205 for vfb in vfbs:
1206 other_config = {}
1207 for key, val in vfb.items():
1208 if key not in valid_keys:
1209 other_config[key] = vfb[key]
1210 del vfb[key]
1211 vfb['other_config'] = other_config
1212 vfb['protocol'] = 'rfb'
1214 return vfbs
1216 else:
1217 return []
1219 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1220 """Update an existing device with the new configuration.
1222 @rtype: boolean
1223 @return: Returns True if succesfully found and updated a device conf
1224 """
1225 if dev_uuid in self['devices'] and cfg_sxp:
1226 if sxp.child0(cfg_sxp) == 'device':
1227 config = sxp.child0(cfg_sxp)
1228 else:
1229 config = cfg_sxp
1231 dev_type, dev_info = self['devices'][dev_uuid]
1232 for opt_val in config[1:]:
1233 try:
1234 opt, val = opt_val
1235 dev_info[opt] = val
1236 except (TypeError, ValueError):
1237 pass # no value for this config option
1239 self['devices'][dev_uuid] = (dev_type, dev_info)
1240 return True
1242 elif dev_uuid in self['devices'] and cfg_xenapi:
1243 dev_type, dev_info = self['devices'][dev_uuid]
1244 for key, val in cfg_xenapi.items():
1245 dev_info[key] = val
1246 self['devices'][dev_uuid] = (dev_type, dev_info)
1248 return False
1251 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
1252 """Get Device SXPR by either giving the device UUID or (type, config).
1254 @rtype: list of lists
1255 @return: device config sxpr
1256 """
1257 sxpr = []
1258 if dev_uuid != None and dev_uuid in self['devices']:
1259 dev_type, dev_info = self['devices'][dev_uuid]
1261 if dev_type == None or dev_info == None:
1262 raise XendConfigError("Required either UUID or device type and "
1263 "configuration dictionary.")
1265 sxpr.append(dev_type)
1266 if dev_type in ('console', 'vfb'):
1267 config = [(opt, val) for opt, val in dev_info.items()
1268 if opt != 'other_config']
1269 else:
1270 config = [(opt, val) for opt, val in dev_info.items()]
1272 sxpr += config
1274 return sxpr
1276 def ordered_device_refs(self):
1277 result = (self['console_refs'] +
1278 self['vbd_refs'] +
1279 self['vif_refs'] +
1280 self['vtpm_refs'])
1281 result.extend([u for u in self['devices'].keys() if u not in result])
1282 return result
1284 def all_devices_sxpr(self):
1285 """Returns the SXPR for all devices in the current configuration."""
1286 sxprs = []
1287 pci_devs = []
1289 if 'devices' not in self:
1290 return sxprs
1292 ordered_refs = self.ordered_device_refs()
1293 for dev_uuid in ordered_refs:
1294 dev_type, dev_info = self['devices'][dev_uuid]
1295 if dev_type == 'pci': # special case for pci devices
1296 sxpr = [['uuid', dev_info['uuid']]]
1297 for pci_dev_info in dev_info['devs']:
1298 pci_dev_sxpr = ['dev']
1299 for opt, val in pci_dev_info.items():
1300 pci_dev_sxpr.append([opt, val])
1301 sxpr.append(pci_dev_sxpr)
1302 sxprs.append((dev_type, sxpr))
1303 else:
1304 sxpr = self.device_sxpr(dev_type = dev_type,
1305 dev_info = dev_info)
1306 sxprs.append((dev_type, sxpr))
1308 return sxprs
1310 def image_sxpr(self):
1311 """Returns a backwards compatible image SXP expression that is
1312 used in xenstore's /vm/<uuid>/image value and xm list."""
1313 image = [self.image_type()]
1314 if self.has_key('PV_kernel'):
1315 image.append(['kernel', self['PV_kernel']])
1316 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1317 image.append(['ramdisk', self['PV_ramdisk']])
1318 if self.has_key('PV_args') and self['PV_args']:
1319 image.append(['args', self['PV_args']])
1321 for key in XENAPI_PLATFORM_CFG:
1322 if key in self['platform']:
1323 image.append([key, self['platform'][key]])
1325 if 'notes' in self:
1326 image.append(self.notes_sxp(self['notes']))
1328 return image
1330 def update_with_image_sxp(self, image_sxp, bootloader = False):
1331 # Convert Legacy "image" config to Xen API PV_*
1332 # configuration
1333 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1335 # user-specified args must come last: previous releases did this and
1336 # some domU kernels rely upon the ordering.
1337 kernel_args = sxp.child_value(image_sxp, 'args', '')
1339 # attempt to extract extra arguments from SXP config
1340 arg_ip = sxp.child_value(image_sxp, 'ip')
1341 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1342 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1343 arg_root = sxp.child_value(image_sxp, 'root')
1344 if arg_root and not re.search(r'root=', kernel_args):
1345 kernel_args = 'root=%s ' % arg_root + kernel_args
1347 if bootloader:
1348 self['_temp_using_bootloader'] = '1'
1349 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1350 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1351 self['_temp_args'] = kernel_args
1352 else:
1353 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1354 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1355 self['PV_args'] = kernel_args
1357 for key in XENAPI_PLATFORM_CFG:
1358 val = sxp.child_value(image_sxp, key, None)
1359 if val is not None:
1360 self['platform'][key] = val
1362 notes = sxp.children(image_sxp, 'notes')
1363 if notes:
1364 self['notes'] = self.notes_from_sxp(notes[0])
1366 self._hvm_boot_params_from_sxp(image_sxp)
1368 def set_notes(self, notes):
1369 'Add parsed elfnotes to image'
1370 self['notes'] = notes
1372 def get_notes(self):
1373 try:
1374 return self['notes'] or {}
1375 except KeyError:
1376 return {}
1378 def notes_from_sxp(self, nsxp):
1379 notes = {}
1380 for note in sxp.children(nsxp):
1381 notes[note[0]] = note[1]
1382 return notes
1384 def notes_sxp(self, notes):
1385 nsxp = ['notes']
1386 for k, v in notes.iteritems():
1387 nsxp.append([k, str(v)])
1388 return nsxp
1390 def _hvm_boot_params_from_sxp(self, image_sxp):
1391 boot = sxp.child_value(image_sxp, 'boot', None)
1392 if boot is not None:
1393 self['HVM_boot_policy'] = 'BIOS order'
1394 self['HVM_boot_params'] = { 'order' : boot }
1396 def is_hvm(self):
1397 return self['HVM_boot_policy'] != ''
1399 def image_type(self):
1400 stored_type = self['platform'].get('image_type')
1401 return stored_type or (self.is_hvm() and 'hvm' or 'linux')