ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 14935:2fe1f293e52d

Use new instance store to resolve network uuid to bridge name

signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
author Tom Wilkie <tom.wilkie@gmail.com>
date Wed Apr 25 15:42:34 2007 +0100 (2007-04-25)
parents 0b4375cd7e16
children 53b9883bbcc3
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_dynamic_min"] <= self["memory_dynamic_max"]:
358 raise XendConfigError("memory_dynamic_min must be less " \
359 "than or equal to memory_dynamic_max")
360 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
361 raise XendConfigError("memory_static_min must be less " \
362 "than or equal to memory_dynamic_min")
363 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
364 raise XendConfigError("memory_dynamic_max must be less " \
365 "than or equal to memory_static_max")
366 if not self["memory_dynamic_max"] > 0:
367 raise XendConfigError("memory_dynamic_max must be greater " \
368 "than zero")
369 if not self["memory_static_max"] > 0:
370 raise XendConfigError("memory_static_max must be greater " \
371 "than zero")
373 def _actions_sanity_check(self):
374 for event in ['shutdown', 'reboot', 'crash']:
375 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
376 raise XendConfigError('Invalid event handling mode: ' +
377 event)
379 def _vcpus_sanity_check(self):
380 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
381 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
383 def _uuid_sanity_check(self):
384 """Make sure UUID is in proper string format with hyphens."""
385 if 'uuid' not in self or not self['uuid']:
386 self['uuid'] = uuid.createString()
387 else:
388 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
390 def _name_sanity_check(self):
391 if 'name_label' not in self:
392 self['name_label'] = 'Domain-' + self['uuid']
394 def _platform_sanity_check(self):
395 if self.is_hvm():
396 if 'device_model' not in self['platform']:
397 self['platform']['device_model'] = DEFAULT_DM
399 # Compatibility hack, can go away soon.
400 if 'soundhw' not in self['platform'] and \
401 self['platform'].get('enable_audio'):
402 self['platform']['soundhw'] = 'sb16'
404 def validate(self):
405 self._uuid_sanity_check()
406 self._name_sanity_check()
407 self._memory_sanity_check()
408 self._actions_sanity_check()
409 self._vcpus_sanity_check()
410 self._platform_sanity_check()
412 def _dominfo_to_xapi(self, dominfo, update_mem = False):
413 self['domid'] = dominfo['domid']
414 self['online_vcpus'] = dominfo['online_vcpus']
415 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
417 if update_mem:
418 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
419 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
420 self['memory_static_min'] = 0
421 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
422 self._memory_sanity_check()
424 self['cpu_time'] = dominfo['cpu_time']/1e9
425 # TODO: i don't know what the security stuff expects here
426 if dominfo.get('ssidref'):
427 self['security'] = [['ssidref', dominfo['ssidref']]]
428 self['shutdown_reason'] = dominfo['shutdown_reason']
430 # parse state into Xen API states
431 self['running'] = dominfo['running']
432 self['crashed'] = dominfo['crashed']
433 self['dying'] = dominfo['dying']
434 self['shutdown'] = dominfo['shutdown']
435 self['paused'] = dominfo['paused']
436 self['blocked'] = dominfo['blocked']
438 if 'name' in dominfo:
439 self['name_label'] = dominfo['name']
441 if 'handle' in dominfo:
442 self['uuid'] = uuid.toString(dominfo['handle'])
444 def _parse_sxp(self, sxp_cfg):
445 """ Populate this XendConfig using the parsed SXP.
447 @param sxp_cfg: Parsed SXP Configuration
448 @type sxp_cfg: list of lists
449 @rtype: dictionary
450 @return: A dictionary containing the parsed options of the SXP.
451 """
452 cfg = {}
454 for key, typ in XENAPI_CFG_TYPES.items():
455 val = sxp.child_value(sxp_cfg, key)
456 if val is not None:
457 try:
458 cfg[key] = typ(val)
459 except (ValueError, TypeError), e:
460 log.warn('Unable to convert type value for key: %s' % key)
462 # Convert deprecated options to current equivalents.
464 restart = sxp.child_value(sxp_cfg, 'restart')
465 if restart:
466 if restart == 'onreboot':
467 cfg['on_poweroff'] = 'destroy'
468 cfg['on_reboot'] = 'restart'
469 cfg['on_crash'] = 'destroy'
470 elif restart == 'always':
471 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
472 cfg[opt] = 'restart'
473 elif restart == 'never':
474 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
475 cfg[opt] = 'never'
476 else:
477 log.warn('Ignoring unrecognised value for deprecated option:'
478 'restart = \'%s\'', restart)
480 # Handle memory, passed in as MiB
482 if sxp.child_value(sxp_cfg, "memory") != None:
483 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
484 if sxp.child_value(sxp_cfg, "maxmem") != None:
485 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
487 # Only extract options we know about.
488 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
489 extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
491 for key in extract_keys:
492 val = sxp.child_value(sxp_cfg, key)
493 if val != None:
494 try:
495 cfg[key] = LEGACY_CFG_TYPES[key](val)
496 except KeyError:
497 cfg[key] = val
498 except (TypeError, ValueError), e:
499 log.warn("Unable to parse key %s: %s: %s" %
500 (key, str(val), e))
502 if 'platform' not in cfg:
503 cfg['platform'] = {}
504 localtime = sxp.child_value(sxp_cfg, 'localtime')
505 if localtime is not None:
506 cfg['platform']['localtime'] = localtime
508 # Compatibility hack -- can go soon.
509 for key in XENAPI_PLATFORM_CFG:
510 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
511 if val is not None:
512 self['platform'][key] = val
514 # Compatibility hack -- can go soon.
515 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
516 if boot_order:
517 cfg['HVM_boot_policy'] = 'BIOS order'
518 cfg['HVM_boot_params'] = { 'order' : boot_order }
520 # Parsing the device SXP's. In most cases, the SXP looks
521 # like this:
522 #
523 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
524 #
525 # However, for PCI devices it looks like this:
526 #
527 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1]]]]
528 #
529 # It seems the reasoning for this difference is because
530 # pciif.py needs all the PCI device configurations at
531 # the same time when creating the devices.
532 #
533 # To further complicate matters, Xen 2.0 configuration format
534 # uses the following for pci device configuration:
535 #
536 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
537 #
538 # Hence we deal with pci device configurations outside of
539 # the regular device parsing.
541 cfg['devices'] = {}
542 for dev in sxp.children(sxp_cfg, 'device'):
543 config = sxp.child0(dev)
544 dev_type = sxp.name(config)
545 dev_info = {}
547 if dev_type == 'pci':
548 pci_devs_uuid = sxp.child_value(config, 'uuid',
549 uuid.createString())
550 pci_devs = []
551 for pci_dev in sxp.children(config, 'dev'):
552 pci_dev_info = {}
553 for opt_val in pci_dev[1:]:
554 try:
555 opt, val = opt_val
556 pci_dev_info[opt] = val
557 except TypeError:
558 pass
559 pci_devs.append(pci_dev_info)
561 cfg['devices'][pci_devs_uuid] = (dev_type,
562 {'devs': pci_devs,
563 'uuid': pci_devs_uuid})
565 log.debug("XendConfig: reading device: %s" % pci_devs)
566 else:
567 self.device_add(dev_type, cfg_sxp = config, target = cfg)
568 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
570 # Extract missing data from configuration entries
571 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
572 if image_sxp:
573 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
574 if image_vcpus != None:
575 try:
576 if 'VCPUs_max' not in cfg:
577 cfg['VCPUs_max'] = int(image_vcpus)
578 elif cfg['VCPUs_max'] != int(image_vcpus):
579 cfg['VCPUs_max'] = int(image_vcpus)
580 log.warn('Overriding vcpus from %d to %d using image'
581 'vcpus value.', cfg['VCPUs_max'])
582 except ValueError, e:
583 raise XendConfigError('integer expeceted: %s: %s' %
584 image_sxp, e)
586 # Deprecated cpu configuration
587 if 'cpu' in cfg:
588 if 'cpus' in cfg:
589 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
590 else:
591 cfg['cpus'] = str(cfg['cpu'])
593 # convert 'cpus' string to list of ints
594 # 'cpus' supports a list of ranges (0-3), seperated by
595 # commas, and negation, (^1).
596 # Precedence is settled by order of the string:
597 # "0-3,^1" -> [0,2,3]
598 # "0-3,^1,1" -> [0,1,2,3]
599 try:
600 if 'cpus' in cfg and type(cfg['cpus']) != list:
601 cpus = []
602 for c in cfg['cpus'].split(','):
603 if c.find('-') != -1:
604 (x, y) = c.split('-')
605 for i in range(int(x), int(y)+1):
606 cpus.append(int(i))
607 else:
608 # remove this element from the list
609 if c[0] == '^':
610 cpus = [x for x in cpus if x != int(c[1:])]
611 else:
612 cpus.append(int(c))
614 cfg['cpus'] = cpus
615 except ValueError, e:
616 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
618 if 'security' in cfg and isinstance(cfg['security'], str):
619 cfg['security'] = sxp.from_string(cfg['security'])
621 old_state = sxp.child_value(sxp_cfg, 'state')
622 if old_state:
623 for i in range(len(CONFIG_OLD_DOM_STATES)):
624 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
626 return cfg
629 def _sxp_to_xapi(self, sxp_cfg):
630 """Read in an SXP Configuration object and
631 populate at much of the Xen API with valid values.
632 """
633 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
635 cfg = self._parse_sxp(sxp_cfg)
637 for key, typ in XENAPI_CFG_TYPES.items():
638 val = cfg.get(key)
639 if val is not None:
640 self[key] = typ(val)
642 # Convert parameters that can be directly mapped from
643 # the Legacy Config to Xen API Config
645 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
646 try:
647 type_conv = XENAPI_CFG_TYPES.get(apikey)
648 if callable(type_conv):
649 self[apikey] = type_conv(cfg[cfgkey])
650 else:
651 log.warn("Unconverted key: " + apikey)
652 self[apikey] = cfg[cfgkey]
653 except KeyError:
654 pass
656 # Lets try and handle memory correctly
658 MiB = 1024 * 1024
660 if "memory" in cfg:
661 self["memory_static_min"] = 0
662 self["memory_static_max"] = int(cfg["memory"]) * MiB
663 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
664 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
666 if "maxmem" in cfg:
667 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
669 self._memory_sanity_check()
671 def update_with(n, o):
672 if not self.get(n):
673 self[n] = cfg.get(o, '')
675 update_with('PV_bootloader', 'bootloader')
676 update_with('PV_bootloader_args', 'bootloader_args')
678 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
679 if image_sxp:
680 self.update_with_image_sxp(image_sxp)
682 # Convert Legacy HVM parameters to Xen API configuration
683 for key in XENAPI_PLATFORM_CFG:
684 if key in cfg:
685 self['platform'][key] = cfg[key]
687 # set device references in the configuration
688 self['devices'] = cfg.get('devices', {})
689 self['console_refs'] = cfg.get('console_refs', [])
690 self['vif_refs'] = cfg.get('vif_refs', [])
691 self['vbd_refs'] = cfg.get('vbd_refs', [])
692 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
694 # coalesce hvm vnc frame buffer with vfb config
695 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
696 # add vfb device if it isn't there already
697 has_rfb = False
698 for console_uuid in self['console_refs']:
699 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
700 has_rfb = True
701 break
702 if self['devices'][console_uuid][0] == 'vfb':
703 has_rfb = True
704 break
706 if not has_rfb:
707 dev_config = ['vfb']
708 # copy VNC related params from platform config to vfb dev conf
709 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
710 'vnclisten']:
711 if key in self['platform']:
712 dev_config.append([key, self['platform'][key]])
714 self.device_add('vfb', cfg_sxp = dev_config)
717 def _sxp_to_xapi_unsupported(self, sxp_cfg):
718 """Read in an SXP configuration object and populate
719 values are that not related directly supported in
720 the Xen API.
721 """
723 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
725 # Parse and convert parameters used to configure
726 # the image (as well as HVM images)
727 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
728 if image_sxp:
729 image_type = sxp.name(image_sxp)
730 if image_type != 'hvm' and image_type != 'linux':
731 self['platform']['image_type'] = image_type
733 for key in XENAPI_PLATFORM_CFG:
734 val = sxp.child_value(image_sxp, key, None)
735 if val is not None and val != '':
736 self['platform'][key] = val
738 notes = sxp.children(image_sxp, 'notes')
739 if notes:
740 self['notes'] = self.notes_from_sxp(notes[0])
742 self._hvm_boot_params_from_sxp(image_sxp)
744 # extract backend value
746 backend = []
747 for c in sxp.children(sxp_cfg, 'backend'):
748 backend.append(sxp.name(sxp.child0(c)))
749 if backend:
750 self['backend'] = backend
752 # Parse and convert other Non Xen API parameters.
753 def _set_cfg_if_exists(sxp_arg):
754 val = sxp.child_value(sxp_cfg, sxp_arg)
755 if val != None:
756 if LEGACY_CFG_TYPES.get(sxp_arg):
757 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
758 else:
759 self[sxp_arg] = val
761 _set_cfg_if_exists('shadow_memory')
762 _set_cfg_if_exists('security')
763 _set_cfg_if_exists('features')
764 _set_cfg_if_exists('on_xend_stop')
765 _set_cfg_if_exists('on_xend_start')
766 _set_cfg_if_exists('vcpu_avail')
767 _set_cfg_if_exists('cpu_weight')
768 _set_cfg_if_exists('cpu_cap')
770 # Parse and store runtime configuration
771 _set_cfg_if_exists('start_time')
772 _set_cfg_if_exists('cpu_time')
773 _set_cfg_if_exists('shutdown_reason')
774 _set_cfg_if_exists('up_time')
775 _set_cfg_if_exists('status') # TODO, deprecated
777 def _get_old_state_string(self):
778 """Returns the old xm state string.
779 @rtype: string
780 @return: old state string
781 """
782 state_string = ''
783 for state_name in CONFIG_OLD_DOM_STATES:
784 on_off = self.get(state_name, 0)
785 if on_off:
786 state_string += state_name[0]
787 else:
788 state_string += '-'
790 return state_string
793 def update_config(self, dominfo):
794 """Update configuration with the output from xc.domain_getinfo().
796 @param dominfo: Domain information via xc.domain_getinfo()
797 @type dominfo: dict
798 """
799 self._dominfo_to_xapi(dominfo)
800 self.validate()
802 def update_with_xenapi_config(self, xapi):
803 """Update configuration with a Xen API VM struct
805 @param xapi: Xen API VM Struct
806 @type xapi: dict
807 """
809 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
811 for key, val in xapi.items():
812 type_conv = XENAPI_CFG_TYPES.get(key)
813 if type_conv is None:
814 key = key.lower()
815 type_conv = XENAPI_CFG_TYPES.get(key)
816 if callable(type_conv):
817 self[key] = type_conv(val)
818 else:
819 self[key] = val
821 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
822 legacy_only = True):
823 """ Get SXP representation of this config object.
825 Incompat: removed store_mfn, console_mfn
827 @keyword domain: (optional) XendDomainInfo to get extra information
828 from such as domid and running devices.
829 @type domain: XendDomainInfo
830 @keyword ignore: (optional) list of 'keys' that we do not want
831 to export.
832 @type ignore: list of strings
833 @rtype: list of list (SXP representation)
834 """
835 sxpr = ['domain']
837 # TODO: domid/dom is the same thing but called differently
838 # depending if it is from xenstore or sxpr.
840 if domain.getDomid() is not None:
841 sxpr.append(['domid', domain.getDomid()])
843 if not legacy_only:
844 for name, typ in XENAPI_CFG_TYPES.items():
845 if name in self and self[name] not in (None, []):
846 if typ == dict:
847 s = self[name].items()
848 else:
849 s = str(self[name])
850 sxpr.append([name, s])
852 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
853 if legacy in ('cpus'): # skip this
854 continue
855 if self.has_key(xenapi) and self[xenapi] not in (None, []):
856 if type(self[xenapi]) == bool:
857 # convert booleans to ints before making an sxp item
858 sxpr.append([legacy, int(self[xenapi])])
859 else:
860 sxpr.append([legacy, self[xenapi]])
862 MiB = 1024*1024
864 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
865 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
867 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
868 if legacy in ('domid', 'uuid', 'cpus'): # skip these
869 continue
870 if self.has_key(legacy) and self[legacy] not in (None, []):
871 sxpr.append([legacy, self[legacy]])
873 sxpr.append(['image', self.image_sxpr()])
874 sxpr.append(['status', domain._stateGet()])
876 if domain.getDomid() is not None:
877 sxpr.append(['state', self._get_old_state_string()])
879 if domain:
880 if domain.store_mfn:
881 sxpr.append(['store_mfn', domain.store_mfn])
882 if domain.console_mfn:
883 sxpr.append(['console_mfn', domain.console_mfn])
886 # Marshall devices (running or from configuration)
887 if not ignore_devices:
888 for cls in XendDevices.valid_devices():
889 found = False
891 # figure if there is a dev controller is valid and running
892 if domain and domain.getDomid() != None:
893 try:
894 controller = domain.getDeviceController(cls)
895 configs = controller.configurations()
896 for config in configs:
897 if sxp.name(config) in ('vbd', 'tap'):
898 # The bootable flag is never written to the
899 # store as part of the device config.
900 dev_uuid = sxp.child_value(config, 'uuid')
901 dev_type, dev_cfg = self['devices'][dev_uuid]
902 is_bootable = dev_cfg.get('bootable', 0)
903 config.append(['bootable', int(is_bootable)])
905 sxpr.append(['device', config])
907 found = True
908 except:
909 log.exception("dumping sxp from device controllers")
910 pass
912 # if we didn't find that device, check the existing config
913 # for a device in the same class
914 if not found:
915 for dev_type, dev_info in self.all_devices_sxpr():
916 if dev_type == cls:
917 sxpr.append(['device', dev_info])
919 return sxpr
921 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
922 target = None):
923 """Add a device configuration in SXP format or XenAPI struct format.
925 For SXP, it could be either:
927 [device, [vbd, [uname ...]]
929 or:
931 [vbd, [uname ..]]
933 @type cfg_sxp: list of lists (parsed sxp object)
934 @param cfg_sxp: SXP configuration object
935 @type cfg_xenapi: dict
936 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
937 @param target: write device information to
938 @type target: None or a dictionary
939 @rtype: string
940 @return: Assigned UUID of the device.
941 """
942 if target == None:
943 target = self
945 if dev_type not in XendDevices.valid_devices():
946 raise XendConfigError("XendConfig: %s not a valid device type" %
947 dev_type)
949 if cfg_sxp == None and cfg_xenapi == None:
950 raise XendConfigError("XendConfig: device_add requires some "
951 "config.")
953 #if cfg_sxp:
954 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
955 #if cfg_xenapi:
956 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
958 if cfg_sxp:
959 if sxp.child0(cfg_sxp) == 'device':
960 config = sxp.child0(cfg_sxp)
961 else:
962 config = cfg_sxp
964 dev_type = sxp.name(config)
965 dev_info = {}
967 for opt_val in config[1:]:
968 try:
969 opt, val = opt_val
970 dev_info[opt] = val
971 except (TypeError, ValueError): # unpack error
972 pass
974 if dev_type == 'vbd':
975 dev_info['bootable'] = 0
976 if dev_info.get('dev', '').startswith('ioemu:'):
977 dev_info['driver'] = 'ioemu'
978 else:
979 dev_info['driver'] = 'paravirtualised'
981 # create uuid if it doesn't exist
982 dev_uuid = dev_info.get('uuid', None)
983 if not dev_uuid:
984 dev_uuid = uuid.createString()
985 dev_info['uuid'] = dev_uuid
987 # store dev references by uuid for certain device types
988 target['devices'][dev_uuid] = (dev_type, dev_info)
989 if dev_type in ('vif', 'vbd', 'vtpm'):
990 param = '%s_refs' % dev_type
991 if param not in target:
992 target[param] = []
993 if dev_uuid not in target[param]:
994 if dev_type == 'vbd' and not target[param]:
995 # Compat hack -- this is the first disk, so mark it
996 # bootable.
997 dev_info['bootable'] = 1
998 target[param].append(dev_uuid)
999 elif dev_type == 'tap':
1000 if 'vbd_refs' not in target:
1001 target['vbd_refs'] = []
1002 if dev_uuid not in target['vbd_refs']:
1003 if not target['vbd_refs']:
1004 # Compat hack -- this is the first disk, so mark it
1005 # bootable.
1006 dev_info['bootable'] = 1
1007 target['vbd_refs'].append(dev_uuid)
1009 elif dev_type == 'vfb':
1010 # Populate other config with aux data that is associated
1011 # with vfb
1013 other_config = {}
1014 for key in ['vncunused', 'vncdisplay', 'vnclisten',
1015 'vncpasswd', 'type', 'display', 'xauthority',
1016 'keymap']:
1017 if key in dev_info:
1018 other_config[key] = dev_info[key]
1019 target['devices'][dev_uuid][1]['other_config'] = other_config
1022 if 'console_refs' not in target:
1023 target['console_refs'] = []
1025 # Treat VFB devices as console devices so they are found
1026 # through Xen API
1027 if dev_uuid not in target['console_refs']:
1028 target['console_refs'].append(dev_uuid)
1030 elif dev_type == 'console':
1031 if 'console_refs' not in target:
1032 target['console_refs'] = []
1033 if dev_uuid not in target['console_refs']:
1034 target['console_refs'].append(dev_uuid)
1036 return dev_uuid
1038 if cfg_xenapi:
1039 dev_info = {}
1040 dev_uuid = ''
1041 if dev_type == 'vif':
1042 if cfg_xenapi.get('MAC'): # don't add if blank
1043 dev_info['mac'] = cfg_xenapi.get('MAC')
1044 # vifname is the name on the guest, not dom0
1045 # TODO: we don't have the ability to find that out or
1046 # change it from dom0
1047 #if cfg_xenapi.get('device'): # don't add if blank
1048 # dev_info['vifname'] = cfg_xenapi.get('device')
1049 if cfg_xenapi.get('type'):
1050 dev_info['type'] = cfg_xenapi.get('type')
1051 if cfg_xenapi.get('name'):
1052 dev_info['name'] = cfg_xenapi.get('name')
1053 if cfg_xenapi.get('network'):
1054 network = XendAPIStore.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')