ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 14973:53b9883bbcc3

Allow dynamic_min/dynamic_max to (temporarily) be out of sync; in practice
we keep them identical but non-atomically.

Signed-off-by: Steven Hand <steven@xensource.com>
author Steven Hand <steven@xensource.com>
date Fri Apr 27 14:45:06 2007 +0100 (2007-04-27)
parents 2fe1f293e52d
children 476efa5c9abf
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' and not target[param]:
992 # Compat hack -- this is the first disk, so mark it
993 # bootable.
994 dev_info['bootable'] = 1
995 target[param].append(dev_uuid)
996 elif dev_type == 'tap':
997 if 'vbd_refs' not in target:
998 target['vbd_refs'] = []
999 if dev_uuid not in target['vbd_refs']:
1000 if not target['vbd_refs']:
1001 # Compat hack -- this is the first disk, so mark it
1002 # bootable.
1003 dev_info['bootable'] = 1
1004 target['vbd_refs'].append(dev_uuid)
1006 elif dev_type == 'vfb':
1007 # Populate other config with aux data that is associated
1008 # with vfb
1010 other_config = {}
1011 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1012 'vncpasswd', 'type', 'display', 'xauthority',
1013 'keymap']:
1014 if key in dev_info:
1015 other_config[key] = dev_info[key]
1016 target['devices'][dev_uuid][1]['other_config'] = other_config
1019 if 'console_refs' not in target:
1020 target['console_refs'] = []
1022 # Treat VFB devices as console devices so they are found
1023 # through Xen API
1024 if dev_uuid not in target['console_refs']:
1025 target['console_refs'].append(dev_uuid)
1027 elif dev_type == 'console':
1028 if 'console_refs' not in target:
1029 target['console_refs'] = []
1030 if dev_uuid not in target['console_refs']:
1031 target['console_refs'].append(dev_uuid)
1033 return dev_uuid
1035 if cfg_xenapi:
1036 dev_info = {}
1037 dev_uuid = ''
1038 if dev_type == 'vif':
1039 if cfg_xenapi.get('MAC'): # don't add if blank
1040 dev_info['mac'] = cfg_xenapi.get('MAC')
1041 # vifname is the name on the guest, not dom0
1042 # TODO: we don't have the ability to find that out or
1043 # change it from dom0
1044 #if cfg_xenapi.get('device'): # don't add if blank
1045 # dev_info['vifname'] = cfg_xenapi.get('device')
1046 if cfg_xenapi.get('type'):
1047 dev_info['type'] = cfg_xenapi.get('type')
1048 if cfg_xenapi.get('name'):
1049 dev_info['name'] = cfg_xenapi.get('name')
1050 if cfg_xenapi.get('network'):
1051 network = XendAPIStore.get(
1052 cfg_xenapi.get('network'), 'network')
1053 dev_info['bridge'] = network.get_name_label()
1055 dev_uuid = cfg_xenapi.get('uuid', None)
1056 if not dev_uuid:
1057 dev_uuid = uuid.createString()
1058 dev_info['uuid'] = dev_uuid
1059 target['devices'][dev_uuid] = (dev_type, dev_info)
1060 target['vif_refs'].append(dev_uuid)
1062 elif dev_type in ('vbd', 'tap'):
1063 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1064 if dev_info['type'] == 'CD':
1065 old_vbd_type = 'cdrom'
1066 else:
1067 old_vbd_type = 'disk'
1069 dev_info['uname'] = cfg_xenapi.get('image', '')
1070 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1071 old_vbd_type)
1072 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1073 dev_info['driver'] = cfg_xenapi.get('driver', '')
1074 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1076 if cfg_xenapi.get('mode') == 'RW':
1077 dev_info['mode'] = 'w'
1078 else:
1079 dev_info['mode'] = 'r'
1081 dev_uuid = cfg_xenapi.get('uuid', None)
1082 if not dev_uuid:
1083 dev_uuid = uuid.createString()
1084 dev_info['uuid'] = dev_uuid
1085 target['devices'][dev_uuid] = (dev_type, dev_info)
1086 target['vbd_refs'].append(dev_uuid)
1088 elif dev_type == 'vtpm':
1089 if cfg_xenapi.get('type'):
1090 dev_info['type'] = cfg_xenapi.get('type')
1092 dev_uuid = cfg_xenapi.get('uuid', None)
1093 if not dev_uuid:
1094 dev_uuid = uuid.createString()
1095 dev_info['uuid'] = dev_uuid
1096 target['devices'][dev_uuid] = (dev_type, dev_info)
1097 target['vtpm_refs'].append(dev_uuid)
1099 elif dev_type == 'console':
1100 dev_uuid = cfg_xenapi.get('uuid', None)
1101 if not dev_uuid:
1102 dev_uuid = uuid.createString()
1103 dev_info['uuid'] = dev_uuid
1104 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1105 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1106 if dev_info['protocol'] == 'rfb':
1107 # collapse other config into devinfo for things
1108 # such as vncpasswd, vncunused, etc.
1109 dev_info.update(cfg_xenapi.get('other_config', {}))
1110 dev_info['type'] = 'vnc'
1111 target['devices'][dev_uuid] = ('vfb', dev_info)
1112 target['console_refs'].append(dev_uuid)
1114 # Finally, if we are a pvfb, we need to make a vkbd
1115 # as well that is not really exposed to Xen API
1116 vkbd_uuid = uuid.createString()
1117 target['devices'][vkbd_uuid] = ('vkbd', {})
1119 elif dev_info['protocol'] == 'vt100':
1120 # if someone tries to create a VT100 console
1121 # via the Xen API, we'll have to ignore it
1122 # because we create one automatically in
1123 # XendDomainInfo._update_consoles
1124 raise XendConfigError('Creating vt100 consoles via '
1125 'Xen API is unsupported')
1127 return dev_uuid
1129 # no valid device to add
1130 return ''
1132 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1133 target = None):
1134 """Add a phantom tap device configuration in XenAPI struct format.
1135 """
1137 if target == None:
1138 target = self
1140 if dev_type not in XendDevices.valid_devices() and \
1141 dev_type not in XendDevices.pseudo_devices():
1142 raise XendConfigError("XendConfig: %s not a valid device type" %
1143 dev_type)
1145 if cfg_xenapi == None:
1146 raise XendConfigError("XendConfig: device_add requires some "
1147 "config.")
1149 if cfg_xenapi:
1150 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1152 if cfg_xenapi:
1153 dev_info = {}
1154 if dev_type in ('vbd', 'tap'):
1155 if dev_type == 'vbd':
1156 dev_info['uname'] = cfg_xenapi.get('image', '')
1157 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1158 elif dev_type == 'tap':
1159 if cfg_xenapi.get('image').find('tap:') == -1:
1160 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1161 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1162 dev_info['uname'] = cfg_xenapi.get('image')
1163 dev_info['mode'] = cfg_xenapi.get('mode')
1164 dev_info['backend'] = '0'
1165 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1166 dev_info['uuid'] = dev_uuid
1167 self['devices'][dev_uuid] = (dev_type, dev_info)
1168 self['vbd_refs'].append(dev_uuid)
1169 return dev_uuid
1171 return ''
1173 def console_add(self, protocol, location, other_config = {}):
1174 dev_uuid = uuid.createString()
1175 if protocol == 'vt100':
1176 dev_info = {
1177 'uuid': dev_uuid,
1178 'protocol': protocol,
1179 'location': location,
1180 'other_config': other_config,
1183 if 'devices' not in self:
1184 self['devices'] = {}
1186 self['devices'][dev_uuid] = ('console', dev_info)
1187 self['console_refs'].append(dev_uuid)
1188 return dev_info
1190 return {}
1192 def console_update(self, console_uuid, key, value):
1193 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1194 if dev_uuid == console_uuid:
1195 dev_info[key] = value
1196 break
1198 def console_get_all(self, protocol):
1199 if protocol == 'vt100':
1200 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1201 if dtype == 'console']
1202 return [c for c in consoles if c.get('protocol') == protocol]
1204 elif protocol == 'rfb':
1205 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1206 if dtype == 'vfb']
1208 # move all non-console key values to other_config before
1209 # returning console config
1210 valid_keys = ['uuid', 'location']
1211 for vfb in vfbs:
1212 other_config = {}
1213 for key, val in vfb.items():
1214 if key not in valid_keys:
1215 other_config[key] = vfb[key]
1216 del vfb[key]
1217 vfb['other_config'] = other_config
1218 vfb['protocol'] = 'rfb'
1220 return vfbs
1222 else:
1223 return []
1225 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1226 """Update an existing device with the new configuration.
1228 @rtype: boolean
1229 @return: Returns True if succesfully found and updated a device conf
1230 """
1231 if dev_uuid in self['devices'] and cfg_sxp:
1232 if sxp.child0(cfg_sxp) == 'device':
1233 config = sxp.child0(cfg_sxp)
1234 else:
1235 config = cfg_sxp
1237 dev_type, dev_info = self['devices'][dev_uuid]
1238 for opt_val in config[1:]:
1239 try:
1240 opt, val = opt_val
1241 dev_info[opt] = val
1242 except (TypeError, ValueError):
1243 pass # no value for this config option
1245 self['devices'][dev_uuid] = (dev_type, dev_info)
1246 return True
1248 elif dev_uuid in self['devices'] and cfg_xenapi:
1249 dev_type, dev_info = self['devices'][dev_uuid]
1250 for key, val in cfg_xenapi.items():
1251 dev_info[key] = val
1252 self['devices'][dev_uuid] = (dev_type, dev_info)
1254 return False
1257 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
1258 """Get Device SXPR by either giving the device UUID or (type, config).
1260 @rtype: list of lists
1261 @return: device config sxpr
1262 """
1263 sxpr = []
1264 if dev_uuid != None and dev_uuid in self['devices']:
1265 dev_type, dev_info = self['devices'][dev_uuid]
1267 if dev_type == None or dev_info == None:
1268 raise XendConfigError("Required either UUID or device type and "
1269 "configuration dictionary.")
1271 sxpr.append(dev_type)
1272 if dev_type in ('console', 'vfb'):
1273 config = [(opt, val) for opt, val in dev_info.items()
1274 if opt != 'other_config']
1275 else:
1276 config = [(opt, val) for opt, val in dev_info.items()]
1278 sxpr += config
1280 return sxpr
1282 def ordered_device_refs(self):
1283 result = []
1284 # vkbd devices *must* be before vfb devices, otherwise
1285 # there is a race condition when setting up devices
1286 # where the daemon spawned for the vfb may write stuff
1287 # into xenstore vkbd backend, before DevController has
1288 # setup permissions on the vkbd backend path. This race
1289 # results in domain creation failing with 'device already
1290 # connected' messages
1291 result.extend([u for u in self['devices'].keys() if self['devices'][u][0] == 'vkbd'])
1293 result.extend(self['console_refs'] +
1294 self['vbd_refs'] +
1295 self['vif_refs'] +
1296 self['vtpm_refs'])
1298 result.extend([u for u in self['devices'].keys() if u not in result])
1299 return result
1301 def all_devices_sxpr(self):
1302 """Returns the SXPR for all devices in the current configuration."""
1303 sxprs = []
1304 pci_devs = []
1306 if 'devices' not in self:
1307 return sxprs
1309 ordered_refs = self.ordered_device_refs()
1310 for dev_uuid in ordered_refs:
1311 dev_type, dev_info = self['devices'][dev_uuid]
1312 if dev_type == 'pci': # special case for pci devices
1313 sxpr = [['uuid', dev_info['uuid']]]
1314 for pci_dev_info in dev_info['devs']:
1315 pci_dev_sxpr = ['dev']
1316 for opt, val in pci_dev_info.items():
1317 pci_dev_sxpr.append([opt, val])
1318 sxpr.append(pci_dev_sxpr)
1319 sxprs.append((dev_type, sxpr))
1320 else:
1321 sxpr = self.device_sxpr(dev_type = dev_type,
1322 dev_info = dev_info)
1323 sxprs.append((dev_type, sxpr))
1325 return sxprs
1327 def image_sxpr(self):
1328 """Returns a backwards compatible image SXP expression that is
1329 used in xenstore's /vm/<uuid>/image value and xm list."""
1330 image = [self.image_type()]
1331 if self.has_key('PV_kernel'):
1332 image.append(['kernel', self['PV_kernel']])
1333 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1334 image.append(['ramdisk', self['PV_ramdisk']])
1335 if self.has_key('PV_args') and self['PV_args']:
1336 image.append(['args', self['PV_args']])
1338 for key in XENAPI_PLATFORM_CFG:
1339 if key in self['platform']:
1340 image.append([key, self['platform'][key]])
1342 if 'notes' in self:
1343 image.append(self.notes_sxp(self['notes']))
1345 return image
1347 def update_with_image_sxp(self, image_sxp, bootloader = False):
1348 # Convert Legacy "image" config to Xen API PV_*
1349 # configuration
1350 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1352 # user-specified args must come last: previous releases did this and
1353 # some domU kernels rely upon the ordering.
1354 kernel_args = sxp.child_value(image_sxp, 'args', '')
1356 # attempt to extract extra arguments from SXP config
1357 arg_ip = sxp.child_value(image_sxp, 'ip')
1358 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1359 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1360 arg_root = sxp.child_value(image_sxp, 'root')
1361 if arg_root and not re.search(r'root=', kernel_args):
1362 kernel_args = 'root=%s ' % arg_root + kernel_args
1364 if bootloader:
1365 self['_temp_using_bootloader'] = '1'
1366 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1367 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1368 self['_temp_args'] = kernel_args
1369 else:
1370 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1371 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1372 self['PV_args'] = kernel_args
1374 for key in XENAPI_PLATFORM_CFG:
1375 val = sxp.child_value(image_sxp, key, None)
1376 if val is not None and val != '':
1377 self['platform'][key] = val
1379 notes = sxp.children(image_sxp, 'notes')
1380 if notes:
1381 self['notes'] = self.notes_from_sxp(notes[0])
1383 self._hvm_boot_params_from_sxp(image_sxp)
1385 def set_notes(self, notes):
1386 'Add parsed elfnotes to image'
1387 self['notes'] = notes
1389 def get_notes(self):
1390 try:
1391 return self['notes'] or {}
1392 except KeyError:
1393 return {}
1395 def notes_from_sxp(self, nsxp):
1396 notes = {}
1397 for note in sxp.children(nsxp):
1398 notes[note[0]] = note[1]
1399 return notes
1401 def notes_sxp(self, notes):
1402 nsxp = ['notes']
1403 for k, v in notes.iteritems():
1404 nsxp.append([k, str(v)])
1405 return nsxp
1407 def _hvm_boot_params_from_sxp(self, image_sxp):
1408 boot = sxp.child_value(image_sxp, 'boot', None)
1409 if boot is not None:
1410 self['HVM_boot_policy'] = 'BIOS order'
1411 self['HVM_boot_params'] = { 'order' : boot }
1413 def is_hvm(self):
1414 return self['HVM_boot_policy'] != ''
1416 def image_type(self):
1417 stored_type = self['platform'].get('image_type')
1418 return stored_type or (self.is_hvm() and 'hvm' or 'linux')