ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 14988:476efa5c9abf

xend: Ensure bootable flag is set in internal xend config for tap
devices.

Original patch by: Jim Fehlig <jfehlig@novell.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue May 01 10:15:08 2007 +0100 (2007-05-01)
parents 53b9883bbcc3
children 853853686147
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 import XendAPIStore
26 from xen.xend.XendError import VmError
27 from xen.xend.XendDevices import XendDevices
28 from xen.xend.PrettyPrint import prettyprintstring
29 from xen.xend.XendConstants import DOM_STATE_HALTED
31 log = logging.getLogger("xend.XendConfig")
32 log.setLevel(logging.WARN)
35 """
36 XendConfig API
38 XendConfig will try to mirror as closely the Xen API VM Struct
39 with extra parameters for those options that are not supported.
41 """
43 def reverse_dict(adict):
44 """Return the reverse mapping of a dictionary."""
45 return dict([(v, k) for k, v in adict.items()])
47 def bool0(v):
48 return v != '0' and v != 'False' and bool(v)
50 # Recursively copy a data struct, scrubbing out VNC passwords.
51 # Will scrub any dict entry with a key of 'vncpasswd' or any
52 # 2-element list whose first member is 'vncpasswd'. It will
53 # also scrub a string matching '(vncpasswd XYZ)'. Everything
54 # else is no-op passthrough
55 def scrub_password(data):
56 if type(data) == dict or type(data) == XendConfig:
57 scrubbed = {}
58 for key in data.keys():
59 if key == "vncpasswd":
60 scrubbed[key] = "XXXXXXXX"
61 else:
62 scrubbed[key] = scrub_password(data[key])
63 return scrubbed
64 elif type(data) == list:
65 if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd':
66 return ['vncpasswd', 'XXXXXXXX']
67 else:
68 scrubbed = []
69 for entry in data:
70 scrubbed.append(scrub_password(entry))
71 return scrubbed
72 elif type(data) == tuple:
73 scrubbed = []
74 for entry in data:
75 scrubbed.append(scrub_password(entry))
76 return tuple(scrubbed)
77 elif type(data) == str:
78 return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data)
79 else:
80 return data
82 #
83 # CPU fields:
84 #
85 # VCPUs_max -- the maximum number of vcpus that this domain may ever have.
86 # aka XendDomainInfo.getVCpuCount().
87 # vcpus -- the legacy configuration name for above.
88 # max_vcpu_id -- vcpus_number - 1. This is given to us by Xen.
89 #
90 # cpus -- the list of pCPUs available to each vCPU.
91 #
92 # vcpu_avail -- a bitmap telling the guest domain whether it may use each of
93 # its VCPUs. This is translated to
94 # <dompath>/cpu/<id>/availability = {online,offline} for use
95 # by the guest domain.
96 # VCPUs_live -- the number of VCPUs currently up, as reported by Xen. This
97 # is changed by changing vcpu_avail, and waiting for the
98 # domain to respond.
99 #
102 # Mapping from XendConfig configuration keys to the old
103 # legacy configuration keys that map directly.
105 XENAPI_CFG_TO_LEGACY_CFG = {
106 'uuid': 'uuid',
107 'VCPUs_max': 'vcpus',
108 'cpus': 'cpus',
109 'name_label': 'name',
110 'actions_after_shutdown': 'on_poweroff',
111 'actions_after_reboot': 'on_reboot',
112 'actions_after_crash': 'on_crash',
113 'PV_bootloader': 'bootloader',
114 'PV_bootloader_args': 'bootloader_args',
115 }
117 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
119 # Platform configuration keys.
120 XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display',
121 'fda', 'fdb', 'keymap', 'isa', 'localtime', 'monitor',
122 'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl',
123 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc',
124 'vncconsole', 'vncdisplay', 'vnclisten',
125 'vncpasswd', 'vncunused', 'xauthority']
127 # List of XendConfig configuration keys that have no direct equivalent
128 # in the old world.
130 XENAPI_CFG_TYPES = {
131 'uuid': str,
132 'name_label': str,
133 'name_description': str,
134 'user_version': str,
135 'is_a_template': bool0,
136 'resident_on': str,
137 'memory_static_min': int, # note these are stored in bytes, not KB!
138 'memory_static_max': int,
139 'memory_dynamic_min': int,
140 'memory_dynamic_max': int,
141 'cpus': list,
142 'vcpus_params': dict,
143 'VCPUs_max': int,
144 'VCPUs_at_startup': int,
145 'VCPUs_live': int,
146 'actions_after_shutdown': str,
147 'actions_after_reboot': str,
148 'actions_after_crash': str,
149 'PV_bootloader': str,
150 'PV_kernel': str,
151 'PV_ramdisk': str,
152 'PV_args': str,
153 'PV_bootloader_args': str,
154 'HVM_boot_policy': str,
155 'HVM_boot_params': dict,
156 'PCI_bus': str,
157 'platform': dict,
158 'tools_version': dict,
159 'other_config': dict,
160 }
162 # List of legacy configuration keys that have no equivalent in the
163 # Xen API, but are still stored in XendConfig.
165 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
166 # roundtripped (dynamic, unmodified)
167 'shadow_memory',
168 'security',
169 'vcpu_avail',
170 'cpu_weight',
171 'cpu_cap',
172 'features',
173 # read/write
174 'on_xend_start',
175 'on_xend_stop',
176 # read-only
177 'domid',
178 'start_time',
179 'cpu_time',
180 'online_vcpus',
181 # write-once
182 'cpu',
183 'cpus',
184 ]
186 LEGACY_CFG_TYPES = {
187 'uuid': str,
188 'name': str,
189 'vcpus': int,
190 'vcpu_avail': long,
191 'memory': int,
192 'shadow_memory': int,
193 'maxmem': int,
194 'start_time': float,
195 'cpu_cap': int,
196 'cpu_weight': int,
197 'cpu_time': float,
198 'features': str,
199 'localtime': int,
200 'name': str,
201 'on_poweroff': str,
202 'on_reboot': str,
203 'on_crash': str,
204 'on_xend_stop': str,
205 'on_xend_start': str,
206 'online_vcpus': int,
207 'rtc/timeoffset': str,
208 }
210 # Values that should be stored in xenstore's /vm/<uuid> that is used
211 # by Xend. Used in XendDomainInfo to restore running VM state from
212 # xenstore.
213 LEGACY_XENSTORE_VM_PARAMS = [
214 'uuid',
215 'name',
216 'vcpus',
217 'vcpu_avail',
218 'memory',
219 'shadow_memory',
220 'maxmem',
221 'start_time',
222 'name',
223 'on_poweroff',
224 'on_crash',
225 'on_reboot',
226 'on_xend_start',
227 'on_xend_stop',
228 ]
230 DEFAULT_DM = '/usr/lib/xen/bin/qemu-dm'
232 ##
233 ## Config Choices
234 ##
236 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
237 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
238 'crashed', 'dying')
240 class XendConfigError(VmError):
241 def __str__(self):
242 return 'Invalid Configuration: %s' % str(self.value)
244 ##
245 ## XendConfig Class (an extended dictionary)
246 ##
248 class XendConfig(dict):
249 """ The new Xend VM Configuration.
251 Stores the configuration in xenapi compatible format but retains
252 import and export functions for SXP.
253 """
254 def __init__(self, filename = None, sxp_obj = None,
255 xapi = None, dominfo = None):
257 dict.__init__(self)
258 self.update(self._defaults())
260 if filename:
261 try:
262 sxp_obj = sxp.parse(open(filename,'r'))
263 sxp_obj = sxp_obj[0]
264 except IOError, e:
265 raise XendConfigError("Unable to read file: %s" % filename)
267 if sxp_obj:
268 self._sxp_to_xapi(sxp_obj)
269 self._sxp_to_xapi_unsupported(sxp_obj)
270 elif xapi:
271 self.update_with_xenapi_config(xapi)
272 elif dominfo:
273 # output from xc.domain_getinfo
274 self._dominfo_to_xapi(dominfo, update_mem = True)
276 log.debug('XendConfig.init: %s' % scrub_password(self))
278 # validators go here
279 self.validate()
281 """ In time, we should enable this type checking addition. It is great
282 also for tracking bugs and unintended writes to XendDomainInfo.info
283 def __setitem__(self, key, value):
284 type_conv = XENAPI_CFG_TYPES.get(key)
285 if callable(type_conv):
286 try:
287 dict.__setitem__(self, key, type_conv(value))
288 except (ValueError, TypeError):
289 raise XendConfigError("Wrong type for configuration value " +
290 "%s. Expected %s" %
291 (key, type_conv.__name__))
292 else:
293 dict.__setitem__(self, key, value)
294 """
296 def _defaults(self):
297 defaults = {
298 'name_label': 'Domain-Unnamed',
299 'actions_after_shutdown': 'destroy',
300 'actions_after_reboot': 'restart',
301 'actions_after_crash': 'restart',
302 'actions_after_suspend': '',
303 'is_a_template': False,
304 'is_control_domain': False,
305 'features': '',
306 'PV_bootloader': '',
307 'PV_kernel': '',
308 'PV_ramdisk': '',
309 'PV_args': '',
310 'PV_bootloader_args': '',
311 'HVM_boot_policy': '',
312 'HVM_boot_params': {},
313 'memory_static_min': 0,
314 'memory_dynamic_min': 0,
315 'shadow_memory': 0,
316 'memory_static_max': 0,
317 'memory_dynamic_max': 0,
318 'devices': {},
319 'security': None,
320 'on_xend_start': 'ignore',
321 'on_xend_stop': 'ignore',
322 'cpus': [],
323 'cpu_weight': 256,
324 'cpu_cap': 0,
325 'VCPUs_max': 1,
326 'VCPUs_live': 1,
327 'VCPUs_at_startup': 1,
328 'vcpus_params': {},
329 'console_refs': [],
330 'vif_refs': [],
331 'vbd_refs': [],
332 'vtpm_refs': [],
333 'other_config': {},
334 'platform': {}
335 }
337 return defaults
339 #
340 # Here we assume these values exist in the dict.
341 # If they don't we have a bigger problem, lets not
342 # try and 'fix it up' but acutually fix the cause ;-)
343 #
344 def _memory_sanity_check(self):
345 log.trace("_memory_sanity_check memory_static_min: %s, "
346 "memory_static_max: %i, "
347 "memory_dynamic_min: %i, "
348 "memory_dynamic_max: %i",
349 self["memory_static_min"],
350 self["memory_static_max"],
351 self["memory_dynamic_min"],
352 self["memory_dynamic_max"])
354 if not self["memory_static_min"] <= self["memory_static_max"]:
355 raise XendConfigError("memory_static_min must be less " \
356 "than or equal to memory_static_max")
357 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
358 raise XendConfigError("memory_static_min must be less " \
359 "than or equal to memory_dynamic_min")
360 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
361 raise XendConfigError("memory_dynamic_max must be less " \
362 "than or equal to memory_static_max")
363 if not self["memory_dynamic_max"] > 0:
364 raise XendConfigError("memory_dynamic_max must be greater " \
365 "than zero")
366 if not self["memory_static_max"] > 0:
367 raise XendConfigError("memory_static_max must be greater " \
368 "than zero")
370 def _actions_sanity_check(self):
371 for event in ['shutdown', 'reboot', 'crash']:
372 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
373 raise XendConfigError('Invalid event handling mode: ' +
374 event)
376 def _vcpus_sanity_check(self):
377 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
378 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
380 def _uuid_sanity_check(self):
381 """Make sure UUID is in proper string format with hyphens."""
382 if 'uuid' not in self or not self['uuid']:
383 self['uuid'] = uuid.createString()
384 else:
385 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
387 def _name_sanity_check(self):
388 if 'name_label' not in self:
389 self['name_label'] = 'Domain-' + self['uuid']
391 def _platform_sanity_check(self):
392 if self.is_hvm():
393 if 'device_model' not in self['platform']:
394 self['platform']['device_model'] = DEFAULT_DM
396 # Compatibility hack, can go away soon.
397 if 'soundhw' not in self['platform'] and \
398 self['platform'].get('enable_audio'):
399 self['platform']['soundhw'] = 'sb16'
401 def validate(self):
402 self._uuid_sanity_check()
403 self._name_sanity_check()
404 self._memory_sanity_check()
405 self._actions_sanity_check()
406 self._vcpus_sanity_check()
407 self._platform_sanity_check()
409 def _dominfo_to_xapi(self, dominfo, update_mem = False):
410 self['domid'] = dominfo['domid']
411 self['online_vcpus'] = dominfo['online_vcpus']
412 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
414 if update_mem:
415 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
416 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
417 self['memory_static_min'] = 0
418 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
419 self._memory_sanity_check()
421 self['cpu_time'] = dominfo['cpu_time']/1e9
422 # TODO: i don't know what the security stuff expects here
423 if dominfo.get('ssidref'):
424 self['security'] = [['ssidref', dominfo['ssidref']]]
425 self['shutdown_reason'] = dominfo['shutdown_reason']
427 # parse state into Xen API states
428 self['running'] = dominfo['running']
429 self['crashed'] = dominfo['crashed']
430 self['dying'] = dominfo['dying']
431 self['shutdown'] = dominfo['shutdown']
432 self['paused'] = dominfo['paused']
433 self['blocked'] = dominfo['blocked']
435 if 'name' in dominfo:
436 self['name_label'] = dominfo['name']
438 if 'handle' in dominfo:
439 self['uuid'] = uuid.toString(dominfo['handle'])
441 def _parse_sxp(self, sxp_cfg):
442 """ Populate this XendConfig using the parsed SXP.
444 @param sxp_cfg: Parsed SXP Configuration
445 @type sxp_cfg: list of lists
446 @rtype: dictionary
447 @return: A dictionary containing the parsed options of the SXP.
448 """
449 cfg = {}
451 for key, typ in XENAPI_CFG_TYPES.items():
452 val = sxp.child_value(sxp_cfg, key)
453 if val is not None:
454 try:
455 cfg[key] = typ(val)
456 except (ValueError, TypeError), e:
457 log.warn('Unable to convert type value for key: %s' % key)
459 # Convert deprecated options to current equivalents.
461 restart = sxp.child_value(sxp_cfg, 'restart')
462 if restart:
463 if restart == 'onreboot':
464 cfg['on_poweroff'] = 'destroy'
465 cfg['on_reboot'] = 'restart'
466 cfg['on_crash'] = 'destroy'
467 elif restart == 'always':
468 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
469 cfg[opt] = 'restart'
470 elif restart == 'never':
471 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
472 cfg[opt] = 'never'
473 else:
474 log.warn('Ignoring unrecognised value for deprecated option:'
475 'restart = \'%s\'', restart)
477 # Handle memory, passed in as MiB
479 if sxp.child_value(sxp_cfg, "memory") != None:
480 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
481 if sxp.child_value(sxp_cfg, "maxmem") != None:
482 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
484 # Only extract options we know about.
485 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
486 extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
488 for key in extract_keys:
489 val = sxp.child_value(sxp_cfg, key)
490 if val != None:
491 try:
492 cfg[key] = LEGACY_CFG_TYPES[key](val)
493 except KeyError:
494 cfg[key] = val
495 except (TypeError, ValueError), e:
496 log.warn("Unable to parse key %s: %s: %s" %
497 (key, str(val), e))
499 if 'platform' not in cfg:
500 cfg['platform'] = {}
501 localtime = sxp.child_value(sxp_cfg, 'localtime')
502 if localtime is not None:
503 cfg['platform']['localtime'] = localtime
505 # Compatibility hack -- can go soon.
506 for key in XENAPI_PLATFORM_CFG:
507 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
508 if val is not None:
509 self['platform'][key] = val
511 # Compatibility hack -- can go soon.
512 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
513 if boot_order:
514 cfg['HVM_boot_policy'] = 'BIOS order'
515 cfg['HVM_boot_params'] = { 'order' : boot_order }
517 # Parsing the device SXP's. In most cases, the SXP looks
518 # like this:
519 #
520 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
521 #
522 # However, for PCI devices it looks like this:
523 #
524 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
525 #
526 # It seems the reasoning for this difference is because
527 # pciif.py needs all the PCI device configurations at
528 # the same time when creating the devices.
529 #
530 # To further complicate matters, Xen 2.0 configuration format
531 # uses the following for pci device configuration:
532 #
533 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
534 #
535 # Hence we deal with pci device configurations outside of
536 # the regular device parsing.
538 cfg['devices'] = {}
539 for dev in sxp.children(sxp_cfg, 'device'):
540 config = sxp.child0(dev)
541 dev_type = sxp.name(config)
542 dev_info = {}
544 if dev_type == 'pci':
545 pci_devs_uuid = sxp.child_value(config, 'uuid',
546 uuid.createString())
547 pci_devs = []
548 for pci_dev in sxp.children(config, 'dev'):
549 pci_dev_info = {}
550 for opt_val in pci_dev[1:]:
551 try:
552 opt, val = opt_val
553 pci_dev_info[opt] = val
554 except TypeError:
555 pass
556 pci_devs.append(pci_dev_info)
558 cfg['devices'][pci_devs_uuid] = (dev_type,
559 {'devs': pci_devs,
560 'uuid': pci_devs_uuid})
562 log.debug("XendConfig: reading device: %s" % pci_devs)
563 else:
564 self.device_add(dev_type, cfg_sxp = config, target = cfg)
565 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
567 # Extract missing data from configuration entries
568 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
569 if image_sxp:
570 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
571 if image_vcpus != None:
572 try:
573 if 'VCPUs_max' not in cfg:
574 cfg['VCPUs_max'] = int(image_vcpus)
575 elif cfg['VCPUs_max'] != int(image_vcpus):
576 cfg['VCPUs_max'] = int(image_vcpus)
577 log.warn('Overriding vcpus from %d to %d using image'
578 'vcpus value.', cfg['VCPUs_max'])
579 except ValueError, e:
580 raise XendConfigError('integer expeceted: %s: %s' %
581 image_sxp, e)
583 # Deprecated cpu configuration
584 if 'cpu' in cfg:
585 if 'cpus' in cfg:
586 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
587 else:
588 cfg['cpus'] = str(cfg['cpu'])
590 # convert 'cpus' string to list of ints
591 # 'cpus' supports a list of ranges (0-3), seperated by
592 # commas, and negation, (^1).
593 # Precedence is settled by order of the string:
594 # "0-3,^1" -> [0,2,3]
595 # "0-3,^1,1" -> [0,1,2,3]
596 try:
597 if 'cpus' in cfg and type(cfg['cpus']) != list:
598 cpus = []
599 for c in cfg['cpus'].split(','):
600 if c.find('-') != -1:
601 (x, y) = c.split('-')
602 for i in range(int(x), int(y)+1):
603 cpus.append(int(i))
604 else:
605 # remove this element from the list
606 if c[0] == '^':
607 cpus = [x for x in cpus if x != int(c[1:])]
608 else:
609 cpus.append(int(c))
611 cfg['cpus'] = cpus
612 except ValueError, e:
613 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
615 if 'security' in cfg and isinstance(cfg['security'], str):
616 cfg['security'] = sxp.from_string(cfg['security'])
618 old_state = sxp.child_value(sxp_cfg, 'state')
619 if old_state:
620 for i in range(len(CONFIG_OLD_DOM_STATES)):
621 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
623 return cfg
626 def _sxp_to_xapi(self, sxp_cfg):
627 """Read in an SXP Configuration object and
628 populate at much of the Xen API with valid values.
629 """
630 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
632 cfg = self._parse_sxp(sxp_cfg)
634 for key, typ in XENAPI_CFG_TYPES.items():
635 val = cfg.get(key)
636 if val is not None:
637 self[key] = typ(val)
639 # Convert parameters that can be directly mapped from
640 # the Legacy Config to Xen API Config
642 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
643 try:
644 type_conv = XENAPI_CFG_TYPES.get(apikey)
645 if callable(type_conv):
646 self[apikey] = type_conv(cfg[cfgkey])
647 else:
648 log.warn("Unconverted key: " + apikey)
649 self[apikey] = cfg[cfgkey]
650 except KeyError:
651 pass
653 # Lets try and handle memory correctly
655 MiB = 1024 * 1024
657 if "memory" in cfg:
658 self["memory_static_min"] = 0
659 self["memory_static_max"] = int(cfg["memory"]) * MiB
660 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
661 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
663 if "maxmem" in cfg:
664 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
666 self._memory_sanity_check()
668 def update_with(n, o):
669 if not self.get(n):
670 self[n] = cfg.get(o, '')
672 update_with('PV_bootloader', 'bootloader')
673 update_with('PV_bootloader_args', 'bootloader_args')
675 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
676 if image_sxp:
677 self.update_with_image_sxp(image_sxp)
679 # Convert Legacy HVM parameters to Xen API configuration
680 for key in XENAPI_PLATFORM_CFG:
681 if key in cfg:
682 self['platform'][key] = cfg[key]
684 # set device references in the configuration
685 self['devices'] = cfg.get('devices', {})
686 self['console_refs'] = cfg.get('console_refs', [])
687 self['vif_refs'] = cfg.get('vif_refs', [])
688 self['vbd_refs'] = cfg.get('vbd_refs', [])
689 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
691 # coalesce hvm vnc frame buffer with vfb config
692 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
693 # add vfb device if it isn't there already
694 has_rfb = False
695 for console_uuid in self['console_refs']:
696 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
697 has_rfb = True
698 break
699 if self['devices'][console_uuid][0] == 'vfb':
700 has_rfb = True
701 break
703 if not has_rfb:
704 dev_config = ['vfb']
705 # copy VNC related params from platform config to vfb dev conf
706 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
707 'vnclisten']:
708 if key in self['platform']:
709 dev_config.append([key, self['platform'][key]])
711 self.device_add('vfb', cfg_sxp = dev_config)
714 def _sxp_to_xapi_unsupported(self, sxp_cfg):
715 """Read in an SXP configuration object and populate
716 values are that not related directly supported in
717 the Xen API.
718 """
720 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
722 # Parse and convert parameters used to configure
723 # the image (as well as HVM images)
724 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
725 if image_sxp:
726 image_type = sxp.name(image_sxp)
727 if image_type != 'hvm' and image_type != 'linux':
728 self['platform']['image_type'] = image_type
730 for key in XENAPI_PLATFORM_CFG:
731 val = sxp.child_value(image_sxp, key, None)
732 if val is not None and val != '':
733 self['platform'][key] = val
735 notes = sxp.children(image_sxp, 'notes')
736 if notes:
737 self['notes'] = self.notes_from_sxp(notes[0])
739 self._hvm_boot_params_from_sxp(image_sxp)
741 # extract backend value
743 backend = []
744 for c in sxp.children(sxp_cfg, 'backend'):
745 backend.append(sxp.name(sxp.child0(c)))
746 if backend:
747 self['backend'] = backend
749 # Parse and convert other Non Xen API parameters.
750 def _set_cfg_if_exists(sxp_arg):
751 val = sxp.child_value(sxp_cfg, sxp_arg)
752 if val != None:
753 if LEGACY_CFG_TYPES.get(sxp_arg):
754 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
755 else:
756 self[sxp_arg] = val
758 _set_cfg_if_exists('shadow_memory')
759 _set_cfg_if_exists('security')
760 _set_cfg_if_exists('features')
761 _set_cfg_if_exists('on_xend_stop')
762 _set_cfg_if_exists('on_xend_start')
763 _set_cfg_if_exists('vcpu_avail')
764 _set_cfg_if_exists('cpu_weight')
765 _set_cfg_if_exists('cpu_cap')
767 # Parse and store runtime configuration
768 _set_cfg_if_exists('start_time')
769 _set_cfg_if_exists('cpu_time')
770 _set_cfg_if_exists('shutdown_reason')
771 _set_cfg_if_exists('up_time')
772 _set_cfg_if_exists('status') # TODO, deprecated
774 def _get_old_state_string(self):
775 """Returns the old xm state string.
776 @rtype: string
777 @return: old state string
778 """
779 state_string = ''
780 for state_name in CONFIG_OLD_DOM_STATES:
781 on_off = self.get(state_name, 0)
782 if on_off:
783 state_string += state_name[0]
784 else:
785 state_string += '-'
787 return state_string
790 def update_config(self, dominfo):
791 """Update configuration with the output from xc.domain_getinfo().
793 @param dominfo: Domain information via xc.domain_getinfo()
794 @type dominfo: dict
795 """
796 self._dominfo_to_xapi(dominfo)
797 self.validate()
799 def update_with_xenapi_config(self, xapi):
800 """Update configuration with a Xen API VM struct
802 @param xapi: Xen API VM Struct
803 @type xapi: dict
804 """
806 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
808 for key, val in xapi.items():
809 type_conv = XENAPI_CFG_TYPES.get(key)
810 if type_conv is None:
811 key = key.lower()
812 type_conv = XENAPI_CFG_TYPES.get(key)
813 if callable(type_conv):
814 self[key] = type_conv(val)
815 else:
816 self[key] = val
818 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
819 legacy_only = True):
820 """ Get SXP representation of this config object.
822 Incompat: removed store_mfn, console_mfn
824 @keyword domain: (optional) XendDomainInfo to get extra information
825 from such as domid and running devices.
826 @type domain: XendDomainInfo
827 @keyword ignore: (optional) list of 'keys' that we do not want
828 to export.
829 @type ignore: list of strings
830 @rtype: list of list (SXP representation)
831 """
832 sxpr = ['domain']
834 # TODO: domid/dom is the same thing but called differently
835 # depending if it is from xenstore or sxpr.
837 if domain.getDomid() is not None:
838 sxpr.append(['domid', domain.getDomid()])
840 if not legacy_only:
841 for name, typ in XENAPI_CFG_TYPES.items():
842 if name in self and self[name] not in (None, []):
843 if typ == dict:
844 s = self[name].items()
845 else:
846 s = str(self[name])
847 sxpr.append([name, s])
849 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
850 if legacy in ('cpus'): # skip this
851 continue
852 if self.has_key(xenapi) and self[xenapi] not in (None, []):
853 if type(self[xenapi]) == bool:
854 # convert booleans to ints before making an sxp item
855 sxpr.append([legacy, int(self[xenapi])])
856 else:
857 sxpr.append([legacy, self[xenapi]])
859 MiB = 1024*1024
861 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
862 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
864 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
865 if legacy in ('domid', 'uuid', 'cpus'): # skip these
866 continue
867 if self.has_key(legacy) and self[legacy] not in (None, []):
868 sxpr.append([legacy, self[legacy]])
870 sxpr.append(['image', self.image_sxpr()])
871 sxpr.append(['status', domain._stateGet()])
873 if domain.getDomid() is not None:
874 sxpr.append(['state', self._get_old_state_string()])
876 if domain:
877 if domain.store_mfn:
878 sxpr.append(['store_mfn', domain.store_mfn])
879 if domain.console_mfn:
880 sxpr.append(['console_mfn', domain.console_mfn])
883 # Marshall devices (running or from configuration)
884 if not ignore_devices:
885 for cls in XendDevices.valid_devices():
886 found = False
888 # figure if there is a dev controller is valid and running
889 if domain and domain.getDomid() != None:
890 try:
891 controller = domain.getDeviceController(cls)
892 configs = controller.configurations()
893 for config in configs:
894 if sxp.name(config) in ('vbd', 'tap'):
895 # The bootable flag is never written to the
896 # store as part of the device config.
897 dev_uuid = sxp.child_value(config, 'uuid')
898 dev_type, dev_cfg = self['devices'][dev_uuid]
899 is_bootable = dev_cfg.get('bootable', 0)
900 config.append(['bootable', int(is_bootable)])
902 sxpr.append(['device', config])
904 found = True
905 except:
906 log.exception("dumping sxp from device controllers")
907 pass
909 # if we didn't find that device, check the existing config
910 # for a device in the same class
911 if not found:
912 for dev_type, dev_info in self.all_devices_sxpr():
913 if dev_type == cls:
914 sxpr.append(['device', dev_info])
916 return sxpr
918 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
919 target = None):
920 """Add a device configuration in SXP format or XenAPI struct format.
922 For SXP, it could be either:
924 [device, [vbd, [uname ...]]
926 or:
928 [vbd, [uname ..]]
930 @type cfg_sxp: list of lists (parsed sxp object)
931 @param cfg_sxp: SXP configuration object
932 @type cfg_xenapi: dict
933 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
934 @param target: write device information to
935 @type target: None or a dictionary
936 @rtype: string
937 @return: Assigned UUID of the device.
938 """
939 if target == None:
940 target = self
942 if dev_type not in XendDevices.valid_devices():
943 raise XendConfigError("XendConfig: %s not a valid device type" %
944 dev_type)
946 if cfg_sxp == None and cfg_xenapi == None:
947 raise XendConfigError("XendConfig: device_add requires some "
948 "config.")
950 #if cfg_sxp:
951 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
952 #if cfg_xenapi:
953 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
955 if cfg_sxp:
956 if sxp.child0(cfg_sxp) == 'device':
957 config = sxp.child0(cfg_sxp)
958 else:
959 config = cfg_sxp
961 dev_type = sxp.name(config)
962 dev_info = {}
964 for opt_val in config[1:]:
965 try:
966 opt, val = opt_val
967 dev_info[opt] = val
968 except (TypeError, ValueError): # unpack error
969 pass
971 if dev_type == 'vbd':
972 dev_info['bootable'] = 0
973 if dev_info.get('dev', '').startswith('ioemu:'):
974 dev_info['driver'] = 'ioemu'
975 else:
976 dev_info['driver'] = 'paravirtualised'
978 # create uuid if it doesn't exist
979 dev_uuid = dev_info.get('uuid', None)
980 if not dev_uuid:
981 dev_uuid = uuid.createString()
982 dev_info['uuid'] = dev_uuid
984 # store dev references by uuid for certain device types
985 target['devices'][dev_uuid] = (dev_type, dev_info)
986 if dev_type in ('vif', 'vbd', 'vtpm'):
987 param = '%s_refs' % dev_type
988 if param not in target:
989 target[param] = []
990 if dev_uuid not in target[param]:
991 if dev_type == 'vbd':
992 # Compat hack -- mark first disk bootable
993 dev_info['bootable'] = int(not target[param])
994 target[param].append(dev_uuid)
995 elif dev_type == 'tap':
996 if 'vbd_refs' not in target:
997 target['vbd_refs'] = []
998 if dev_uuid not in target['vbd_refs']:
999 # Compat hack -- mark first disk bootable
1000 dev_info['bootable'] = int(not target['vbd_refs'])
1001 target['vbd_refs'].append(dev_uuid)
1003 elif dev_type == 'vfb':
1004 # Populate other config with aux data that is associated
1005 # with vfb
1007 other_config = {}
1008 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1009 'vncpasswd', 'type', 'display', 'xauthority',
1010 'keymap']:
1011 if key in dev_info:
1012 other_config[key] = dev_info[key]
1013 target['devices'][dev_uuid][1]['other_config'] = other_config
1016 if 'console_refs' not in target:
1017 target['console_refs'] = []
1019 # Treat VFB devices as console devices so they are found
1020 # through Xen API
1021 if dev_uuid not in target['console_refs']:
1022 target['console_refs'].append(dev_uuid)
1024 elif dev_type == 'console':
1025 if 'console_refs' not in target:
1026 target['console_refs'] = []
1027 if dev_uuid not in target['console_refs']:
1028 target['console_refs'].append(dev_uuid)
1030 return dev_uuid
1032 if cfg_xenapi:
1033 dev_info = {}
1034 dev_uuid = ''
1035 if dev_type == 'vif':
1036 if cfg_xenapi.get('MAC'): # don't add if blank
1037 dev_info['mac'] = cfg_xenapi.get('MAC')
1038 # vifname is the name on the guest, not dom0
1039 # TODO: we don't have the ability to find that out or
1040 # change it from dom0
1041 #if cfg_xenapi.get('device'): # don't add if blank
1042 # dev_info['vifname'] = cfg_xenapi.get('device')
1043 if cfg_xenapi.get('type'):
1044 dev_info['type'] = cfg_xenapi.get('type')
1045 if cfg_xenapi.get('name'):
1046 dev_info['name'] = cfg_xenapi.get('name')
1047 if cfg_xenapi.get('network'):
1048 network = XendAPIStore.get(
1049 cfg_xenapi.get('network'), 'network')
1050 dev_info['bridge'] = network.get_name_label()
1052 dev_uuid = cfg_xenapi.get('uuid', None)
1053 if not dev_uuid:
1054 dev_uuid = uuid.createString()
1055 dev_info['uuid'] = dev_uuid
1056 target['devices'][dev_uuid] = (dev_type, dev_info)
1057 target['vif_refs'].append(dev_uuid)
1059 elif dev_type in ('vbd', 'tap'):
1060 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1061 if dev_info['type'] == 'CD':
1062 old_vbd_type = 'cdrom'
1063 else:
1064 old_vbd_type = 'disk'
1066 dev_info['uname'] = cfg_xenapi.get('image', '')
1067 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1068 old_vbd_type)
1069 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1070 dev_info['driver'] = cfg_xenapi.get('driver', '')
1071 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1073 if cfg_xenapi.get('mode') == 'RW':
1074 dev_info['mode'] = 'w'
1075 else:
1076 dev_info['mode'] = 'r'
1078 dev_uuid = cfg_xenapi.get('uuid', None)
1079 if not dev_uuid:
1080 dev_uuid = uuid.createString()
1081 dev_info['uuid'] = dev_uuid
1082 target['devices'][dev_uuid] = (dev_type, dev_info)
1083 target['vbd_refs'].append(dev_uuid)
1085 elif dev_type == 'vtpm':
1086 if cfg_xenapi.get('type'):
1087 dev_info['type'] = cfg_xenapi.get('type')
1089 dev_uuid = cfg_xenapi.get('uuid', None)
1090 if not dev_uuid:
1091 dev_uuid = uuid.createString()
1092 dev_info['uuid'] = dev_uuid
1093 target['devices'][dev_uuid] = (dev_type, dev_info)
1094 target['vtpm_refs'].append(dev_uuid)
1096 elif dev_type == 'console':
1097 dev_uuid = cfg_xenapi.get('uuid', None)
1098 if not dev_uuid:
1099 dev_uuid = uuid.createString()
1100 dev_info['uuid'] = dev_uuid
1101 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1102 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1103 if dev_info['protocol'] == 'rfb':
1104 # collapse other config into devinfo for things
1105 # such as vncpasswd, vncunused, etc.
1106 dev_info.update(cfg_xenapi.get('other_config', {}))
1107 dev_info['type'] = 'vnc'
1108 target['devices'][dev_uuid] = ('vfb', dev_info)
1109 target['console_refs'].append(dev_uuid)
1111 # Finally, if we are a pvfb, we need to make a vkbd
1112 # as well that is not really exposed to Xen API
1113 vkbd_uuid = uuid.createString()
1114 target['devices'][vkbd_uuid] = ('vkbd', {})
1116 elif dev_info['protocol'] == 'vt100':
1117 # if someone tries to create a VT100 console
1118 # via the Xen API, we'll have to ignore it
1119 # because we create one automatically in
1120 # XendDomainInfo._update_consoles
1121 raise XendConfigError('Creating vt100 consoles via '
1122 'Xen API is unsupported')
1124 return dev_uuid
1126 # no valid device to add
1127 return ''
1129 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1130 target = None):
1131 """Add a phantom tap device configuration in XenAPI struct format.
1132 """
1134 if target == None:
1135 target = self
1137 if dev_type not in XendDevices.valid_devices() and \
1138 dev_type not in XendDevices.pseudo_devices():
1139 raise XendConfigError("XendConfig: %s not a valid device type" %
1140 dev_type)
1142 if cfg_xenapi == None:
1143 raise XendConfigError("XendConfig: device_add requires some "
1144 "config.")
1146 if cfg_xenapi:
1147 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1149 if cfg_xenapi:
1150 dev_info = {}
1151 if dev_type in ('vbd', 'tap'):
1152 if dev_type == 'vbd':
1153 dev_info['uname'] = cfg_xenapi.get('image', '')
1154 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1155 elif dev_type == 'tap':
1156 if cfg_xenapi.get('image').find('tap:') == -1:
1157 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1158 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1159 dev_info['uname'] = cfg_xenapi.get('image')
1160 dev_info['mode'] = cfg_xenapi.get('mode')
1161 dev_info['backend'] = '0'
1162 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1163 dev_info['uuid'] = dev_uuid
1164 self['devices'][dev_uuid] = (dev_type, dev_info)
1165 self['vbd_refs'].append(dev_uuid)
1166 return dev_uuid
1168 return ''
1170 def console_add(self, protocol, location, other_config = {}):
1171 dev_uuid = uuid.createString()
1172 if protocol == 'vt100':
1173 dev_info = {
1174 'uuid': dev_uuid,
1175 'protocol': protocol,
1176 'location': location,
1177 'other_config': other_config,
1180 if 'devices' not in self:
1181 self['devices'] = {}
1183 self['devices'][dev_uuid] = ('console', dev_info)
1184 self['console_refs'].append(dev_uuid)
1185 return dev_info
1187 return {}
1189 def console_update(self, console_uuid, key, value):
1190 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1191 if dev_uuid == console_uuid:
1192 dev_info[key] = value
1193 break
1195 def console_get_all(self, protocol):
1196 if protocol == 'vt100':
1197 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1198 if dtype == 'console']
1199 return [c for c in consoles if c.get('protocol') == protocol]
1201 elif protocol == 'rfb':
1202 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1203 if dtype == 'vfb']
1205 # move all non-console key values to other_config before
1206 # returning console config
1207 valid_keys = ['uuid', 'location']
1208 for vfb in vfbs:
1209 other_config = {}
1210 for key, val in vfb.items():
1211 if key not in valid_keys:
1212 other_config[key] = vfb[key]
1213 del vfb[key]
1214 vfb['other_config'] = other_config
1215 vfb['protocol'] = 'rfb'
1217 return vfbs
1219 else:
1220 return []
1222 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1223 """Update an existing device with the new configuration.
1225 @rtype: boolean
1226 @return: Returns True if succesfully found and updated a device conf
1227 """
1228 if dev_uuid in self['devices'] and cfg_sxp:
1229 if sxp.child0(cfg_sxp) == 'device':
1230 config = sxp.child0(cfg_sxp)
1231 else:
1232 config = cfg_sxp
1234 dev_type, dev_info = self['devices'][dev_uuid]
1235 for opt_val in config[1:]:
1236 try:
1237 opt, val = opt_val
1238 dev_info[opt] = val
1239 except (TypeError, ValueError):
1240 pass # no value for this config option
1242 self['devices'][dev_uuid] = (dev_type, dev_info)
1243 return True
1245 elif dev_uuid in self['devices'] and cfg_xenapi:
1246 dev_type, dev_info = self['devices'][dev_uuid]
1247 for key, val in cfg_xenapi.items():
1248 dev_info[key] = val
1249 self['devices'][dev_uuid] = (dev_type, dev_info)
1251 return False
1254 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
1255 """Get Device SXPR by either giving the device UUID or (type, config).
1257 @rtype: list of lists
1258 @return: device config sxpr
1259 """
1260 sxpr = []
1261 if dev_uuid != None and dev_uuid in self['devices']:
1262 dev_type, dev_info = self['devices'][dev_uuid]
1264 if dev_type == None or dev_info == None:
1265 raise XendConfigError("Required either UUID or device type and "
1266 "configuration dictionary.")
1268 sxpr.append(dev_type)
1269 if dev_type in ('console', 'vfb'):
1270 config = [(opt, val) for opt, val in dev_info.items()
1271 if opt != 'other_config']
1272 else:
1273 config = [(opt, val) for opt, val in dev_info.items()]
1275 sxpr += config
1277 return sxpr
1279 def ordered_device_refs(self):
1280 result = []
1281 # vkbd devices *must* be before vfb devices, otherwise
1282 # there is a race condition when setting up devices
1283 # where the daemon spawned for the vfb may write stuff
1284 # into xenstore vkbd backend, before DevController has
1285 # setup permissions on the vkbd backend path. This race
1286 # results in domain creation failing with 'device already
1287 # connected' messages
1288 result.extend([u for u in self['devices'].keys() if self['devices'][u][0] == 'vkbd'])
1290 result.extend(self['console_refs'] +
1291 self['vbd_refs'] +
1292 self['vif_refs'] +
1293 self['vtpm_refs'])
1295 result.extend([u for u in self['devices'].keys() if u not in result])
1296 return result
1298 def all_devices_sxpr(self):
1299 """Returns the SXPR for all devices in the current configuration."""
1300 sxprs = []
1301 pci_devs = []
1303 if 'devices' not in self:
1304 return sxprs
1306 ordered_refs = self.ordered_device_refs()
1307 for dev_uuid in ordered_refs:
1308 dev_type, dev_info = self['devices'][dev_uuid]
1309 if dev_type == 'pci': # special case for pci devices
1310 sxpr = [['uuid', dev_info['uuid']]]
1311 for pci_dev_info in dev_info['devs']:
1312 pci_dev_sxpr = ['dev']
1313 for opt, val in pci_dev_info.items():
1314 pci_dev_sxpr.append([opt, val])
1315 sxpr.append(pci_dev_sxpr)
1316 sxprs.append((dev_type, sxpr))
1317 else:
1318 sxpr = self.device_sxpr(dev_type = dev_type,
1319 dev_info = dev_info)
1320 sxprs.append((dev_type, sxpr))
1322 return sxprs
1324 def image_sxpr(self):
1325 """Returns a backwards compatible image SXP expression that is
1326 used in xenstore's /vm/<uuid>/image value and xm list."""
1327 image = [self.image_type()]
1328 if self.has_key('PV_kernel'):
1329 image.append(['kernel', self['PV_kernel']])
1330 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1331 image.append(['ramdisk', self['PV_ramdisk']])
1332 if self.has_key('PV_args') and self['PV_args']:
1333 image.append(['args', self['PV_args']])
1335 for key in XENAPI_PLATFORM_CFG:
1336 if key in self['platform']:
1337 image.append([key, self['platform'][key]])
1339 if 'notes' in self:
1340 image.append(self.notes_sxp(self['notes']))
1342 return image
1344 def update_with_image_sxp(self, image_sxp, bootloader = False):
1345 # Convert Legacy "image" config to Xen API PV_*
1346 # configuration
1347 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1349 # user-specified args must come last: previous releases did this and
1350 # some domU kernels rely upon the ordering.
1351 kernel_args = sxp.child_value(image_sxp, 'args', '')
1353 # attempt to extract extra arguments from SXP config
1354 arg_ip = sxp.child_value(image_sxp, 'ip')
1355 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1356 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1357 arg_root = sxp.child_value(image_sxp, 'root')
1358 if arg_root and not re.search(r'root=', kernel_args):
1359 kernel_args = 'root=%s ' % arg_root + kernel_args
1361 if bootloader:
1362 self['_temp_using_bootloader'] = '1'
1363 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1364 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1365 self['_temp_args'] = kernel_args
1366 else:
1367 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1368 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1369 self['PV_args'] = kernel_args
1371 for key in XENAPI_PLATFORM_CFG:
1372 val = sxp.child_value(image_sxp, key, None)
1373 if val is not None and val != '':
1374 self['platform'][key] = val
1376 notes = sxp.children(image_sxp, 'notes')
1377 if notes:
1378 self['notes'] = self.notes_from_sxp(notes[0])
1380 self._hvm_boot_params_from_sxp(image_sxp)
1382 def set_notes(self, notes):
1383 'Add parsed elfnotes to image'
1384 self['notes'] = notes
1386 def get_notes(self):
1387 try:
1388 return self['notes'] or {}
1389 except KeyError:
1390 return {}
1392 def notes_from_sxp(self, nsxp):
1393 notes = {}
1394 for note in sxp.children(nsxp):
1395 notes[note[0]] = note[1]
1396 return notes
1398 def notes_sxp(self, notes):
1399 nsxp = ['notes']
1400 for k, v in notes.iteritems():
1401 nsxp.append([k, str(v)])
1402 return nsxp
1404 def _hvm_boot_params_from_sxp(self, image_sxp):
1405 boot = sxp.child_value(image_sxp, 'boot', None)
1406 if boot is not None:
1407 self['HVM_boot_policy'] = 'BIOS order'
1408 self['HVM_boot_params'] = { 'order' : boot }
1410 def is_hvm(self):
1411 return self['HVM_boot_policy'] != ''
1413 def image_type(self):
1414 stored_type = self['platform'].get('image_type')
1415 return stored_type or (self.is_hvm() and 'hvm' or 'linux')