ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 19813:b55070edb185

tools: don't require hardcoded firmware path in guest config file

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