ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 19791:c0d2838fc10f

stubdoms: qemu monitor support

Add support for the qemu monitor in a stubdom, the same way the
emulated serial support was added few days ago. The stubdom exports
the monitor as a pty and minios opens a console frontend; qemu in dom0
provides the correspondent backend for this additional pv console that
happens to be the qemu monitor.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 18 10:20:17 2009 +0100 (2009-06-18)
parents a4036225c168
children bfbd7a85d2f8
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 XendOptions
26 from xen.xend import XendAPIStore
27 from xen.xend.XendPPCI import XendPPCI
28 from xen.xend.XendDPCI import XendDPCI
29 from xen.xend.XendPSCSI import XendPSCSI
30 from xen.xend.XendDSCSI import XendDSCSI
31 from xen.xend.XendError import VmError
32 from xen.xend.XendDevices import XendDevices
33 from xen.xend.PrettyPrint import prettyprintstring
34 from xen.xend.XendConstants import DOM_STATE_HALTED, AUTO_PHP_SLOT_STR
35 from xen.xend.xenstore.xstransact import xstransact
36 from xen.xend.server.BlktapController import blktap_disk_types
37 from xen.xend.server.netif import randomMAC
38 from xen.util.blkif import blkdev_name_to_number, blkdev_uname_to_file
39 from xen.util.pci import pci_opts_list_from_sxp, pci_convert_sxp_to_dict
40 from xen.xend.XendSXPDev import dev_dict_to_sxp
41 from xen.util import xsconstants
42 import xen.util.auxbin
44 log = logging.getLogger("xend.XendConfig")
45 log.setLevel(logging.WARN)
48 """
49 XendConfig API
51 XendConfig will try to mirror as closely the Xen API VM Struct
52 with extra parameters for those options that are not supported.
54 """
56 def reverse_dict(adict):
57 """Return the reverse mapping of a dictionary."""
58 return dict([(v, k) for k, v in adict.items()])
60 def bool0(v):
61 return v != '0' and v != 'False' and bool(v)
63 # Recursively copy a data struct, scrubbing out VNC passwords.
64 # Will scrub any dict entry with a key of 'vncpasswd' or any
65 # 2-element list whose first member is 'vncpasswd'. It will
66 # also scrub a string matching '(vncpasswd XYZ)'. Everything
67 # else is no-op passthrough
68 def scrub_password(data):
69 if type(data) == dict or type(data) == XendConfig:
70 scrubbed = {}
71 for key in data.keys():
72 if key == "vncpasswd":
73 scrubbed[key] = "XXXXXXXX"
74 else:
75 scrubbed[key] = scrub_password(data[key])
76 return scrubbed
77 elif type(data) == list:
78 if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd':
79 return ['vncpasswd', 'XXXXXXXX']
80 else:
81 scrubbed = []
82 for entry in data:
83 scrubbed.append(scrub_password(entry))
84 return scrubbed
85 elif type(data) == tuple:
86 scrubbed = []
87 for entry in data:
88 scrubbed.append(scrub_password(entry))
89 return tuple(scrubbed)
90 elif type(data) == str:
91 return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data)
92 else:
93 return data
95 #
96 # CPU fields:
97 #
98 # VCPUs_max -- the maximum number of vcpus that this domain may ever have.
99 # aka XendDomainInfo.getVCpuCount().
100 # vcpus -- the legacy configuration name for above.
101 # max_vcpu_id -- vcpus_number - 1. This is given to us by Xen.
102 #
103 # cpus -- the list of pCPUs available to each vCPU.
104 #
105 # vcpu_avail -- a bitmap telling the guest domain whether it may use each of
106 # its VCPUs. This is translated to
107 # <dompath>/cpu/<id>/availability = {online,offline} for use
108 # by the guest domain.
109 # VCPUs_live -- the number of VCPUs currently up, as reported by Xen. This
110 # is changed by changing vcpu_avail, and waiting for the
111 # domain to respond.
112 #
115 # Mapping from XendConfig configuration keys to the old
116 # legacy configuration keys that map directly.
118 XENAPI_CFG_TO_LEGACY_CFG = {
119 'uuid': 'uuid',
120 'VCPUs_max': 'vcpus',
121 'cpus': 'cpus',
122 'name_label': 'name',
123 'actions_after_shutdown': 'on_poweroff',
124 'actions_after_reboot': 'on_reboot',
125 'actions_after_crash': 'on_crash',
126 'PV_bootloader': 'bootloader',
127 'PV_bootloader_args': 'bootloader_args',
128 }
130 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
132 # Platform configuration keys and their types.
133 XENAPI_PLATFORM_CFG_TYPES = {
134 'acpi': int,
135 'apic': int,
136 'boot': str,
137 'device_model': str,
138 'loader': str,
139 'display' : str,
140 'fda': str,
141 'fdb': str,
142 'keymap': str,
143 'isa' : int,
144 'localtime': int,
145 'monitor': int,
146 'nographic': int,
147 'pae' : int,
148 'rtc_timeoffset': int,
149 'serial': str,
150 'sdl': int,
151 'opengl': int,
152 'soundhw': str,
153 'stdvga': int,
154 'videoram': int,
155 'usb': int,
156 'usbdevice': str,
157 'hpet': int,
158 'vnc': int,
159 'vncconsole': int,
160 'vncdisplay': int,
161 'vnclisten': str,
162 'timer_mode': int,
163 'vpt_align': int,
164 'viridian': int,
165 'vncpasswd': str,
166 'vncunused': int,
167 'xauthority': str,
168 'pci': str,
169 'vhpt': int,
170 'guest_os_type': str,
171 'hap': int,
172 'xen_extended_power_mgmt': int,
173 'pci_msitranslate': int,
174 'pci_power_mgmt': int,
175 'xen_platform_pci': int,
176 }
178 # Xen API console 'other_config' keys.
179 XENAPI_CONSOLE_OTHER_CFG = ['vncunused', 'vncdisplay', 'vnclisten',
180 'vncpasswd', 'sdl', 'vnc', 'display', 'xauthority',
181 'keymap', 'opengl']
183 # List of XendConfig configuration keys that have no direct equivalent
184 # in the old world.
186 XENAPI_CFG_TYPES = {
187 'uuid': str,
188 'name_label': str,
189 'name_description': str,
190 'user_version': str,
191 'is_a_template': bool0,
192 'auto_power_on': bool0,
193 'resident_on': str,
194 'memory_static_min': int, # note these are stored in bytes, not KB!
195 'memory_static_max': int,
196 'memory_dynamic_min': int,
197 'memory_dynamic_max': int,
198 'cpus': list,
199 'vcpus_params': dict,
200 'VCPUs_max': int,
201 'VCPUs_at_startup': int,
202 'VCPUs_live': int,
203 'actions_after_shutdown': str,
204 'actions_after_reboot': str,
205 'actions_after_crash': str,
206 'PV_bootloader': str,
207 'PV_kernel': str,
208 'PV_ramdisk': str,
209 'PV_args': str,
210 'PV_bootloader_args': str,
211 'HVM_boot_policy': str,
212 'HVM_boot_params': dict,
213 'PCI_bus': str,
214 'platform': dict,
215 'tools_version': dict,
216 'other_config': dict,
217 'target': int,
218 'security_label': str,
219 'pci': str,
220 'cpuid' : dict,
221 'cpuid_check' : dict,
222 'machine_address_size': int,
223 'suppress_spurious_page_faults': bool0,
224 's3_integrity' : int,
225 'superpages' : int,
226 }
228 # List of legacy configuration keys that have no equivalent in the
229 # Xen API, but are still stored in XendConfig.
231 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
232 # roundtripped (dynamic, unmodified)
233 'shadow_memory',
234 'vcpu_avail',
235 'features',
236 # read/write
237 'on_xend_start',
238 'on_xend_stop',
239 # read-only
240 'domid',
241 'start_time',
242 'cpu_time',
243 'online_vcpus',
244 # write-once
245 'cpu',
246 'cpus',
247 ]
249 LEGACY_CFG_TYPES = {
250 'uuid': str,
251 'name': str,
252 'vcpus': int,
253 'vcpu_avail': long,
254 'memory': int,
255 'shadow_memory': int,
256 'maxmem': int,
257 'start_time': float,
258 'cpu_time': float,
259 'features': str,
260 'localtime': int,
261 'name': str,
262 'on_poweroff': str,
263 'on_reboot': str,
264 'on_crash': str,
265 'on_xend_stop': str,
266 'on_xend_start': str,
267 'online_vcpus': int,
268 'rtc/timeoffset': str,
269 'bootloader': str,
270 'bootloader_args': str,
271 }
273 # Values that should be stored in xenstore's /vm/<uuid> that is used
274 # by Xend. Used in XendDomainInfo to restore running VM state from
275 # xenstore.
276 LEGACY_XENSTORE_VM_PARAMS = [
277 'uuid',
278 'name',
279 'vcpus',
280 'vcpu_avail',
281 'memory',
282 'shadow_memory',
283 'maxmem',
284 'start_time',
285 'name',
286 'on_poweroff',
287 'on_crash',
288 'on_reboot',
289 'on_xend_start',
290 'on_xend_stop',
291 'bootloader',
292 'bootloader_args',
293 ]
295 ##
296 ## Config Choices
297 ##
299 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart',
300 'coredump-destroy', 'coredump-restart')
301 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
302 'crashed', 'dying')
304 class XendConfigError(VmError):
305 def __str__(self):
306 return 'Invalid Configuration: %s' % str(self.value)
308 ##
309 ## XendConfig Class (an extended dictionary)
310 ##
312 class XendConfig(dict):
313 """ The new Xend VM Configuration.
315 Stores the configuration in xenapi compatible format but retains
316 import and export functions for SXP.
317 """
318 def __init__(self, filename = None, sxp_obj = None,
319 xapi = None, dominfo = None):
321 dict.__init__(self)
322 self.update(self._defaults())
324 if filename:
325 try:
326 sxp_obj = sxp.parse(open(filename,'r'))
327 sxp_obj = sxp_obj[0]
328 except IOError, e:
329 raise XendConfigError("Unable to read file: %s" % filename)
331 if sxp_obj:
332 self._sxp_to_xapi(sxp_obj)
333 self._sxp_to_xapi_unsupported(sxp_obj)
334 elif xapi:
335 self.update_with_xenapi_config(xapi)
336 elif dominfo:
337 # output from xc.domain_getinfo
338 self._dominfo_to_xapi(dominfo, update_mem = True)
340 log.debug('XendConfig.init: %s' % scrub_password(self))
342 # validators go here
343 self.validate()
345 """ In time, we should enable this type checking addition. It is great
346 also for tracking bugs and unintended writes to XendDomainInfo.info
347 def __setitem__(self, key, value):
348 type_conv = XENAPI_CFG_TYPES.get(key)
349 if callable(type_conv):
350 try:
351 dict.__setitem__(self, key, type_conv(value))
352 except (ValueError, TypeError):
353 raise XendConfigError("Wrong type for configuration value " +
354 "%s. Expected %s" %
355 (key, type_conv.__name__))
356 else:
357 dict.__setitem__(self, key, value)
358 """
360 def _defaults(self):
361 defaults = {
362 'name_label': 'Domain-Unnamed',
363 'actions_after_shutdown': 'destroy',
364 'actions_after_reboot': 'restart',
365 'actions_after_crash': 'restart',
366 'actions_after_suspend': '',
367 'is_a_template': False,
368 'auto_power_on': False,
369 'is_control_domain': False,
370 'features': '',
371 'PV_bootloader': '',
372 'PV_kernel': '',
373 'PV_ramdisk': '',
374 'PV_args': '',
375 'PV_bootloader_args': '',
376 'HVM_boot_policy': '',
377 'HVM_boot_params': {},
378 'memory_static_min': 0,
379 'memory_dynamic_min': 0,
380 'shadow_memory': 0,
381 'memory_static_max': 0,
382 'memory_dynamic_max': 0,
383 'devices': {},
384 'on_xend_start': 'ignore',
385 'on_xend_stop': 'ignore',
386 'cpus': [],
387 'VCPUs_max': 1,
388 'VCPUs_live': 1,
389 'VCPUs_at_startup': 1,
390 'vcpus_params': {},
391 'console_refs': [],
392 'vif_refs': [],
393 'vbd_refs': [],
394 'vtpm_refs': [],
395 'other_config': {},
396 'platform': {},
397 'target': 0,
398 'superpages': 0,
399 }
401 return defaults
403 #
404 # Here we assume these values exist in the dict.
405 # If they don't we have a bigger problem, lets not
406 # try and 'fix it up' but acutually fix the cause ;-)
407 #
408 def _memory_sanity_check(self):
409 log.trace("_memory_sanity_check memory_static_min: %s, "
410 "memory_static_max: %i, "
411 "memory_dynamic_min: %i, "
412 "memory_dynamic_max: %i",
413 self["memory_static_min"],
414 self["memory_static_max"],
415 self["memory_dynamic_min"],
416 self["memory_dynamic_max"])
418 if not self["memory_static_min"] <= self["memory_static_max"]:
419 raise XendConfigError("memory_static_min must be less " \
420 "than or equal to memory_static_max")
421 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
422 raise XendConfigError("memory_static_min must be less " \
423 "than or equal to memory_dynamic_min")
424 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
425 raise XendConfigError("memory_dynamic_max must be less " \
426 "than or equal to memory_static_max")
427 if not self["memory_dynamic_max"] > 0:
428 raise XendConfigError("memory_dynamic_max must be greater " \
429 "than zero")
430 if not self["memory_static_max"] > 0:
431 raise XendConfigError("memory_static_max must be greater " \
432 "than zero")
434 def _actions_sanity_check(self):
435 for event in ['shutdown', 'reboot', 'crash']:
436 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
437 raise XendConfigError('Invalid event handling mode: ' +
438 event)
440 def _vcpus_sanity_check(self):
441 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
442 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
443 if 'online_vcpus' in self:
444 self['VCPUs_live'] = self['online_vcpus']
446 def _uuid_sanity_check(self):
447 """Make sure UUID is in proper string format with hyphens."""
448 if 'uuid' not in self or not self['uuid']:
449 self['uuid'] = uuid.createString()
450 else:
451 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
453 def _name_sanity_check(self):
454 if 'name_label' not in self:
455 self['name_label'] = 'Domain-' + self['uuid']
457 def _platform_sanity_check(self):
458 if 'keymap' not in self['platform'] and XendOptions.instance().get_keymap():
459 self['platform']['keymap'] = XendOptions.instance().get_keymap()
461 if self.is_hvm() or self.has_rfb():
462 if 'device_model' not in self['platform']:
463 self['platform']['device_model'] = xen.util.auxbin.pathTo("qemu-dm")
465 if self.is_hvm():
466 if 'timer_mode' not in self['platform']:
467 self['platform']['timer_mode'] = 1
468 if 'viridian' not in self['platform']:
469 self['platform']['viridian'] = 0
470 if 'rtc_timeoffset' not in self['platform']:
471 self['platform']['rtc_timeoffset'] = 0
472 if 'hpet' not in self['platform']:
473 self['platform']['hpet'] = 0
474 if 'xen_platform_pci' not in self['platform']:
475 self['platform']['xen_platform_pci'] = 1
476 if 'vpt_align' not in self['platform']:
477 self['platform']['vpt_align'] = 1
478 if 'loader' not in self['platform']:
479 # Old configs may have hvmloader set as PV_kernel param
480 if self.has_key('PV_kernel') and self['PV_kernel'] != '':
481 self['platform']['loader'] = self['PV_kernel']
482 self['PV_kernel'] = ''
483 else:
484 self['platform']['loader'] = "/usr/lib/xen/boot/hvmloader"
485 log.debug("Loader is %s" % str(self['platform']['loader']))
487 # Compatibility hack, can go away soon.
488 if 'soundhw' not in self['platform'] and \
489 self['platform'].get('enable_audio'):
490 self['platform']['soundhw'] = 'sb16'
492 def validate(self):
493 self._uuid_sanity_check()
494 self._name_sanity_check()
495 self._memory_sanity_check()
496 self._actions_sanity_check()
497 self._vcpus_sanity_check()
498 self._platform_sanity_check()
500 def _dominfo_to_xapi(self, dominfo, update_mem = False):
501 self['domid'] = dominfo['domid']
502 self['online_vcpus'] = dominfo['online_vcpus']
503 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
505 if update_mem:
506 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
507 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
508 self['memory_static_min'] = 0
509 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
510 self._memory_sanity_check()
512 self['cpu_time'] = dominfo['cpu_time']/1e9
513 if dominfo.get('ssidref'):
514 ssidref = int(dominfo.get('ssidref'))
515 import xen.util.xsm.xsm as security
516 self['security_label'] = security.ssidref2security_label(ssidref)
518 self['shutdown_reason'] = dominfo['shutdown_reason']
520 # parse state into Xen API states
521 self['running'] = dominfo['running']
522 self['crashed'] = dominfo['crashed']
523 self['dying'] = dominfo['dying']
524 self['shutdown'] = dominfo['shutdown']
525 self['paused'] = dominfo['paused']
526 self['blocked'] = dominfo['blocked']
528 if 'name' in dominfo:
529 self['name_label'] = dominfo['name']
531 if 'handle' in dominfo:
532 self['uuid'] = uuid.toString(dominfo['handle'])
534 def parse_cpuid(self, cfg, field):
535 def int2bin(n, count=32):
536 return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
538 for input, regs in cfg[field].iteritems():
539 if not regs is dict:
540 cfg[field][input] = dict(regs)
542 cpuid = {}
543 for input in cfg[field]:
544 inputs = input.split(',')
545 if inputs[0][0:2] == '0x':
546 inputs[0] = str(int(inputs[0], 16))
547 if len(inputs) == 2:
548 if inputs[1][0:2] == '0x':
549 inputs[1] = str(int(inputs[1], 16))
550 new_input = ','.join(inputs)
551 cpuid[new_input] = {} # new input
552 for reg in cfg[field][input]:
553 val = cfg[field][input][reg]
554 if val[0:2] == '0x':
555 cpuid[new_input][reg] = int2bin(int(val, 16))
556 else:
557 cpuid[new_input][reg] = val
558 cfg[field] = cpuid
560 def _parse_sxp(self, sxp_cfg):
561 """ Populate this XendConfig using the parsed SXP.
563 @param sxp_cfg: Parsed SXP Configuration
564 @type sxp_cfg: list of lists
565 @rtype: dictionary
566 @return: A dictionary containing the parsed options of the SXP.
567 """
568 cfg = {}
570 for key, typ in XENAPI_CFG_TYPES.items():
571 val = sxp.child_value(sxp_cfg, key)
572 if val is not None:
573 try:
574 cfg[key] = typ(val)
575 except (ValueError, TypeError), e:
576 log.warn('Unable to convert type value for key: %s' % key)
578 # Convert deprecated options to current equivalents.
580 restart = sxp.child_value(sxp_cfg, 'restart')
581 if restart:
582 if restart == 'onreboot':
583 cfg['on_poweroff'] = 'destroy'
584 cfg['on_reboot'] = 'restart'
585 cfg['on_crash'] = 'destroy'
586 elif restart == 'always':
587 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
588 cfg[opt] = 'restart'
589 elif restart == 'never':
590 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
591 cfg[opt] = 'never'
592 else:
593 log.warn('Ignoring unrecognised value for deprecated option:'
594 'restart = \'%s\'', restart)
596 # Handle memory, passed in as MiB
598 if sxp.child_value(sxp_cfg, "memory") != None:
599 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
600 if sxp.child_value(sxp_cfg, "maxmem") != None:
601 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
603 # Convert scheduling parameters to vcpus_params
604 if 'vcpus_params' not in cfg:
605 cfg['vcpus_params'] = {}
606 cfg["vcpus_params"]["weight"] = \
607 int(sxp.child_value(sxp_cfg, "cpu_weight", 256))
608 cfg["vcpus_params"]["cap"] = \
609 int(sxp.child_value(sxp_cfg, "cpu_cap", 0))
611 # Only extract options we know about.
612 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG + \
613 XENAPI_CFG_TO_LEGACY_CFG.values()
615 for key in extract_keys:
616 val = sxp.child_value(sxp_cfg, key)
617 if val != None:
618 try:
619 cfg[key] = LEGACY_CFG_TYPES[key](val)
620 except KeyError:
621 cfg[key] = val
622 except (TypeError, ValueError), e:
623 log.warn("Unable to parse key %s: %s: %s" %
624 (key, str(val), e))
626 if 'platform' not in cfg:
627 cfg['platform'] = {}
628 localtime = sxp.child_value(sxp_cfg, 'localtime')
629 if localtime is not None:
630 cfg['platform']['localtime'] = localtime
632 # Compatibility hack -- can go soon.
633 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
634 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
635 if val is not None:
636 self['platform'][key] = val
638 # Compatibility hack -- can go soon.
639 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
640 if boot_order:
641 cfg['HVM_boot_policy'] = 'BIOS order'
642 cfg['HVM_boot_params'] = { 'order' : boot_order }
645 # Parsing the device SXP's.
646 cfg['devices'] = {}
647 for dev in sxp.children(sxp_cfg, 'device'):
648 config = sxp.child0(dev)
649 dev_type = sxp.name(config)
650 self.device_add(dev_type, cfg_sxp = config, target = cfg)
652 # Extract missing data from configuration entries
653 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
654 if image_sxp:
655 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
656 if image_vcpus != None:
657 try:
658 if 'VCPUs_max' not in cfg:
659 cfg['VCPUs_max'] = int(image_vcpus)
660 elif cfg['VCPUs_max'] != int(image_vcpus):
661 cfg['VCPUs_max'] = int(image_vcpus)
662 log.warn('Overriding vcpus from %d to %d using image'
663 'vcpus value.', cfg['VCPUs_max'])
664 except ValueError, e:
665 raise XendConfigError('integer expeceted: %s: %s' %
666 image_sxp, e)
668 # Deprecated cpu configuration
669 if 'cpu' in cfg:
670 if 'cpus' in cfg:
671 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
672 else:
673 cfg['cpus'] = str(cfg['cpu'])
675 # Convert 'cpus' to list of list of ints
676 cpus_list = []
677 if 'cpus' in cfg:
678 # Convert the following string to list of ints.
679 # The string supports a list of ranges (0-3),
680 # seperated by commas, and negation (^1).
681 # Precedence is settled by order of the string:
682 # "0-3,^1" -> [0,2,3]
683 # "0-3,^1,1" -> [0,1,2,3]
684 def cnv(s):
685 l = []
686 for c in s.split(','):
687 if c.find('-') != -1:
688 (x, y) = c.split('-')
689 for i in range(int(x), int(y)+1):
690 l.append(int(i))
691 else:
692 # remove this element from the list
693 if c[0] == '^':
694 l = [x for x in l if x != int(c[1:])]
695 else:
696 l.append(int(c))
697 return l
699 if type(cfg['cpus']) == list:
700 if len(cfg['cpus']) > 0 and type(cfg['cpus'][0]) == list:
701 # If sxp_cfg was created from config.sxp,
702 # the form of 'cpus' is list of list of string.
703 # Convert 'cpus' to list of list of ints.
704 # Conversion examples:
705 # [['1']] -> [[1]]
706 # [['0','2'],['1','3']] -> [[0,2],[1,3]]
707 try:
708 for c1 in cfg['cpus']:
709 cpus = []
710 for c2 in c1:
711 cpus.append(int(c2))
712 cpus_list.append(cpus)
713 except ValueError, e:
714 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
715 else:
716 # Conversion examples:
717 # ["1"] -> [[1]]
718 # ["0,2","1,3"] -> [[0,2],[1,3]]
719 # ["0-3,^1","1-4,^2"] -> [[0,2,3],[1,3,4]]
720 try:
721 for c in cfg['cpus']:
722 cpus = cnv(c)
723 cpus_list.append(cpus)
724 except ValueError, e:
725 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
727 if len(cpus_list) != cfg['vcpus']:
728 raise XendConfigError('vcpus and the item number of cpus are not same')
729 else:
730 # Conversion examples:
731 # vcpus=1:
732 # "1" -> [[1]]
733 # "0-3,^1" -> [[0,2,3]]
734 # vcpus=2:
735 # "1" -> [[1],[1]]
736 # "0-3,^1" -> [[0,2,3],[0,2,3]]
737 try:
738 cpus = cnv(cfg['cpus'])
739 for v in range(0, cfg['vcpus']):
740 cpus_list.append(cpus)
741 except ValueError, e:
742 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
743 else:
744 # Generation examples:
745 # vcpus=1:
746 # -> [[]]
747 # vcpus=2:
748 # -> [[],[]]
749 for v in range(0, cfg['vcpus']):
750 cpus_list.append(list())
752 cfg['cpus'] = cpus_list
754 # Parse cpuid
755 if 'cpuid' in cfg:
756 self.parse_cpuid(cfg, 'cpuid')
757 if 'cpuid_check' in cfg:
758 self.parse_cpuid(cfg, 'cpuid_check')
760 import xen.util.xsm.xsm as security
761 if security.on() == xsconstants.XS_POLICY_USE:
762 from xen.util.acmpolicy import ACM_LABEL_UNLABELED
763 if not 'security' in cfg and sxp.child_value(sxp_cfg, 'security'):
764 cfg['security'] = sxp.child_value(sxp_cfg, 'security')
765 elif not cfg.get('security_label'):
766 cfg['security'] = [['access_control',
767 ['policy', security.get_active_policy_name() ],
768 ['label', ACM_LABEL_UNLABELED ]]]
770 if 'security' in cfg and not cfg.get('security_label'):
771 secinfo = cfg['security']
772 # The xm command sends a list formatted like this:
773 # [['access_control', ['policy', 'xm-test'],['label', 'red']],
774 # ['ssidref', 196611]]
775 policy = ""
776 label = ""
777 for idx in range(0, len(secinfo)):
778 if secinfo[idx][0] == "access_control":
779 for aidx in range(1, len(secinfo[idx])):
780 if secinfo[idx][aidx][0] == "policy":
781 policy = secinfo[idx][aidx][1]
782 if secinfo[idx][aidx][0] == "label":
783 label = secinfo[idx][aidx][1]
784 cfg['security_label'] = \
785 security.set_security_label(policy, label)
786 if not sxp.child_value(sxp_cfg, 'security_label'):
787 del cfg['security']
789 sec_lab = cfg['security_label'].split(":")
790 if len(sec_lab) != 3:
791 raise XendConfigError("Badly formatted security label: %s"
792 % cfg['security_label'])
794 old_state = sxp.child_value(sxp_cfg, 'state')
795 if old_state:
796 for i in range(len(CONFIG_OLD_DOM_STATES)):
797 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
799 return cfg
802 def _sxp_to_xapi(self, sxp_cfg):
803 """Read in an SXP Configuration object and
804 populate at much of the Xen API with valid values.
805 """
806 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
808 # _parse_sxp() below will call device_add() and construct devices.
809 # Some devices may require VM's uuid, so setup self['uuid']
810 # beforehand.
811 self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString())
813 cfg = self._parse_sxp(sxp_cfg)
815 for key, typ in XENAPI_CFG_TYPES.items():
816 val = cfg.get(key)
817 if val is not None:
818 self[key] = typ(val)
820 # Convert parameters that can be directly mapped from
821 # the Legacy Config to Xen API Config
823 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
824 try:
825 type_conv = XENAPI_CFG_TYPES.get(apikey)
826 if callable(type_conv):
827 self[apikey] = type_conv(cfg[cfgkey])
828 else:
829 log.warn("Unconverted key: " + apikey)
830 self[apikey] = cfg[cfgkey]
831 except KeyError:
832 pass
834 # Lets try and handle memory correctly
836 MiB = 1024 * 1024
838 if "memory" in cfg:
839 self["memory_static_min"] = 0
840 self["memory_static_max"] = int(cfg["memory"]) * MiB
841 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
842 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
844 if "maxmem" in cfg:
845 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
847 self._memory_sanity_check()
849 def update_with(n, o):
850 if not self.get(n):
851 self[n] = cfg.get(o, '')
853 update_with('PV_bootloader', 'bootloader')
854 update_with('PV_bootloader_args', 'bootloader_args')
856 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
857 if image_sxp:
858 self.update_with_image_sxp(image_sxp)
860 # Convert Legacy HVM parameters to Xen API configuration
861 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
862 if key in cfg:
863 self['platform'][key] = cfg[key]
865 # set device references in the configuration
866 self['devices'] = cfg.get('devices', {})
867 self['console_refs'] = cfg.get('console_refs', [])
868 self['vif_refs'] = cfg.get('vif_refs', [])
869 self['vbd_refs'] = cfg.get('vbd_refs', [])
870 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
872 # coalesce hvm vnc frame buffer with vfb config
873 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
874 # add vfb device if it isn't there already
875 if not self.has_rfb():
876 dev_config = ['vfb']
877 dev_config.append(['vnc', '1'])
878 # copy VNC related params from platform config to vfb dev conf
879 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
880 'vnclisten']:
881 if key in self['platform']:
882 dev_config.append([key, self['platform'][key]])
884 self.device_add('vfb', cfg_sxp = dev_config)
887 def has_rfb(self):
888 for console_uuid in self['console_refs']:
889 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
890 return True
891 if self['devices'][console_uuid][0] == 'vfb':
892 return True
893 return False
895 def _sxp_to_xapi_unsupported(self, sxp_cfg):
896 """Read in an SXP configuration object and populate
897 values are that not related directly supported in
898 the Xen API.
899 """
901 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
903 # Parse and convert parameters used to configure
904 # the image (as well as HVM images)
905 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
906 if image_sxp:
907 image_type = sxp.name(image_sxp)
908 if image_type != 'hvm' and image_type != 'linux':
909 self['platform']['image_type'] = image_type
911 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
912 val = sxp.child_value(image_sxp, key, None)
913 if val is not None and val != '':
914 self['platform'][key] = val
916 notes = sxp.children(image_sxp, 'notes')
917 if notes:
918 self['notes'] = self.notes_from_sxp(notes[0])
920 self._hvm_boot_params_from_sxp(image_sxp)
922 # extract backend value
924 backend = []
925 for c in sxp.children(sxp_cfg, 'backend'):
926 backend.append(sxp.name(sxp.child0(c)))
927 if backend:
928 self['backend'] = backend
930 # Parse and convert other Non Xen API parameters.
931 def _set_cfg_if_exists(sxp_arg):
932 val = sxp.child_value(sxp_cfg, sxp_arg)
933 if val != None:
934 if LEGACY_CFG_TYPES.get(sxp_arg):
935 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
936 else:
937 self[sxp_arg] = val
939 _set_cfg_if_exists('shadow_memory')
940 _set_cfg_if_exists('features')
941 _set_cfg_if_exists('on_xend_stop')
942 _set_cfg_if_exists('on_xend_start')
943 _set_cfg_if_exists('vcpu_avail')
945 # Parse and store runtime configuration
946 _set_cfg_if_exists('start_time')
947 _set_cfg_if_exists('cpu_time')
948 _set_cfg_if_exists('shutdown_reason')
949 _set_cfg_if_exists('up_time')
950 _set_cfg_if_exists('status') # TODO, deprecated
952 def _get_old_state_string(self):
953 """Returns the old xm state string.
954 @rtype: string
955 @return: old state string
956 """
957 state_string = ''
958 for state_name in CONFIG_OLD_DOM_STATES:
959 on_off = self.get(state_name, 0)
960 if on_off:
961 state_string += state_name[0]
962 else:
963 state_string += '-'
965 return state_string
968 def update_config(self, dominfo):
969 """Update configuration with the output from xc.domain_getinfo().
971 @param dominfo: Domain information via xc.domain_getinfo()
972 @type dominfo: dict
973 """
974 self._dominfo_to_xapi(dominfo)
975 self.validate()
977 def update_with_xenapi_config(self, xapi):
978 """Update configuration with a Xen API VM struct
980 @param xapi: Xen API VM Struct
981 @type xapi: dict
982 """
984 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
986 for key, val in xapi.items():
987 type_conv = XENAPI_CFG_TYPES.get(key)
988 if type_conv is None:
989 key = key.lower()
990 type_conv = XENAPI_CFG_TYPES.get(key)
991 if callable(type_conv):
992 self[key] = type_conv(val)
993 else:
994 self[key] = val
996 # XenAPI defines platform as a string-string map. If platform
997 # configuration exists, convert values to appropriate type.
998 if 'platform' in xapi:
999 for key, val in xapi['platform'].items():
1000 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1001 if type_conv is None:
1002 key = key.lower()
1003 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1004 if callable(type_conv):
1005 self['platform'][key] = type_conv(val)
1006 else:
1007 self['platform'][key] = val
1009 self['vcpus_params']['weight'] = \
1010 int(self['vcpus_params'].get('weight', 256))
1011 self['vcpus_params']['cap'] = int(self['vcpus_params'].get('cap', 0))
1013 def cpuid_to_sxp(self, sxpr, field):
1014 regs_list = []
1015 for input, regs in self[field].iteritems():
1016 reg_list = []
1017 for reg, val in regs.iteritems():
1018 reg_list.append([reg, val])
1019 regs_list.append([input, reg_list])
1020 sxpr.append([field, regs_list])
1023 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
1024 legacy_only = True):
1025 """ Get SXP representation of this config object.
1027 Incompat: removed store_mfn, console_mfn
1029 @keyword domain: (optional) XendDomainInfo to get extra information
1030 from such as domid and running devices.
1031 @type domain: XendDomainInfo
1032 @keyword ignore: (optional) list of 'keys' that we do not want
1033 to export.
1034 @type ignore: list of strings
1035 @rtype: list of list (SXP representation)
1036 """
1037 sxpr = ['domain']
1039 # TODO: domid/dom is the same thing but called differently
1040 # depending if it is from xenstore or sxpr.
1042 if domain.getDomid() is not None:
1043 sxpr.append(['domid', domain.getDomid()])
1045 if not legacy_only:
1046 for name, typ in XENAPI_CFG_TYPES.items():
1047 if name in self and self[name] not in (None, []):
1048 if typ == dict:
1049 s = self[name].items()
1050 elif typ == list:
1051 s = self[name]
1052 else:
1053 s = str(self[name])
1054 sxpr.append([name, s])
1056 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
1057 if self.has_key(xenapi) and self[xenapi] not in (None, []):
1058 if type(self[xenapi]) == bool:
1059 # convert booleans to ints before making an sxp item
1060 sxpr.append([legacy, int(self[xenapi])])
1061 else:
1062 sxpr.append([legacy, self[xenapi]])
1064 MiB = 1024*1024
1066 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
1067 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
1069 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
1070 if legacy in ('domid', 'uuid', 'cpus'): # skip these
1071 continue
1072 if self.has_key(legacy) and self[legacy] not in (None, []):
1073 sxpr.append([legacy, self[legacy]])
1075 if self.has_key('security_label'):
1076 sxpr.append(['security_label', self['security_label']])
1078 sxpr.append(['image', self.image_sxpr()])
1079 sxpr.append(['status', domain._stateGet()])
1081 if domain.getDomid() is not None:
1082 sxpr.append(['state', self._get_old_state_string()])
1084 if domain:
1085 if domain.store_mfn:
1086 sxpr.append(['store_mfn', domain.store_mfn])
1087 if domain.console_mfn:
1088 sxpr.append(['console_mfn', domain.console_mfn])
1091 # Marshall devices (running or from configuration)
1092 if not ignore_devices:
1093 txn = xstransact()
1094 try:
1095 for cls in XendDevices.valid_devices():
1096 found = False
1098 # figure if there is a dev controller is valid and running
1099 if domain and domain.getDomid() != None:
1100 try:
1101 controller = domain.getDeviceController(cls)
1102 configs = controller.configurations(txn)
1103 for config in configs:
1104 if sxp.name(config) in ('vbd', 'tap'):
1105 dev_uuid = sxp.child_value(config, 'uuid')
1106 dev_type, dev_cfg = self['devices'][dev_uuid]
1107 if sxp.child_value(config, 'bootable', None) is None:
1108 is_bootable = dev_cfg.get('bootable', 0)
1109 config.append(['bootable', int(is_bootable)])
1110 config.append(['VDI', dev_cfg.get('VDI', '')])
1112 sxpr.append(['device', config])
1114 found = True
1115 except:
1116 log.exception("dumping sxp from device controllers")
1117 pass
1119 # if we didn't find that device, check the existing config
1120 # for a device in the same class
1121 if not found:
1122 for dev_type, dev_info in self.all_devices_sxpr():
1123 if dev_type == cls:
1124 sxpr.append(['device', dev_info])
1126 txn.commit()
1127 except:
1128 txn.abort()
1129 raise
1131 if 'cpuid' in self:
1132 self.cpuid_to_sxp(sxpr, 'cpuid')
1133 if 'cpuid_check' in self:
1134 self.cpuid_to_sxp(sxpr, 'cpuid_check')
1136 log.debug(sxpr)
1138 return sxpr
1140 def _blkdev_name_to_number(self, dev):
1141 if 'ioemu:' in dev:
1142 _, dev = dev.split(':', 1)
1143 try:
1144 dev, _ = dev.split(':', 1)
1145 except ValueError:
1146 pass
1148 try:
1149 devid = int(dev)
1150 except ValueError:
1151 # devid is not a number but a string containing either device
1152 # name (e.g. xvda) or device_type/device_id (e.g. vbd/51728)
1153 dev2 = type(dev) is str and dev.split('/')[-1] or None
1154 if dev2 == None:
1155 log.debug("Could not check the device %s", dev)
1156 return None
1157 try:
1158 devid = int(dev2)
1159 except ValueError:
1160 (xenbus, devid) = blkdev_name_to_number(dev2)
1161 if devid == None:
1162 log.debug("The device %s is not device name", dev2)
1163 return None
1164 return devid
1166 def device_duplicate_check(self, dev_type, dev_info, defined_config, config):
1167 defined_devices_sxpr = self.all_devices_sxpr(target = defined_config)
1169 if dev_type == 'vbd' or dev_type == 'tap':
1170 dev_uname = dev_info.get('uname')
1171 blkdev_name = dev_info.get('dev')
1172 devid = self._blkdev_name_to_number(blkdev_name)
1173 if devid == None or dev_uname == None:
1174 return
1176 for o_dev_type, o_dev_info in defined_devices_sxpr:
1177 if o_dev_type == 'vbd' or o_dev_type == 'tap':
1178 blkdev_file = blkdev_uname_to_file(dev_uname)
1179 o_dev_uname = sxp.child_value(o_dev_info, 'uname')
1180 if o_dev_uname != None:
1181 o_blkdev_file = blkdev_uname_to_file(o_dev_uname)
1182 if blkdev_file == o_blkdev_file:
1183 raise XendConfigError('The file "%s" is already used' %
1184 blkdev_file)
1185 if dev_uname == o_dev_uname:
1186 raise XendConfigError('The uname "%s" is already defined' %
1187 dev_uname)
1188 o_blkdev_name = sxp.child_value(o_dev_info, 'dev')
1189 o_devid = self._blkdev_name_to_number(o_blkdev_name)
1190 if o_devid != None and devid == o_devid:
1191 name_array = blkdev_name.split(':', 2)
1192 if len(name_array) == 2 and name_array[1] == 'cdrom':
1194 # Since the device is a cdrom, we are most likely
1195 # inserting, changing, or removing a cd. We can
1196 # update the old device instead of creating a new
1197 # one.
1199 if o_dev_uname != None and dev_uname == None:
1201 # We are removing a cd. We can simply update
1202 # the uname on the existing device.
1204 merge_sxp = sxp.from_string("('vbd' ('uname' ''))")
1205 else:
1206 merge_sxp = config
1208 dev_uuid = sxp.child_value(o_dev_info, 'uuid')
1209 if dev_uuid != None and \
1210 self.device_update(dev_uuid, cfg_sxp = merge_sxp):
1211 return dev_uuid
1213 raise XendConfigError('The device "%s" is already defined' %
1214 blkdev_name)
1216 elif dev_type == 'vif':
1217 dev_mac = dev_info.get('mac')
1219 for o_dev_type, o_dev_info in defined_devices_sxpr:
1220 if dev_type == o_dev_type:
1221 if dev_mac.lower() == sxp.child_value(o_dev_info, 'mac').lower():
1222 raise XendConfigError('The mac "%s" is already defined' %
1223 dev_mac)
1224 return None
1226 def create_dpci_from_sxp(self, pci_devs):
1227 for pci_dev in pci_devs:
1228 dpci_uuid = pci_dev.get('uuid')
1229 log.debug("create_dpci_from_sxp: %s" % pci_dev)
1230 ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
1231 pci_dev['bus'],
1232 pci_dev['slot'],
1233 pci_dev['func'])
1234 if ppci_uuid is None:
1235 continue
1236 dpci_record = {
1237 'VM': self['uuid'],
1238 'PPCI': ppci_uuid,
1239 'hotplug_slot': pci_dev.get('vslot',
1240 '0x' + AUTO_PHP_SLOT_STR)
1243 dpci_opts = pci_dev.get('opts')
1244 if dpci_opts and len(dpci_opts) > 0:
1245 dpci_record['options'] = dpci_opts
1247 XendDPCI(dpci_uuid, dpci_record)
1249 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
1250 target = None):
1251 """Add a device configuration in SXP format or XenAPI struct format.
1253 For SXP, it could be either:
1255 [device, [vbd, [uname ...]]
1257 or:
1259 [vbd, [uname ..]]
1261 @type cfg_sxp: list of lists (parsed sxp object)
1262 @param cfg_sxp: SXP configuration object
1263 @type cfg_xenapi: dict
1264 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
1265 @param target: write device information to
1266 @type target: None or a dictionary
1267 @rtype: string
1268 @return: Assigned UUID of the device.
1269 """
1270 if target == None:
1271 target = self
1273 if dev_type not in XendDevices.valid_devices():
1274 raise XendConfigError("XendConfig: %s not a valid device type" %
1275 dev_type)
1277 if cfg_sxp == None and cfg_xenapi == None:
1278 raise XendConfigError("XendConfig: device_add requires some "
1279 "config.")
1281 #if cfg_sxp:
1282 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
1283 #if cfg_xenapi:
1284 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
1286 if cfg_sxp:
1287 if sxp.child0(cfg_sxp) == 'device':
1288 config = sxp.child0(cfg_sxp)
1289 else:
1290 config = cfg_sxp
1292 dev_type = sxp.name(config)
1293 dev_info = {}
1295 if dev_type == 'pci':
1296 pci_devs_uuid = sxp.child_value(config, 'uuid',
1297 uuid.createString())
1299 pci_dict = pci_convert_sxp_to_dict(config)
1300 pci_devs = pci_dict['devs']
1302 # create XenAPI DPCI objects.
1303 self.create_dpci_from_sxp(pci_devs)
1305 target['devices'][pci_devs_uuid] = (dev_type,
1306 {'devs': pci_devs,
1307 'uuid': pci_devs_uuid})
1309 log.debug("XendConfig: reading device: %s" % pci_devs)
1311 return pci_devs_uuid
1313 if dev_type == 'vscsi':
1314 vscsi_devs_uuid = sxp.child_value(config, 'uuid',
1315 uuid.createString())
1316 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1317 vscsi_devs = vscsi_dict['devs']
1318 vscsi_mode = vscsi_dict['feature-host']
1319 vscsi_be = vscsi_dict.get('backend', None)
1321 # create XenAPI DSCSI objects.
1322 for vscsi_dev in vscsi_devs:
1323 dscsi_uuid = vscsi_dev.get('uuid')
1324 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1325 if pscsi_uuid is None:
1326 continue
1327 dscsi_record = {
1328 'VM': self['uuid'],
1329 'PSCSI': pscsi_uuid,
1330 'virtual_HCTL': vscsi_dev.get('v-dev')
1332 XendDSCSI(dscsi_uuid, dscsi_record)
1334 vscsi_info = {
1335 'devs': vscsi_devs,
1336 'feature-host': vscsi_mode,
1337 'uuid': vscsi_devs_uuid
1339 if vscsi_be is not None:
1340 vscsi_info['backend'] = vscsi_be
1341 target['devices'][vscsi_devs_uuid] = (dev_type, vscsi_info)
1342 log.debug("XendConfig: reading device: %s,%s" % \
1343 (vscsi_devs, vscsi_mode))
1344 return vscsi_devs_uuid
1346 for opt_val in config[1:]:
1347 try:
1348 opt, val = opt_val
1349 dev_info[opt] = val
1350 except (TypeError, ValueError): # unpack error
1351 pass
1353 if dev_type == 'vbd':
1354 if dev_info.get('dev', '').startswith('ioemu:'):
1355 dev_info['driver'] = 'ioemu'
1356 else:
1357 dev_info['driver'] = 'paravirtualised'
1359 if dev_type == 'tap':
1360 if dev_info['uname'].split(':')[1] not in blktap_disk_types:
1361 raise XendConfigError("tap:%s not a valid disk type" %
1362 dev_info['uname'].split(':')[1])
1364 if dev_type == 'vif':
1365 if not dev_info.get('mac'):
1366 dev_info['mac'] = randomMAC()
1368 ret_uuid = self.device_duplicate_check(dev_type, dev_info, target, config)
1369 if ret_uuid != None:
1370 return ret_uuid
1372 if dev_type == 'vif':
1373 if dev_info.get('policy') and dev_info.get('label'):
1374 dev_info['security_label'] = "%s:%s:%s" % \
1375 (xsconstants.ACM_POLICY_ID,
1376 dev_info['policy'],dev_info['label'])
1378 # create uuid if it doesn't exist
1379 dev_uuid = dev_info.get('uuid', None)
1380 if not dev_uuid:
1381 dev_uuid = uuid.createString()
1382 dev_info['uuid'] = dev_uuid
1384 # store dev references by uuid for certain device types
1385 target['devices'][dev_uuid] = (dev_type, dev_info)
1386 if dev_type in ('vif', 'vbd', 'vtpm'):
1387 param = '%s_refs' % dev_type
1388 if param not in target:
1389 target[param] = []
1390 if dev_uuid not in target[param]:
1391 if dev_type == 'vbd' and 'bootable' not in dev_info:
1392 # Compat hack -- mark first disk bootable
1393 dev_info['bootable'] = int(not target[param])
1394 target[param].append(dev_uuid)
1395 elif dev_type == 'tap':
1396 if 'vbd_refs' not in target:
1397 target['vbd_refs'] = []
1398 if dev_uuid not in target['vbd_refs']:
1399 if 'bootable' not in dev_info:
1400 # Compat hack -- mark first disk bootable
1401 dev_info['bootable'] = int(not target['vbd_refs'])
1402 target['vbd_refs'].append(dev_uuid)
1404 elif dev_type == 'vfb':
1405 # Populate other config with aux data that is associated
1406 # with vfb
1408 other_config = {}
1409 for key in XENAPI_CONSOLE_OTHER_CFG:
1410 if key in dev_info:
1411 other_config[key] = dev_info[key]
1412 target['devices'][dev_uuid][1]['other_config'] = other_config
1415 if 'console_refs' not in target:
1416 target['console_refs'] = []
1418 # Treat VFB devices as console devices so they are found
1419 # through Xen API
1420 if dev_uuid not in target['console_refs']:
1421 target['console_refs'].append(dev_uuid)
1423 # Cope with old-format save files which say under vfb
1424 # (type vfb) rather than (vfb 1)
1425 try:
1426 vfb_type = dev_info['type']
1427 except KeyError:
1428 vfb_type = None
1429 log.debug("iwj dev_type=%s vfb type %s" %
1430 (dev_type, `vfb_type`))
1432 if vfb_type == 'vnc' or vfb_type == 'sdl':
1433 dev_info[vfb_type] = 1
1434 del dev_info['type']
1435 log.debug("iwj dev_type=%s vfb setting dev_info['%s']" %
1436 (dev_type, vfb_type))
1437 # Create serial backends now, the location value is bogus, but does not matter
1438 i=0
1439 chardev=0
1440 if dev_info.get('serial') is not None :
1441 chardev = chardev + 1
1442 if dev_info.get('monitor') is not None :
1443 chardev = chardev + 1
1444 if chardev > 0 :
1445 chardev = chardev + 1
1446 while i < chardev :
1447 cfg = self.console_add('vt100', str(i))
1448 c_uuid = uuid.createString()
1449 target['devices'][c_uuid] = ('console', cfg)
1450 target['console_refs'].append(c_uuid)
1451 i = i + 1
1452 elif dev_type == 'console':
1453 if 'console_refs' not in target:
1454 target['console_refs'] = []
1455 if dev_uuid not in target['console_refs']:
1456 target['console_refs'].append(dev_uuid)
1458 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
1459 return dev_uuid
1461 if cfg_xenapi:
1462 dev_info = {}
1463 dev_uuid = ''
1464 if dev_type == 'vif':
1465 dev_info['mac'] = cfg_xenapi.get('MAC')
1466 if not dev_info['mac']:
1467 dev_info['mac'] = randomMAC()
1468 # vifname is the name on the guest, not dom0
1469 # TODO: we don't have the ability to find that out or
1470 # change it from dom0
1471 #if cfg_xenapi.get('device'): # don't add if blank
1472 # dev_info['vifname'] = cfg_xenapi.get('device')
1473 if cfg_xenapi.get('type'):
1474 dev_info['type'] = cfg_xenapi.get('type')
1475 if cfg_xenapi.get('name'):
1476 dev_info['name'] = cfg_xenapi.get('name')
1477 if cfg_xenapi.get('network'):
1478 network = XendAPIStore.get(
1479 cfg_xenapi.get('network'), 'network')
1480 dev_info['bridge'] = network.get_name_label()
1482 if cfg_xenapi.get('security_label'):
1483 dev_info['security_label'] = \
1484 cfg_xenapi.get('security_label')
1486 dev_uuid = cfg_xenapi.get('uuid', None)
1487 if not dev_uuid:
1488 dev_uuid = uuid.createString()
1489 dev_info['uuid'] = dev_uuid
1490 target['devices'][dev_uuid] = (dev_type, dev_info)
1491 target['vif_refs'].append(dev_uuid)
1493 elif dev_type in ('vbd', 'tap'):
1494 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1495 if dev_info['type'] == 'CD':
1496 old_vbd_type = 'cdrom'
1497 else:
1498 old_vbd_type = 'disk'
1500 dev_info['uname'] = cfg_xenapi.get('image', '')
1501 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1502 old_vbd_type)
1503 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1504 dev_info['driver'] = cfg_xenapi.get('driver', '')
1505 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1507 if cfg_xenapi.get('mode') == 'RW':
1508 dev_info['mode'] = 'w'
1509 else:
1510 dev_info['mode'] = 'r'
1512 dev_uuid = cfg_xenapi.get('uuid', None)
1513 if not dev_uuid:
1514 dev_uuid = uuid.createString()
1515 dev_info['uuid'] = dev_uuid
1516 target['devices'][dev_uuid] = (dev_type, dev_info)
1517 target['vbd_refs'].append(dev_uuid)
1519 elif dev_type == 'vtpm':
1520 if cfg_xenapi.get('type'):
1521 dev_info['type'] = cfg_xenapi.get('type')
1523 dev_uuid = cfg_xenapi.get('uuid', None)
1524 if not dev_uuid:
1525 dev_uuid = uuid.createString()
1526 dev_info['uuid'] = dev_uuid
1527 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1528 target['devices'][dev_uuid] = (dev_type, dev_info)
1529 target['vtpm_refs'].append(dev_uuid)
1531 elif dev_type == 'console':
1532 dev_uuid = cfg_xenapi.get('uuid', None)
1533 if not dev_uuid:
1534 dev_uuid = uuid.createString()
1535 dev_info['uuid'] = dev_uuid
1536 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1537 console_other_config = cfg_xenapi.get('other_config', {})
1538 dev_info['other_config'] = console_other_config
1539 if dev_info['protocol'] == 'rfb':
1540 # collapse other config into devinfo for things
1541 # such as vncpasswd, vncunused, etc.
1542 dev_info.update(console_other_config)
1543 dev_info['vnc'] = console_other_config.get('vnc', '0')
1544 dev_info['sdl'] = console_other_config.get('sdl', '0')
1545 target['devices'][dev_uuid] = ('vfb', dev_info)
1546 target['console_refs'].append(dev_uuid)
1548 # if console is rfb, set device_model ensuring qemu
1549 # is invoked for pvfb services
1550 if 'device_model' not in target['platform']:
1551 target['platform']['device_model'] = \
1552 xen.util.auxbin.pathTo("qemu-dm")
1554 # Finally, if we are a pvfb, we need to make a vkbd
1555 # as well that is not really exposed to Xen API
1556 vkbd_uuid = uuid.createString()
1557 target['devices'][vkbd_uuid] = ('vkbd', {})
1559 elif dev_info['protocol'] == 'vt100':
1560 # if someone tries to create a VT100 console
1561 # via the Xen API, we'll have to ignore it
1562 # because we create one automatically in
1563 # XendDomainInfo._update_consoles
1564 raise XendConfigError('Creating vt100 consoles via '
1565 'Xen API is unsupported')
1567 return dev_uuid
1569 # no valid device to add
1570 return ''
1572 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1573 target = None):
1574 """Add a phantom tap device configuration in XenAPI struct format.
1575 """
1577 if target == None:
1578 target = self
1580 if dev_type not in XendDevices.valid_devices() and \
1581 dev_type not in XendDevices.pseudo_devices():
1582 raise XendConfigError("XendConfig: %s not a valid device type" %
1583 dev_type)
1585 if cfg_xenapi == None:
1586 raise XendConfigError("XendConfig: device_add requires some "
1587 "config.")
1589 if cfg_xenapi:
1590 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1592 if cfg_xenapi:
1593 dev_info = {}
1594 if dev_type in ('vbd', 'tap'):
1595 if dev_type == 'vbd':
1596 dev_info['uname'] = cfg_xenapi.get('image', '')
1597 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1598 elif dev_type == 'tap':
1599 if cfg_xenapi.get('image').find('tap:') == -1:
1600 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1601 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1602 dev_info['uname'] = cfg_xenapi.get('image')
1603 dev_info['mode'] = cfg_xenapi.get('mode')
1604 dev_info['backend'] = '0'
1605 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1606 dev_info['uuid'] = dev_uuid
1607 self['devices'][dev_uuid] = (dev_type, dev_info)
1608 self['vbd_refs'].append(dev_uuid)
1609 return dev_uuid
1611 return ''
1613 def vscsi_convert_sxp_to_dict(self, dev_sxp):
1614 """Convert vscsi device sxp to dict
1615 @param dev_sxp: device configuration
1616 @type dev_sxp: SXP object (parsed config)
1617 @return: dev_config
1618 @rtype: dictionary
1619 """
1620 # Parsing the device SXP's. In most cases, the SXP looks
1621 # like this:
1623 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
1625 # However, for SCSI devices it looks like this:
1627 # [device,
1628 # [vscsi,
1629 # [feature-host, 0],
1630 # [backend, 0],
1631 # [dev,
1632 # [devid, 0], [p-devname, sdb], [p-dev, 1:0:0:1],
1633 # [v-dev, 0:0:0:0], [state, 1]
1634 # ],
1635 # [dev,
1636 # [devid, 0], [p-devname, sdc], [p-dev, 1:0:0:2],
1637 # [v-dev, 0:0:0:1], [satet, 1]
1638 # ]
1639 # ],
1640 # [vscsi,
1641 # [feature-host, 1],
1642 # [backend, 0],
1643 # [dev,
1644 # [devid, 1], [p-devname, sdg], [p-dev, 2:0:0:0],
1645 # [v-dev, 1:0:0:0], [state, 1]
1646 # ],
1647 # [dev,
1648 # [devid, 1], [p-devname, sdh], [p-dev, 2:0:0:1],
1649 # [v-dev, 1:0:0:1], [satet, 1]
1650 # ]
1651 # ]
1652 # ]
1654 # It seems the reasoning for this difference is because
1655 # vscsiif.py needs all the SCSI device configurations with
1656 # same host number at the same time when creating the devices.
1658 # For SCSI device hotplug support, the SXP of SCSI devices is
1659 # extendend like this:
1661 # [device,
1662 # [vscsi,
1663 # [feature-host, 0],
1664 # [backend, 0],
1665 # [dev,
1666 # [devid, 0], [p-devname, sdd], [p-dev, 1:0:0:3],
1667 # [v-dev, 0:0:0:2], [state, 1]
1668 # ]
1669 # ]
1670 # ]
1672 # state xenbusState['Initialising'] indicates that the device is
1673 # being attached, while state xenbusState['Closing'] indicates
1674 # that the device is being detached.
1676 # The Dict looks like this:
1678 # { devs: [ {devid: 0, p-devname: sdd, p-dev: 1:0:0:3,
1679 # v-dev: 0:0:0:2, state: 1} ],
1680 # feature-host: 1 , backend: 0 }
1682 dev_config = {}
1684 vscsi_devs = []
1685 for vscsi_dev in sxp.children(dev_sxp, 'dev'):
1686 vscsi_dev_info = {}
1687 for opt_val in vscsi_dev[1:]:
1688 try:
1689 opt, val = opt_val
1690 vscsi_dev_info[opt] = val
1691 except TypeError:
1692 pass
1693 # append uuid for each vscsi device.
1694 vscsi_uuid = vscsi_dev_info.get('uuid', uuid.createString())
1695 vscsi_dev_info['uuid'] = vscsi_uuid
1696 vscsi_devs.append(vscsi_dev_info)
1697 dev_config['devs'] = vscsi_devs
1699 vscsi_mode = sxp.children(dev_sxp, 'feature-host')[0]
1700 dev_config['feature-host'] = vscsi_mode[1]
1701 try:
1702 vscsi_be = sxp.children(dev_sxp, 'backend')[0]
1703 dev_config['backend'] = vscsi_be[1]
1704 except IndexError:
1705 pass
1707 return dev_config
1709 def console_add(self, protocol, location, other_config = {}):
1710 dev_uuid = uuid.createString()
1711 if protocol == 'vt100':
1712 dev_info = {
1713 'uuid': dev_uuid,
1714 'protocol': protocol,
1715 'location': location,
1716 'other_config': other_config,
1719 if 'devices' not in self:
1720 self['devices'] = {}
1722 self['devices'][dev_uuid] = ('console', dev_info)
1723 self['console_refs'].append(dev_uuid)
1724 return dev_info
1726 return {}
1728 def console_update(self, console_uuid, key, value):
1729 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1730 if dev_uuid == console_uuid:
1731 dev_info[key] = value
1732 # collapse other_config into dev_info for things
1733 # such as vncpasswd, vncunused, etc.
1734 if key == 'other_config':
1735 for k in XENAPI_CONSOLE_OTHER_CFG:
1736 if k in dev_info and k not in value:
1737 del dev_info[k]
1738 dev_info.update(value)
1739 break
1741 def console_get_all(self, protocol):
1742 if protocol == 'vt100':
1743 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1744 if dtype == 'console']
1745 return [c for c in consoles if c.get('protocol') == protocol]
1747 elif protocol == 'rfb':
1748 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1749 if dtype == 'vfb']
1751 # move all non-console key values to other_config before
1752 # returning console config
1753 valid_keys = ['uuid', 'location']
1754 for vfb in vfbs:
1755 other_config = {}
1756 for key, val in vfb.items():
1757 if key not in valid_keys:
1758 other_config[key] = vfb[key]
1759 del vfb[key]
1760 vfb['other_config'] = other_config
1761 vfb['protocol'] = 'rfb'
1763 return vfbs
1765 else:
1766 return []
1768 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1769 """Update an existing device with the new configuration.
1771 @rtype: boolean
1772 @return: Returns True if succesfully found and updated a device conf
1773 """
1774 if dev_uuid in self['devices'] and cfg_sxp:
1775 if sxp.child0(cfg_sxp) == 'device':
1776 config = sxp.child0(cfg_sxp)
1777 else:
1778 config = cfg_sxp
1780 dev_type, dev_info = self['devices'][dev_uuid]
1782 if dev_type == 'pci': # Special case for pci
1783 pci_dict = pci_convert_sxp_to_dict(config)
1784 pci_devs = pci_dict['devs']
1786 # destroy existing XenAPI DPCI objects
1787 for dpci_uuid in XendDPCI.get_by_VM(self['uuid']):
1788 XendAPIStore.deregister(dpci_uuid, "DPCI")
1790 # create XenAPI DPCI objects.
1791 self.create_dpci_from_sxp(pci_devs)
1793 self['devices'][dev_uuid] = (dev_type,
1794 {'devs': pci_devs,
1795 'uuid': dev_uuid})
1796 return True
1798 if dev_type == 'vscsi': # Special case for vscsi
1799 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1800 vscsi_devs = vscsi_dict['devs']
1801 vscsi_mode = vscsi_dict['feature-host']
1802 vscsi_be = vscsi_dict.get('backend', None)
1804 # destroy existing XenAPI DSCSI objects
1805 vscsi_devid = int(dev_info['devs'][0]['devid'])
1806 for dscsi_uuid in XendDSCSI.get_by_VM(self['uuid']):
1807 dscsi_inst = XendAPIStore.get(dscsi_uuid, 'DSCSI')
1808 if vscsi_devid == dscsi_inst.get_virtual_host():
1809 XendAPIStore.deregister(dscsi_uuid, "DSCSI")
1811 # create XenAPI DSCSI objects.
1812 for vscsi_dev in vscsi_devs:
1813 dscsi_uuid = vscsi_dev.get('uuid')
1814 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1815 if pscsi_uuid is None:
1816 continue
1817 dscsi_record = {
1818 'VM': self['uuid'],
1819 'PSCSI': pscsi_uuid,
1820 'virtual_HCTL': vscsi_dev.get('v-dev')
1822 XendDSCSI(dscsi_uuid, dscsi_record)
1824 vscsi_info = {
1825 'devs': vscsi_devs,
1826 'feature-host': vscsi_mode,
1827 'uuid': dev_uuid
1829 if vscsi_be is not None:
1830 vscsi_info['backend'] = vscsi_be
1831 self['devices'][dev_uuid] = (dev_type, vscsi_info)
1832 return True
1834 for opt_val in config[1:]:
1835 try:
1836 opt, val = opt_val
1837 dev_info[opt] = val
1838 except (TypeError, ValueError):
1839 pass # no value for this config option
1841 self['devices'][dev_uuid] = (dev_type, dev_info)
1842 return True
1844 elif dev_uuid in self['devices'] and cfg_xenapi:
1845 dev_type, dev_info = self['devices'][dev_uuid]
1846 for key, val in cfg_xenapi.items():
1847 dev_info[key] = val
1848 self['devices'][dev_uuid] = (dev_type, dev_info)
1849 return True
1851 return False
1854 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None, target = None):
1855 """Get Device SXPR by either giving the device UUID or (type, config).
1857 @rtype: list of lists
1858 @return: device config sxpr
1859 """
1860 sxpr = []
1862 if target == None:
1863 target = self
1865 if dev_uuid != None and dev_uuid in target['devices']:
1866 dev_type, dev_info = target['devices'][dev_uuid]
1868 if dev_type == None or dev_info == None:
1869 raise XendConfigError("Required either UUID or device type and "
1870 "configuration dictionary.")
1872 sxpr.append(dev_type)
1873 if dev_type in ('console', 'vfb'):
1874 config = [(opt, val) for opt, val in dev_info.items()
1875 if opt != 'other_config']
1876 else:
1877 config = [(opt, val) for opt, val in dev_info.items()]
1879 sxpr += config
1881 return sxpr
1883 def ordered_device_refs(self, target = None):
1884 result = []
1886 if target == None:
1887 target = self
1889 # vkbd devices *must* be before vfb devices, otherwise
1890 # there is a race condition when setting up devices
1891 # where the daemon spawned for the vfb may write stuff
1892 # into xenstore vkbd backend, before DevController has
1893 # setup permissions on the vkbd backend path. This race
1894 # results in domain creation failing with 'device already
1895 # connected' messages
1896 result.extend([u for u in target['devices'].keys() if target['devices'][u][0] == 'vkbd'])
1898 result.extend(target.get('console_refs', []) +
1899 target.get('vbd_refs', []) +
1900 target.get('vif_refs', []) +
1901 target.get('vtpm_refs', []))
1903 result.extend([u for u in target['devices'].keys() if u not in result])
1904 return result
1906 def all_devices_sxpr(self, target = None):
1907 """Returns the SXPR for all devices in the current configuration."""
1908 sxprs = []
1910 if target == None:
1911 target = self
1913 if 'devices' not in target:
1914 return sxprs
1916 ordered_refs = self.ordered_device_refs(target = target)
1917 for dev_uuid in ordered_refs:
1918 dev_type, dev_info = target['devices'][dev_uuid]
1919 if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
1920 if dev_type == 'pci':
1921 sxpr = ['pci', ['uuid', dev_info['uuid']]]
1922 elif dev_type == 'vscsi':
1923 sxpr = ['vscsi', ['uuid', dev_info['uuid']],
1924 ['feature-host', dev_info['feature-host']]]
1925 if dev_info.has_key('backend'):
1926 sxpr.append(['backend', dev_info['backend']])
1927 for pci_dev_info in dev_info['devs']:
1928 sxpr.append(dev_dict_to_sxp(pci_dev_info))
1929 sxprs.append((dev_type, sxpr))
1930 else:
1931 sxpr = self.device_sxpr(dev_type = dev_type,
1932 dev_info = dev_info,
1933 target = target)
1934 sxprs.append((dev_type, sxpr))
1936 return sxprs
1938 def image_sxpr(self):
1939 """Returns a backwards compatible image SXP expression that is
1940 used in xenstore's /vm/<uuid>/image value and xm list."""
1941 image = [self.image_type()]
1942 if self.has_key('PV_kernel'):
1943 image.append(['kernel', self['PV_kernel']])
1944 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1945 image.append(['ramdisk', self['PV_ramdisk']])
1946 if self.has_key('PV_args') and self['PV_args']:
1947 image.append(['args', self['PV_args']])
1948 if self.has_key('superpages'):
1949 image.append(['superpages', self['superpages']])
1951 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
1952 if key in self['platform']:
1953 image.append([key, self['platform'][key]])
1955 if 'notes' in self:
1956 image.append(self.notes_sxp(self['notes']))
1958 return image
1960 def update_with_image_sxp(self, image_sxp, bootloader = False):
1961 # Convert Legacy "image" config to Xen API PV_*
1962 # configuration
1963 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1965 # user-specified args must come last: previous releases did this and
1966 # some domU kernels rely upon the ordering.
1967 kernel_args = sxp.child_value(image_sxp, 'args', '')
1969 # attempt to extract extra arguments from SXP config
1970 arg_ip = sxp.child_value(image_sxp, 'ip')
1971 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1972 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1973 arg_root = sxp.child_value(image_sxp, 'root')
1974 if arg_root and not re.search(r'root=', kernel_args):
1975 kernel_args = 'root=%s ' % arg_root + kernel_args
1977 if bootloader:
1978 self['_temp_using_bootloader'] = '1'
1979 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1980 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1981 self['_temp_args'] = kernel_args
1982 else:
1983 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1984 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1985 self['PV_args'] = kernel_args
1987 self['superpages'] = sxp.child_value(image_sxp, 'superpages',0)
1989 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
1990 val = sxp.child_value(image_sxp, key, None)
1991 if val is not None and val != '':
1992 self['platform'][key] = val
1994 notes = sxp.children(image_sxp, 'notes')
1995 if notes:
1996 self['notes'] = self.notes_from_sxp(notes[0])
1998 self._hvm_boot_params_from_sxp(image_sxp)
2000 def set_notes(self, notes):
2001 'Add parsed elfnotes to image'
2002 self['notes'] = notes
2004 def get_notes(self):
2005 try:
2006 return self['notes'] or {}
2007 except KeyError:
2008 return {}
2010 def notes_from_sxp(self, nsxp):
2011 notes = {}
2012 for note in sxp.children(nsxp):
2013 notes[note[0]] = note[1]
2014 return notes
2016 def notes_sxp(self, notes):
2017 nsxp = ['notes']
2018 for k, v in notes.iteritems():
2019 nsxp.append([k, str(v)])
2020 return nsxp
2022 def _hvm_boot_params_from_sxp(self, image_sxp):
2023 boot = sxp.child_value(image_sxp, 'boot', None)
2024 if boot is not None:
2025 self['HVM_boot_policy'] = 'BIOS order'
2026 self['HVM_boot_params'] = { 'order' : boot }
2028 def is_hvm(self):
2029 return self['HVM_boot_policy'] != ''
2031 def target(self):
2032 return self['target']
2034 def image_type(self):
2035 stored_type = self['platform'].get('image_type')
2036 return stored_type or (self.is_hvm() and 'hvm' or 'linux')
2038 def is_hap(self):
2039 return self['platform'].get('hap', 0)
2041 def update_platform_pci(self):
2042 if not self.is_hvm():
2043 return
2045 pci = []
2046 for dev_type, dev_info in self.all_devices_sxpr():
2047 if dev_type != 'pci':
2048 continue
2049 for dev in sxp.children(dev_info, 'dev'):
2050 domain = sxp.child_value(dev, 'domain')
2051 bus = sxp.child_value(dev, 'bus')
2052 slot = sxp.child_value(dev, 'slot')
2053 func = sxp.child_value(dev, 'func')
2054 vslot = sxp.child_value(dev, 'vslot')
2055 opts = pci_opts_list_from_sxp(dev)
2056 pci.append([domain, bus, slot, func, vslot, opts])
2057 self['platform']['pci'] = pci