ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 14931:0b4375cd7e16

Translate network uuid to bridge name and store it in XendConfig when createing a new vif.

Fixes a bug where a new vif gets added to the wrong bridge.

signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
author Tom Wilkie <tom.wilkie@gmail.com>
date Wed Apr 25 13:44:37 2007 +0100 (2007-04-25)
parents 8ca89a9e54a7
children 2fe1f293e52d
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', 'monitor',
121 'nographic', 'pae', 'rtc_timeoffset', '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 'rtc/timeoffset': str,
207 }
209 # Values that should be stored in xenstore's /vm/<uuid> that is used
210 # by Xend. Used in XendDomainInfo to restore running VM state from
211 # xenstore.
212 LEGACY_XENSTORE_VM_PARAMS = [
213 'uuid',
214 'name',
215 'vcpus',
216 'vcpu_avail',
217 'memory',
218 'shadow_memory',
219 'maxmem',
220 'start_time',
221 'name',
222 'on_poweroff',
223 'on_crash',
224 'on_reboot',
225 'on_xend_start',
226 'on_xend_stop',
227 ]
229 DEFAULT_DM = '/usr/lib/xen/bin/qemu-dm'
231 ##
232 ## Config Choices
233 ##
235 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart')
236 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
237 'crashed', 'dying')
239 class XendConfigError(VmError):
240 def __str__(self):
241 return 'Invalid Configuration: %s' % str(self.value)
243 ##
244 ## XendConfig Class (an extended dictionary)
245 ##
247 class XendConfig(dict):
248 """ The new Xend VM Configuration.
250 Stores the configuration in xenapi compatible format but retains
251 import and export functions for SXP.
252 """
253 def __init__(self, filename = None, sxp_obj = None,
254 xapi = None, dominfo = None):
256 dict.__init__(self)
257 self.update(self._defaults())
259 if filename:
260 try:
261 sxp_obj = sxp.parse(open(filename,'r'))
262 sxp_obj = sxp_obj[0]
263 except IOError, e:
264 raise XendConfigError("Unable to read file: %s" % filename)
266 if sxp_obj:
267 self._sxp_to_xapi(sxp_obj)
268 self._sxp_to_xapi_unsupported(sxp_obj)
269 elif xapi:
270 self.update_with_xenapi_config(xapi)
271 elif dominfo:
272 # output from xc.domain_getinfo
273 self._dominfo_to_xapi(dominfo, update_mem = True)
275 log.debug('XendConfig.init: %s' % scrub_password(self))
277 # validators go here
278 self.validate()
280 """ In time, we should enable this type checking addition. It is great
281 also for tracking bugs and unintended writes to XendDomainInfo.info
282 def __setitem__(self, key, value):
283 type_conv = XENAPI_CFG_TYPES.get(key)
284 if callable(type_conv):
285 try:
286 dict.__setitem__(self, key, type_conv(value))
287 except (ValueError, TypeError):
288 raise XendConfigError("Wrong type for configuration value " +
289 "%s. Expected %s" %
290 (key, type_conv.__name__))
291 else:
292 dict.__setitem__(self, key, value)
293 """
295 def _defaults(self):
296 defaults = {
297 'name_label': 'Domain-Unnamed',
298 'actions_after_shutdown': 'destroy',
299 'actions_after_reboot': 'restart',
300 'actions_after_crash': 'restart',
301 'actions_after_suspend': '',
302 'is_a_template': False,
303 'is_control_domain': False,
304 'features': '',
305 'PV_bootloader': '',
306 'PV_kernel': '',
307 'PV_ramdisk': '',
308 'PV_args': '',
309 'PV_bootloader_args': '',
310 'HVM_boot_policy': '',
311 'HVM_boot_params': {},
312 'memory_static_min': 0,
313 'memory_dynamic_min': 0,
314 'shadow_memory': 0,
315 'memory_static_max': 0,
316 'memory_dynamic_max': 0,
317 'devices': {},
318 'security': None,
319 'on_xend_start': 'ignore',
320 'on_xend_stop': 'ignore',
321 'cpus': [],
322 'cpu_weight': 256,
323 'cpu_cap': 0,
324 'VCPUs_max': 1,
325 'VCPUs_live': 1,
326 'VCPUs_at_startup': 1,
327 'vcpus_params': {},
328 'console_refs': [],
329 'vif_refs': [],
330 'vbd_refs': [],
331 'vtpm_refs': [],
332 'other_config': {},
333 'platform': {}
334 }
336 return defaults
338 #
339 # Here we assume these values exist in the dict.
340 # If they don't we have a bigger problem, lets not
341 # try and 'fix it up' but acutually fix the cause ;-)
342 #
343 def _memory_sanity_check(self):
344 log.trace("_memory_sanity_check memory_static_min: %s, "
345 "memory_static_max: %i, "
346 "memory_dynamic_min: %i, "
347 "memory_dynamic_max: %i",
348 self["memory_static_min"],
349 self["memory_static_max"],
350 self["memory_dynamic_min"],
351 self["memory_dynamic_max"])
353 if not self["memory_static_min"] <= self["memory_static_max"]:
354 raise XendConfigError("memory_static_min must be less " \
355 "than or equal to memory_static_max")
356 if not self["memory_dynamic_min"] <= self["memory_dynamic_max"]:
357 raise XendConfigError("memory_dynamic_min must be less " \
358 "than or equal to memory_dynamic_max")
359 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
360 raise XendConfigError("memory_static_min must be less " \
361 "than or equal to memory_dynamic_min")
362 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
363 raise XendConfigError("memory_dynamic_max must be less " \
364 "than or equal to memory_static_max")
365 if not self["memory_dynamic_max"] > 0:
366 raise XendConfigError("memory_dynamic_max must be greater " \
367 "than zero")
368 if not self["memory_static_max"] > 0:
369 raise XendConfigError("memory_static_max must be greater " \
370 "than zero")
372 def _actions_sanity_check(self):
373 for event in ['shutdown', 'reboot', 'crash']:
374 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
375 raise XendConfigError('Invalid event handling mode: ' +
376 event)
378 def _vcpus_sanity_check(self):
379 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
380 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
382 def _uuid_sanity_check(self):
383 """Make sure UUID is in proper string format with hyphens."""
384 if 'uuid' not in self or not self['uuid']:
385 self['uuid'] = uuid.createString()
386 else:
387 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
389 def _name_sanity_check(self):
390 if 'name_label' not in self:
391 self['name_label'] = 'Domain-' + self['uuid']
393 def _platform_sanity_check(self):
394 if self.is_hvm():
395 if 'device_model' not in self['platform']:
396 self['platform']['device_model'] = DEFAULT_DM
398 # Compatibility hack, can go away soon.
399 if 'soundhw' not in self['platform'] and \
400 self['platform'].get('enable_audio'):
401 self['platform']['soundhw'] = 'sb16'
403 def validate(self):
404 self._uuid_sanity_check()
405 self._name_sanity_check()
406 self._memory_sanity_check()
407 self._actions_sanity_check()
408 self._vcpus_sanity_check()
409 self._platform_sanity_check()
411 def _dominfo_to_xapi(self, dominfo, update_mem = False):
412 self['domid'] = dominfo['domid']
413 self['online_vcpus'] = dominfo['online_vcpus']
414 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
416 if update_mem:
417 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
418 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
419 self['memory_static_min'] = 0
420 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
421 self._memory_sanity_check()
423 self['cpu_time'] = dominfo['cpu_time']/1e9
424 # TODO: i don't know what the security stuff expects here
425 if dominfo.get('ssidref'):
426 self['security'] = [['ssidref', dominfo['ssidref']]]
427 self['shutdown_reason'] = dominfo['shutdown_reason']
429 # parse state into Xen API states
430 self['running'] = dominfo['running']
431 self['crashed'] = dominfo['crashed']
432 self['dying'] = dominfo['dying']
433 self['shutdown'] = dominfo['shutdown']
434 self['paused'] = dominfo['paused']
435 self['blocked'] = dominfo['blocked']
437 if 'name' in dominfo:
438 self['name_label'] = dominfo['name']
440 if 'handle' in dominfo:
441 self['uuid'] = uuid.toString(dominfo['handle'])
443 def _parse_sxp(self, sxp_cfg):
444 """ Populate this XendConfig using the parsed SXP.
446 @param sxp_cfg: Parsed SXP Configuration
447 @type sxp_cfg: list of lists
448 @rtype: dictionary
449 @return: A dictionary containing the parsed options of the SXP.
450 """
451 cfg = {}
453 for key, typ in XENAPI_CFG_TYPES.items():
454 val = sxp.child_value(sxp_cfg, key)
455 if val is not None:
456 try:
457 cfg[key] = typ(val)
458 except (ValueError, TypeError), e:
459 log.warn('Unable to convert type value for key: %s' % key)
461 # Convert deprecated options to current equivalents.
463 restart = sxp.child_value(sxp_cfg, 'restart')
464 if restart:
465 if restart == 'onreboot':
466 cfg['on_poweroff'] = 'destroy'
467 cfg['on_reboot'] = 'restart'
468 cfg['on_crash'] = 'destroy'
469 elif restart == 'always':
470 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
471 cfg[opt] = 'restart'
472 elif restart == 'never':
473 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
474 cfg[opt] = 'never'
475 else:
476 log.warn('Ignoring unrecognised value for deprecated option:'
477 'restart = \'%s\'', restart)
479 # Handle memory, passed in as MiB
481 if sxp.child_value(sxp_cfg, "memory") != None:
482 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
483 if sxp.child_value(sxp_cfg, "maxmem") != None:
484 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
486 # Only extract options we know about.
487 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
488 extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
490 for key in extract_keys:
491 val = sxp.child_value(sxp_cfg, key)
492 if val != None:
493 try:
494 cfg[key] = LEGACY_CFG_TYPES[key](val)
495 except KeyError:
496 cfg[key] = val
497 except (TypeError, ValueError), e:
498 log.warn("Unable to parse key %s: %s: %s" %
499 (key, str(val), e))
501 if 'platform' not in cfg:
502 cfg['platform'] = {}
503 localtime = sxp.child_value(sxp_cfg, 'localtime')
504 if localtime is not None:
505 cfg['platform']['localtime'] = localtime
507 # Compatibility hack -- can go soon.
508 for key in XENAPI_PLATFORM_CFG:
509 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
510 if val is not None:
511 self['platform'][key] = val
513 # Compatibility hack -- can go soon.
514 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
515 if boot_order:
516 cfg['HVM_boot_policy'] = 'BIOS order'
517 cfg['HVM_boot_params'] = { 'order' : boot_order }
519 # Parsing the device SXP's. In most cases, the SXP looks
520 # like this:
521 #
522 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
523 #
524 # However, for PCI devices it looks like this:
525 #
526 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
527 #
528 # It seems the reasoning for this difference is because
529 # pciif.py needs all the PCI device configurations at
530 # the same time when creating the devices.
531 #
532 # To further complicate matters, Xen 2.0 configuration format
533 # uses the following for pci device configuration:
534 #
535 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
536 #
537 # Hence we deal with pci device configurations outside of
538 # the regular device parsing.
540 cfg['devices'] = {}
541 for dev in sxp.children(sxp_cfg, 'device'):
542 config = sxp.child0(dev)
543 dev_type = sxp.name(config)
544 dev_info = {}
546 if dev_type == 'pci':
547 pci_devs_uuid = sxp.child_value(config, 'uuid',
548 uuid.createString())
549 pci_devs = []
550 for pci_dev in sxp.children(config, 'dev'):
551 pci_dev_info = {}
552 for opt_val in pci_dev[1:]:
553 try:
554 opt, val = opt_val
555 pci_dev_info[opt] = val
556 except TypeError:
557 pass
558 pci_devs.append(pci_dev_info)
560 cfg['devices'][pci_devs_uuid] = (dev_type,
561 {'devs': pci_devs,
562 'uuid': pci_devs_uuid})
564 log.debug("XendConfig: reading device: %s" % pci_devs)
565 else:
566 self.device_add(dev_type, cfg_sxp = config, target = cfg)
567 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
569 # Extract missing data from configuration entries
570 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
571 if image_sxp:
572 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
573 if image_vcpus != None:
574 try:
575 if 'VCPUs_max' not in cfg:
576 cfg['VCPUs_max'] = int(image_vcpus)
577 elif cfg['VCPUs_max'] != int(image_vcpus):
578 cfg['VCPUs_max'] = int(image_vcpus)
579 log.warn('Overriding vcpus from %d to %d using image'
580 'vcpus value.', cfg['VCPUs_max'])
581 except ValueError, e:
582 raise XendConfigError('integer expeceted: %s: %s' %
583 image_sxp, e)
585 # Deprecated cpu configuration
586 if 'cpu' in cfg:
587 if 'cpus' in cfg:
588 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
589 else:
590 cfg['cpus'] = str(cfg['cpu'])
592 # convert 'cpus' string to list of ints
593 # 'cpus' supports a list of ranges (0-3), seperated by
594 # commas, and negation, (^1).
595 # Precedence is settled by order of the string:
596 # "0-3,^1" -> [0,2,3]
597 # "0-3,^1,1" -> [0,1,2,3]
598 try:
599 if 'cpus' in cfg and type(cfg['cpus']) != list:
600 cpus = []
601 for c in cfg['cpus'].split(','):
602 if c.find('-') != -1:
603 (x, y) = c.split('-')
604 for i in range(int(x), int(y)+1):
605 cpus.append(int(i))
606 else:
607 # remove this element from the list
608 if c[0] == '^':
609 cpus = [x for x in cpus if x != int(c[1:])]
610 else:
611 cpus.append(int(c))
613 cfg['cpus'] = cpus
614 except ValueError, e:
615 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
617 if 'security' in cfg and isinstance(cfg['security'], str):
618 cfg['security'] = sxp.from_string(cfg['security'])
620 old_state = sxp.child_value(sxp_cfg, 'state')
621 if old_state:
622 for i in range(len(CONFIG_OLD_DOM_STATES)):
623 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
625 return cfg
628 def _sxp_to_xapi(self, sxp_cfg):
629 """Read in an SXP Configuration object and
630 populate at much of the Xen API with valid values.
631 """
632 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
634 cfg = self._parse_sxp(sxp_cfg)
636 for key, typ in XENAPI_CFG_TYPES.items():
637 val = cfg.get(key)
638 if val is not None:
639 self[key] = typ(val)
641 # Convert parameters that can be directly mapped from
642 # the Legacy Config to Xen API Config
644 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
645 try:
646 type_conv = XENAPI_CFG_TYPES.get(apikey)
647 if callable(type_conv):
648 self[apikey] = type_conv(cfg[cfgkey])
649 else:
650 log.warn("Unconverted key: " + apikey)
651 self[apikey] = cfg[cfgkey]
652 except KeyError:
653 pass
655 # Lets try and handle memory correctly
657 MiB = 1024 * 1024
659 if "memory" in cfg:
660 self["memory_static_min"] = 0
661 self["memory_static_max"] = int(cfg["memory"]) * MiB
662 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
663 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
665 if "maxmem" in cfg:
666 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
668 self._memory_sanity_check()
670 def update_with(n, o):
671 if not self.get(n):
672 self[n] = cfg.get(o, '')
674 update_with('PV_bootloader', 'bootloader')
675 update_with('PV_bootloader_args', 'bootloader_args')
677 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
678 if image_sxp:
679 self.update_with_image_sxp(image_sxp)
681 # Convert Legacy HVM parameters to Xen API configuration
682 for key in XENAPI_PLATFORM_CFG:
683 if key in cfg:
684 self['platform'][key] = cfg[key]
686 # set device references in the configuration
687 self['devices'] = cfg.get('devices', {})
688 self['console_refs'] = cfg.get('console_refs', [])
689 self['vif_refs'] = cfg.get('vif_refs', [])
690 self['vbd_refs'] = cfg.get('vbd_refs', [])
691 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
693 # coalesce hvm vnc frame buffer with vfb config
694 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
695 # add vfb device if it isn't there already
696 has_rfb = False
697 for console_uuid in self['console_refs']:
698 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
699 has_rfb = True
700 break
701 if self['devices'][console_uuid][0] == 'vfb':
702 has_rfb = True
703 break
705 if not has_rfb:
706 dev_config = ['vfb']
707 # copy VNC related params from platform config to vfb dev conf
708 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
709 'vnclisten']:
710 if key in self['platform']:
711 dev_config.append([key, self['platform'][key]])
713 self.device_add('vfb', cfg_sxp = dev_config)
716 def _sxp_to_xapi_unsupported(self, sxp_cfg):
717 """Read in an SXP configuration object and populate
718 values are that not related directly supported in
719 the Xen API.
720 """
722 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
724 # Parse and convert parameters used to configure
725 # the image (as well as HVM images)
726 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
727 if image_sxp:
728 image_type = sxp.name(image_sxp)
729 if image_type != 'hvm' and image_type != 'linux':
730 self['platform']['image_type'] = image_type
732 for key in XENAPI_PLATFORM_CFG:
733 val = sxp.child_value(image_sxp, key, None)
734 if val is not None and val != '':
735 self['platform'][key] = val
737 notes = sxp.children(image_sxp, 'notes')
738 if notes:
739 self['notes'] = self.notes_from_sxp(notes[0])
741 self._hvm_boot_params_from_sxp(image_sxp)
743 # extract backend value
745 backend = []
746 for c in sxp.children(sxp_cfg, 'backend'):
747 backend.append(sxp.name(sxp.child0(c)))
748 if backend:
749 self['backend'] = backend
751 # Parse and convert other Non Xen API parameters.
752 def _set_cfg_if_exists(sxp_arg):
753 val = sxp.child_value(sxp_cfg, sxp_arg)
754 if val != None:
755 if LEGACY_CFG_TYPES.get(sxp_arg):
756 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
757 else:
758 self[sxp_arg] = val
760 _set_cfg_if_exists('shadow_memory')
761 _set_cfg_if_exists('security')
762 _set_cfg_if_exists('features')
763 _set_cfg_if_exists('on_xend_stop')
764 _set_cfg_if_exists('on_xend_start')
765 _set_cfg_if_exists('vcpu_avail')
766 _set_cfg_if_exists('cpu_weight')
767 _set_cfg_if_exists('cpu_cap')
769 # Parse and store runtime configuration
770 _set_cfg_if_exists('start_time')
771 _set_cfg_if_exists('cpu_time')
772 _set_cfg_if_exists('shutdown_reason')
773 _set_cfg_if_exists('up_time')
774 _set_cfg_if_exists('status') # TODO, deprecated
776 def _get_old_state_string(self):
777 """Returns the old xm state string.
778 @rtype: string
779 @return: old state string
780 """
781 state_string = ''
782 for state_name in CONFIG_OLD_DOM_STATES:
783 on_off = self.get(state_name, 0)
784 if on_off:
785 state_string += state_name[0]
786 else:
787 state_string += '-'
789 return state_string
792 def update_config(self, dominfo):
793 """Update configuration with the output from xc.domain_getinfo().
795 @param dominfo: Domain information via xc.domain_getinfo()
796 @type dominfo: dict
797 """
798 self._dominfo_to_xapi(dominfo)
799 self.validate()
801 def update_with_xenapi_config(self, xapi):
802 """Update configuration with a Xen API VM struct
804 @param xapi: Xen API VM Struct
805 @type xapi: dict
806 """
808 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
810 for key, val in xapi.items():
811 type_conv = XENAPI_CFG_TYPES.get(key)
812 if type_conv is None:
813 key = key.lower()
814 type_conv = XENAPI_CFG_TYPES.get(key)
815 if callable(type_conv):
816 self[key] = type_conv(val)
817 else:
818 self[key] = val
820 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
821 legacy_only = True):
822 """ Get SXP representation of this config object.
824 Incompat: removed store_mfn, console_mfn
826 @keyword domain: (optional) XendDomainInfo to get extra information
827 from such as domid and running devices.
828 @type domain: XendDomainInfo
829 @keyword ignore: (optional) list of 'keys' that we do not want
830 to export.
831 @type ignore: list of strings
832 @rtype: list of list (SXP representation)
833 """
834 sxpr = ['domain']
836 # TODO: domid/dom is the same thing but called differently
837 # depending if it is from xenstore or sxpr.
839 if domain.getDomid() is not None:
840 sxpr.append(['domid', domain.getDomid()])
842 if not legacy_only:
843 for name, typ in XENAPI_CFG_TYPES.items():
844 if name in self and self[name] not in (None, []):
845 if typ == dict:
846 s = self[name].items()
847 else:
848 s = str(self[name])
849 sxpr.append([name, s])
851 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
852 if legacy in ('cpus'): # skip this
853 continue
854 if self.has_key(xenapi) and self[xenapi] not in (None, []):
855 if type(self[xenapi]) == bool:
856 # convert booleans to ints before making an sxp item
857 sxpr.append([legacy, int(self[xenapi])])
858 else:
859 sxpr.append([legacy, self[xenapi]])
861 MiB = 1024*1024
863 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
864 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
866 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
867 if legacy in ('domid', 'uuid', 'cpus'): # skip these
868 continue
869 if self.has_key(legacy) and self[legacy] not in (None, []):
870 sxpr.append([legacy, self[legacy]])
872 sxpr.append(['image', self.image_sxpr()])
873 sxpr.append(['status', domain._stateGet()])
875 if domain.getDomid() is not None:
876 sxpr.append(['state', self._get_old_state_string()])
878 if domain:
879 if domain.store_mfn:
880 sxpr.append(['store_mfn', domain.store_mfn])
881 if domain.console_mfn:
882 sxpr.append(['console_mfn', domain.console_mfn])
885 # Marshall devices (running or from configuration)
886 if not ignore_devices:
887 for cls in XendDevices.valid_devices():
888 found = False
890 # figure if there is a dev controller is valid and running
891 if domain and domain.getDomid() != None:
892 try:
893 controller = domain.getDeviceController(cls)
894 configs = controller.configurations()
895 for config in configs:
896 if sxp.name(config) in ('vbd', 'tap'):
897 # The bootable flag is never written to the
898 # store as part of the device config.
899 dev_uuid = sxp.child_value(config, 'uuid')
900 dev_type, dev_cfg = self['devices'][dev_uuid]
901 is_bootable = dev_cfg.get('bootable', 0)
902 config.append(['bootable', int(is_bootable)])
904 sxpr.append(['device', config])
906 found = True
907 except:
908 log.exception("dumping sxp from device controllers")
909 pass
911 # if we didn't find that device, check the existing config
912 # for a device in the same class
913 if not found:
914 for dev_type, dev_info in self.all_devices_sxpr():
915 if dev_type == cls:
916 sxpr.append(['device', dev_info])
918 return sxpr
920 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
921 target = None):
922 """Add a device configuration in SXP format or XenAPI struct format.
924 For SXP, it could be either:
926 [device, [vbd, [uname ...]]
928 or:
930 [vbd, [uname ..]]
932 @type cfg_sxp: list of lists (parsed sxp object)
933 @param cfg_sxp: SXP configuration object
934 @type cfg_xenapi: dict
935 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
936 @param target: write device information to
937 @type target: None or a dictionary
938 @rtype: string
939 @return: Assigned UUID of the device.
940 """
941 if target == None:
942 target = self
944 if dev_type not in XendDevices.valid_devices():
945 raise XendConfigError("XendConfig: %s not a valid device type" %
946 dev_type)
948 if cfg_sxp == None and cfg_xenapi == None:
949 raise XendConfigError("XendConfig: device_add requires some "
950 "config.")
952 #if cfg_sxp:
953 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
954 #if cfg_xenapi:
955 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
957 if cfg_sxp:
958 if sxp.child0(cfg_sxp) == 'device':
959 config = sxp.child0(cfg_sxp)
960 else:
961 config = cfg_sxp
963 dev_type = sxp.name(config)
964 dev_info = {}
966 for opt_val in config[1:]:
967 try:
968 opt, val = opt_val
969 dev_info[opt] = val
970 except (TypeError, ValueError): # unpack error
971 pass
973 if dev_type == 'vbd':
974 dev_info['bootable'] = 0
975 if dev_info.get('dev', '').startswith('ioemu:'):
976 dev_info['driver'] = 'ioemu'
977 else:
978 dev_info['driver'] = 'paravirtualised'
980 # create uuid if it doesn't exist
981 dev_uuid = dev_info.get('uuid', None)
982 if not dev_uuid:
983 dev_uuid = uuid.createString()
984 dev_info['uuid'] = dev_uuid
986 # store dev references by uuid for certain device types
987 target['devices'][dev_uuid] = (dev_type, dev_info)
988 if dev_type in ('vif', 'vbd', 'vtpm'):
989 param = '%s_refs' % dev_type
990 if param not in target:
991 target[param] = []
992 if dev_uuid not in target[param]:
993 if dev_type == 'vbd' and not target[param]:
994 # Compat hack -- this is the first disk, so mark it
995 # bootable.
996 dev_info['bootable'] = 1
997 target[param].append(dev_uuid)
998 elif dev_type == 'tap':
999 if 'vbd_refs' not in target:
1000 target['vbd_refs'] = []
1001 if dev_uuid not in target['vbd_refs']:
1002 if not target['vbd_refs']:
1003 # Compat hack -- this is the first disk, so mark it
1004 # bootable.
1005 dev_info['bootable'] = 1
1006 target['vbd_refs'].append(dev_uuid)
1008 elif dev_type == 'vfb':
1009 # Populate other config with aux data that is associated
1010 # with vfb
1012 other_config = {}
1013 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1014 'vncpasswd', 'type', 'display', 'xauthority',
1015 'keymap']:
1016 if key in dev_info:
1017 other_config[key] = dev_info[key]
1018 target['devices'][dev_uuid][1]['other_config'] = other_config
1021 if 'console_refs' not in target:
1022 target['console_refs'] = []
1024 # Treat VFB devices as console devices so they are found
1025 # through Xen API
1026 if dev_uuid not in target['console_refs']:
1027 target['console_refs'].append(dev_uuid)
1029 elif dev_type == 'console':
1030 if 'console_refs' not in target:
1031 target['console_refs'] = []
1032 if dev_uuid not in target['console_refs']:
1033 target['console_refs'].append(dev_uuid)
1035 return dev_uuid
1037 if cfg_xenapi:
1038 dev_info = {}
1039 dev_uuid = ''
1040 if dev_type == 'vif':
1041 if cfg_xenapi.get('MAC'): # don't add if blank
1042 dev_info['mac'] = cfg_xenapi.get('MAC')
1043 # vifname is the name on the guest, not dom0
1044 # TODO: we don't have the ability to find that out or
1045 # change it from dom0
1046 #if cfg_xenapi.get('device'): # don't add if blank
1047 # dev_info['vifname'] = cfg_xenapi.get('device')
1048 if cfg_xenapi.get('type'):
1049 dev_info['type'] = cfg_xenapi.get('type')
1050 if cfg_xenapi.get('name'):
1051 dev_info['name'] = cfg_xenapi.get('name')
1052 if cfg_xenapi.get('network'):
1053 from xen.xend.XendNode import XendAPIInstanceStore
1054 network = XendAPIInstanceStore.get(
1055 cfg_xenapi.get('network'), 'network')
1056 dev_info['bridge'] = network.get_name_label()
1058 dev_uuid = cfg_xenapi.get('uuid', None)
1059 if not dev_uuid:
1060 dev_uuid = uuid.createString()
1061 dev_info['uuid'] = dev_uuid
1062 target['devices'][dev_uuid] = (dev_type, dev_info)
1063 target['vif_refs'].append(dev_uuid)
1065 elif dev_type in ('vbd', 'tap'):
1066 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1067 if dev_info['type'] == 'CD':
1068 old_vbd_type = 'cdrom'
1069 else:
1070 old_vbd_type = 'disk'
1072 dev_info['uname'] = cfg_xenapi.get('image', '')
1073 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1074 old_vbd_type)
1075 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1076 dev_info['driver'] = cfg_xenapi.get('driver', '')
1077 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1079 if cfg_xenapi.get('mode') == 'RW':
1080 dev_info['mode'] = 'w'
1081 else:
1082 dev_info['mode'] = 'r'
1084 dev_uuid = cfg_xenapi.get('uuid', None)
1085 if not dev_uuid:
1086 dev_uuid = uuid.createString()
1087 dev_info['uuid'] = dev_uuid
1088 target['devices'][dev_uuid] = (dev_type, dev_info)
1089 target['vbd_refs'].append(dev_uuid)
1091 elif dev_type == 'vtpm':
1092 if cfg_xenapi.get('type'):
1093 dev_info['type'] = cfg_xenapi.get('type')
1095 dev_uuid = cfg_xenapi.get('uuid', None)
1096 if not dev_uuid:
1097 dev_uuid = uuid.createString()
1098 dev_info['uuid'] = dev_uuid
1099 target['devices'][dev_uuid] = (dev_type, dev_info)
1100 target['vtpm_refs'].append(dev_uuid)
1102 elif dev_type == 'console':
1103 dev_uuid = cfg_xenapi.get('uuid', None)
1104 if not dev_uuid:
1105 dev_uuid = uuid.createString()
1106 dev_info['uuid'] = dev_uuid
1107 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1108 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1109 if dev_info['protocol'] == 'rfb':
1110 # collapse other config into devinfo for things
1111 # such as vncpasswd, vncunused, etc.
1112 dev_info.update(cfg_xenapi.get('other_config', {}))
1113 dev_info['type'] = 'vnc'
1114 target['devices'][dev_uuid] = ('vfb', dev_info)
1115 target['console_refs'].append(dev_uuid)
1117 # Finally, if we are a pvfb, we need to make a vkbd
1118 # as well that is not really exposed to Xen API
1119 vkbd_uuid = uuid.createString()
1120 target['devices'][vkbd_uuid] = ('vkbd', {})
1122 elif dev_info['protocol'] == 'vt100':
1123 # if someone tries to create a VT100 console
1124 # via the Xen API, we'll have to ignore it
1125 # because we create one automatically in
1126 # XendDomainInfo._update_consoles
1127 raise XendConfigError('Creating vt100 consoles via '
1128 'Xen API is unsupported')
1130 return dev_uuid
1132 # no valid device to add
1133 return ''
1135 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1136 target = None):
1137 """Add a phantom tap device configuration in XenAPI struct format.
1138 """
1140 if target == None:
1141 target = self
1143 if dev_type not in XendDevices.valid_devices() and \
1144 dev_type not in XendDevices.pseudo_devices():
1145 raise XendConfigError("XendConfig: %s not a valid device type" %
1146 dev_type)
1148 if cfg_xenapi == None:
1149 raise XendConfigError("XendConfig: device_add requires some "
1150 "config.")
1152 if cfg_xenapi:
1153 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1155 if cfg_xenapi:
1156 dev_info = {}
1157 if dev_type in ('vbd', 'tap'):
1158 if dev_type == 'vbd':
1159 dev_info['uname'] = cfg_xenapi.get('image', '')
1160 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1161 elif dev_type == 'tap':
1162 if cfg_xenapi.get('image').find('tap:') == -1:
1163 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1164 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1165 dev_info['uname'] = cfg_xenapi.get('image')
1166 dev_info['mode'] = cfg_xenapi.get('mode')
1167 dev_info['backend'] = '0'
1168 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1169 dev_info['uuid'] = dev_uuid
1170 self['devices'][dev_uuid] = (dev_type, dev_info)
1171 self['vbd_refs'].append(dev_uuid)
1172 return dev_uuid
1174 return ''
1176 def console_add(self, protocol, location, other_config = {}):
1177 dev_uuid = uuid.createString()
1178 if protocol == 'vt100':
1179 dev_info = {
1180 'uuid': dev_uuid,
1181 'protocol': protocol,
1182 'location': location,
1183 'other_config': other_config,
1186 if 'devices' not in self:
1187 self['devices'] = {}
1189 self['devices'][dev_uuid] = ('console', dev_info)
1190 self['console_refs'].append(dev_uuid)
1191 return dev_info
1193 return {}
1195 def console_update(self, console_uuid, key, value):
1196 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1197 if dev_uuid == console_uuid:
1198 dev_info[key] = value
1199 break
1201 def console_get_all(self, protocol):
1202 if protocol == 'vt100':
1203 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1204 if dtype == 'console']
1205 return [c for c in consoles if c.get('protocol') == protocol]
1207 elif protocol == 'rfb':
1208 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1209 if dtype == 'vfb']
1211 # move all non-console key values to other_config before
1212 # returning console config
1213 valid_keys = ['uuid', 'location']
1214 for vfb in vfbs:
1215 other_config = {}
1216 for key, val in vfb.items():
1217 if key not in valid_keys:
1218 other_config[key] = vfb[key]
1219 del vfb[key]
1220 vfb['other_config'] = other_config
1221 vfb['protocol'] = 'rfb'
1223 return vfbs
1225 else:
1226 return []
1228 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1229 """Update an existing device with the new configuration.
1231 @rtype: boolean
1232 @return: Returns True if succesfully found and updated a device conf
1233 """
1234 if dev_uuid in self['devices'] and cfg_sxp:
1235 if sxp.child0(cfg_sxp) == 'device':
1236 config = sxp.child0(cfg_sxp)
1237 else:
1238 config = cfg_sxp
1240 dev_type, dev_info = self['devices'][dev_uuid]
1241 for opt_val in config[1:]:
1242 try:
1243 opt, val = opt_val
1244 dev_info[opt] = val
1245 except (TypeError, ValueError):
1246 pass # no value for this config option
1248 self['devices'][dev_uuid] = (dev_type, dev_info)
1249 return True
1251 elif dev_uuid in self['devices'] and cfg_xenapi:
1252 dev_type, dev_info = self['devices'][dev_uuid]
1253 for key, val in cfg_xenapi.items():
1254 dev_info[key] = val
1255 self['devices'][dev_uuid] = (dev_type, dev_info)
1257 return False
1260 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
1261 """Get Device SXPR by either giving the device UUID or (type, config).
1263 @rtype: list of lists
1264 @return: device config sxpr
1265 """
1266 sxpr = []
1267 if dev_uuid != None and dev_uuid in self['devices']:
1268 dev_type, dev_info = self['devices'][dev_uuid]
1270 if dev_type == None or dev_info == None:
1271 raise XendConfigError("Required either UUID or device type and "
1272 "configuration dictionary.")
1274 sxpr.append(dev_type)
1275 if dev_type in ('console', 'vfb'):
1276 config = [(opt, val) for opt, val in dev_info.items()
1277 if opt != 'other_config']
1278 else:
1279 config = [(opt, val) for opt, val in dev_info.items()]
1281 sxpr += config
1283 return sxpr
1285 def ordered_device_refs(self):
1286 result = []
1287 # vkbd devices *must* be before vfb devices, otherwise
1288 # there is a race condition when setting up devices
1289 # where the daemon spawned for the vfb may write stuff
1290 # into xenstore vkbd backend, before DevController has
1291 # setup permissions on the vkbd backend path. This race
1292 # results in domain creation failing with 'device already
1293 # connected' messages
1294 result.extend([u for u in self['devices'].keys() if self['devices'][u][0] == 'vkbd'])
1296 result.extend(self['console_refs'] +
1297 self['vbd_refs'] +
1298 self['vif_refs'] +
1299 self['vtpm_refs'])
1301 result.extend([u for u in self['devices'].keys() if u not in result])
1302 return result
1304 def all_devices_sxpr(self):
1305 """Returns the SXPR for all devices in the current configuration."""
1306 sxprs = []
1307 pci_devs = []
1309 if 'devices' not in self:
1310 return sxprs
1312 ordered_refs = self.ordered_device_refs()
1313 for dev_uuid in ordered_refs:
1314 dev_type, dev_info = self['devices'][dev_uuid]
1315 if dev_type == 'pci': # special case for pci devices
1316 sxpr = [['uuid', dev_info['uuid']]]
1317 for pci_dev_info in dev_info['devs']:
1318 pci_dev_sxpr = ['dev']
1319 for opt, val in pci_dev_info.items():
1320 pci_dev_sxpr.append([opt, val])
1321 sxpr.append(pci_dev_sxpr)
1322 sxprs.append((dev_type, sxpr))
1323 else:
1324 sxpr = self.device_sxpr(dev_type = dev_type,
1325 dev_info = dev_info)
1326 sxprs.append((dev_type, sxpr))
1328 return sxprs
1330 def image_sxpr(self):
1331 """Returns a backwards compatible image SXP expression that is
1332 used in xenstore's /vm/<uuid>/image value and xm list."""
1333 image = [self.image_type()]
1334 if self.has_key('PV_kernel'):
1335 image.append(['kernel', self['PV_kernel']])
1336 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1337 image.append(['ramdisk', self['PV_ramdisk']])
1338 if self.has_key('PV_args') and self['PV_args']:
1339 image.append(['args', self['PV_args']])
1341 for key in XENAPI_PLATFORM_CFG:
1342 if key in self['platform']:
1343 image.append([key, self['platform'][key]])
1345 if 'notes' in self:
1346 image.append(self.notes_sxp(self['notes']))
1348 return image
1350 def update_with_image_sxp(self, image_sxp, bootloader = False):
1351 # Convert Legacy "image" config to Xen API PV_*
1352 # configuration
1353 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1355 # user-specified args must come last: previous releases did this and
1356 # some domU kernels rely upon the ordering.
1357 kernel_args = sxp.child_value(image_sxp, 'args', '')
1359 # attempt to extract extra arguments from SXP config
1360 arg_ip = sxp.child_value(image_sxp, 'ip')
1361 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1362 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1363 arg_root = sxp.child_value(image_sxp, 'root')
1364 if arg_root and not re.search(r'root=', kernel_args):
1365 kernel_args = 'root=%s ' % arg_root + kernel_args
1367 if bootloader:
1368 self['_temp_using_bootloader'] = '1'
1369 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1370 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1371 self['_temp_args'] = kernel_args
1372 else:
1373 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1374 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1375 self['PV_args'] = kernel_args
1377 for key in XENAPI_PLATFORM_CFG:
1378 val = sxp.child_value(image_sxp, key, None)
1379 if val is not None and val != '':
1380 self['platform'][key] = val
1382 notes = sxp.children(image_sxp, 'notes')
1383 if notes:
1384 self['notes'] = self.notes_from_sxp(notes[0])
1386 self._hvm_boot_params_from_sxp(image_sxp)
1388 def set_notes(self, notes):
1389 'Add parsed elfnotes to image'
1390 self['notes'] = notes
1392 def get_notes(self):
1393 try:
1394 return self['notes'] or {}
1395 except KeyError:
1396 return {}
1398 def notes_from_sxp(self, nsxp):
1399 notes = {}
1400 for note in sxp.children(nsxp):
1401 notes[note[0]] = note[1]
1402 return notes
1404 def notes_sxp(self, notes):
1405 nsxp = ['notes']
1406 for k, v in notes.iteritems():
1407 nsxp.append([k, str(v)])
1408 return nsxp
1410 def _hvm_boot_params_from_sxp(self, image_sxp):
1411 boot = sxp.child_value(image_sxp, 'boot', None)
1412 if boot is not None:
1413 self['HVM_boot_policy'] = 'BIOS order'
1414 self['HVM_boot_params'] = { 'order' : boot }
1416 def is_hvm(self):
1417 return self['HVM_boot_policy'] != ''
1419 def image_type(self):
1420 stored_type = self['platform'].get('image_type')
1421 return stored_type or (self.is_hvm() and 'hvm' or 'linux')