debuggers.hg

view tools/python/xen/xend/XendConfig.py @ 19975:e845326ae203

python: Remove tab indents.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jul 14 14:43:19 2009 +0100 (2009-07-14)
parents 8f6dd1671599
children e07726c03d31
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
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'])
469 if not os.path.exists(self['platform']['device_model']):
470 raise VmError("device model '%s' not found" % str(self['platform']['device_model']))
472 if self.is_hvm():
473 if 'timer_mode' not in self['platform']:
474 self['platform']['timer_mode'] = 1
475 if 'viridian' not in self['platform']:
476 self['platform']['viridian'] = 0
477 if 'rtc_timeoffset' not in self['platform']:
478 self['platform']['rtc_timeoffset'] = 0
479 if 'hpet' not in self['platform']:
480 self['platform']['hpet'] = 0
481 if 'xen_platform_pci' not in self['platform']:
482 self['platform']['xen_platform_pci'] = 1
483 if 'vpt_align' not in self['platform']:
484 self['platform']['vpt_align'] = 1
485 if 'loader' not in self['platform']:
486 # Old configs may have hvmloader set as PV_kernel param
487 if self.has_key('PV_kernel') and self['PV_kernel'] != '':
488 if self['PV_kernel'] == 'hvmloader':
489 self['PV_kernel'] = auxbin.pathTo("hvmloader")
490 self['platform']['loader'] = self['PV_kernel']
491 self['PV_kernel'] = ''
492 else:
493 self['platform']['loader'] = auxbin.pathTo("hvmloader")
494 log.debug("Loader is %s" % str(self['platform']['loader']))
495 elif self['platform']['loader'] == 'hvmloader':
496 self['platform']['loader'] = auxbin.pathTo("hvmloader")
497 if not os.path.exists(self['platform']['loader']):
498 raise VmError("kernel '%s' not found" % str(self['platform']['loader']))
500 # Compatibility hack, can go away soon.
501 if 'soundhw' not in self['platform'] and \
502 self['platform'].get('enable_audio'):
503 self['platform']['soundhw'] = 'sb16'
505 def validate(self):
506 self._uuid_sanity_check()
507 self._name_sanity_check()
508 self._memory_sanity_check()
509 self._actions_sanity_check()
510 self._vcpus_sanity_check()
511 self._platform_sanity_check()
513 def _dominfo_to_xapi(self, dominfo, update_mem = False):
514 self['domid'] = dominfo['domid']
515 self['online_vcpus'] = dominfo['online_vcpus']
516 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
518 if update_mem:
519 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
520 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
521 self['memory_static_min'] = 0
522 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
523 self._memory_sanity_check()
525 self['cpu_time'] = dominfo['cpu_time']/1e9
526 if dominfo.get('ssidref'):
527 ssidref = int(dominfo.get('ssidref'))
528 import xen.util.xsm.xsm as security
529 self['security_label'] = security.ssidref2security_label(ssidref)
531 self['shutdown_reason'] = dominfo['shutdown_reason']
533 # parse state into Xen API states
534 self['running'] = dominfo['running']
535 self['crashed'] = dominfo['crashed']
536 self['dying'] = dominfo['dying']
537 self['shutdown'] = dominfo['shutdown']
538 self['paused'] = dominfo['paused']
539 self['blocked'] = dominfo['blocked']
541 if 'name' in dominfo:
542 self['name_label'] = dominfo['name']
544 if 'handle' in dominfo:
545 self['uuid'] = uuid.toString(dominfo['handle'])
547 def parse_cpuid(self, cfg, field):
548 def int2bin(n, count=32):
549 return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
551 for input, regs in cfg[field].iteritems():
552 if not regs is dict:
553 cfg[field][input] = dict(regs)
555 cpuid = {}
556 for input in cfg[field]:
557 inputs = input.split(',')
558 if inputs[0][0:2] == '0x':
559 inputs[0] = str(int(inputs[0], 16))
560 if len(inputs) == 2:
561 if inputs[1][0:2] == '0x':
562 inputs[1] = str(int(inputs[1], 16))
563 new_input = ','.join(inputs)
564 cpuid[new_input] = {} # new input
565 for reg in cfg[field][input]:
566 val = cfg[field][input][reg]
567 if val[0:2] == '0x':
568 cpuid[new_input][reg] = int2bin(int(val, 16))
569 else:
570 cpuid[new_input][reg] = val
571 cfg[field] = cpuid
573 def _parse_sxp(self, sxp_cfg):
574 """ Populate this XendConfig using the parsed SXP.
576 @param sxp_cfg: Parsed SXP Configuration
577 @type sxp_cfg: list of lists
578 @rtype: dictionary
579 @return: A dictionary containing the parsed options of the SXP.
580 """
581 cfg = {}
583 for key, typ in XENAPI_CFG_TYPES.items():
584 val = sxp.child_value(sxp_cfg, key)
585 if val is not None:
586 try:
587 cfg[key] = typ(val)
588 except (ValueError, TypeError), e:
589 log.warn('Unable to convert type value for key: %s' % key)
591 # Convert deprecated options to current equivalents.
593 restart = sxp.child_value(sxp_cfg, 'restart')
594 if restart:
595 if restart == 'onreboot':
596 cfg['on_poweroff'] = 'destroy'
597 cfg['on_reboot'] = 'restart'
598 cfg['on_crash'] = 'destroy'
599 elif restart == 'always':
600 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
601 cfg[opt] = 'restart'
602 elif restart == 'never':
603 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
604 cfg[opt] = 'never'
605 else:
606 log.warn('Ignoring unrecognised value for deprecated option:'
607 'restart = \'%s\'', restart)
609 # Handle memory, passed in as MiB
611 if sxp.child_value(sxp_cfg, "memory") != None:
612 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
613 if sxp.child_value(sxp_cfg, "maxmem") != None:
614 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
616 # Convert scheduling parameters to vcpus_params
617 if 'vcpus_params' not in cfg:
618 cfg['vcpus_params'] = {}
619 cfg["vcpus_params"]["weight"] = \
620 int(sxp.child_value(sxp_cfg, "cpu_weight", 256))
621 cfg["vcpus_params"]["cap"] = \
622 int(sxp.child_value(sxp_cfg, "cpu_cap", 0))
624 # Only extract options we know about.
625 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG + \
626 XENAPI_CFG_TO_LEGACY_CFG.values()
628 for key in extract_keys:
629 val = sxp.child_value(sxp_cfg, key)
630 if val != None:
631 try:
632 cfg[key] = LEGACY_CFG_TYPES[key](val)
633 except KeyError:
634 cfg[key] = val
635 except (TypeError, ValueError), e:
636 log.warn("Unable to parse key %s: %s: %s" %
637 (key, str(val), e))
639 if 'platform' not in cfg:
640 cfg['platform'] = {}
641 localtime = sxp.child_value(sxp_cfg, 'localtime')
642 if localtime is not None:
643 cfg['platform']['localtime'] = localtime
645 # Compatibility hack -- can go soon.
646 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
647 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
648 if val is not None:
649 self['platform'][key] = val
651 # Compatibility hack -- can go soon.
652 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
653 if boot_order:
654 cfg['HVM_boot_policy'] = 'BIOS order'
655 cfg['HVM_boot_params'] = { 'order' : boot_order }
658 # Parsing the device SXP's.
659 cfg['devices'] = {}
660 for dev in sxp.children(sxp_cfg, 'device'):
661 config = sxp.child0(dev)
662 dev_type = sxp.name(config)
663 self.device_add(dev_type, cfg_sxp = config, target = cfg)
665 # Extract missing data from configuration entries
666 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
667 if image_sxp:
668 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
669 if image_vcpus != None:
670 try:
671 if 'VCPUs_max' not in cfg:
672 cfg['VCPUs_max'] = int(image_vcpus)
673 elif cfg['VCPUs_max'] != int(image_vcpus):
674 cfg['VCPUs_max'] = int(image_vcpus)
675 log.warn('Overriding vcpus from %d to %d using image'
676 'vcpus value.', cfg['VCPUs_max'])
677 except ValueError, e:
678 raise XendConfigError('integer expeceted: %s: %s' %
679 image_sxp, e)
681 # Deprecated cpu configuration
682 if 'cpu' in cfg:
683 if 'cpus' in cfg:
684 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
685 else:
686 cfg['cpus'] = str(cfg['cpu'])
688 # Convert 'cpus' to list of list of ints
689 cpus_list = []
690 if 'cpus' in cfg:
691 # Convert the following string to list of ints.
692 # The string supports a list of ranges (0-3),
693 # seperated by commas, and negation (^1).
694 # Precedence is settled by order of the string:
695 # "0-3,^1" -> [0,2,3]
696 # "0-3,^1,1" -> [0,1,2,3]
697 def cnv(s):
698 l = []
699 for c in s.split(','):
700 if c.find('-') != -1:
701 (x, y) = c.split('-')
702 for i in range(int(x), int(y)+1):
703 l.append(int(i))
704 else:
705 # remove this element from the list
706 if c[0] == '^':
707 l = [x for x in l if x != int(c[1:])]
708 else:
709 l.append(int(c))
710 return l
712 if type(cfg['cpus']) == list:
713 if len(cfg['cpus']) > 0 and type(cfg['cpus'][0]) == list:
714 # If sxp_cfg was created from config.sxp,
715 # the form of 'cpus' is list of list of string.
716 # Convert 'cpus' to list of list of ints.
717 # Conversion examples:
718 # [['1']] -> [[1]]
719 # [['0','2'],['1','3']] -> [[0,2],[1,3]]
720 try:
721 for c1 in cfg['cpus']:
722 cpus = []
723 for c2 in c1:
724 cpus.append(int(c2))
725 cpus_list.append(cpus)
726 except ValueError, e:
727 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
728 else:
729 # Conversion examples:
730 # ["1"] -> [[1]]
731 # ["0,2","1,3"] -> [[0,2],[1,3]]
732 # ["0-3,^1","1-4,^2"] -> [[0,2,3],[1,3,4]]
733 try:
734 for c in cfg['cpus']:
735 cpus = cnv(c)
736 cpus_list.append(cpus)
737 except ValueError, e:
738 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
740 if len(cpus_list) != cfg['vcpus']:
741 raise XendConfigError('vcpus and the item number of cpus are not same')
742 else:
743 # Conversion examples:
744 # vcpus=1:
745 # "1" -> [[1]]
746 # "0-3,^1" -> [[0,2,3]]
747 # vcpus=2:
748 # "1" -> [[1],[1]]
749 # "0-3,^1" -> [[0,2,3],[0,2,3]]
750 try:
751 cpus = cnv(cfg['cpus'])
752 for v in range(0, cfg['vcpus']):
753 cpus_list.append(cpus)
754 except ValueError, e:
755 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
756 else:
757 # Generation examples:
758 # vcpus=1:
759 # -> [[]]
760 # vcpus=2:
761 # -> [[],[]]
762 for v in range(0, cfg['vcpus']):
763 cpus_list.append(list())
765 cfg['cpus'] = cpus_list
767 # Parse cpuid
768 if 'cpuid' in cfg:
769 self.parse_cpuid(cfg, 'cpuid')
770 if 'cpuid_check' in cfg:
771 self.parse_cpuid(cfg, 'cpuid_check')
773 import xen.util.xsm.xsm as security
774 if security.on() == xsconstants.XS_POLICY_USE:
775 from xen.util.acmpolicy import ACM_LABEL_UNLABELED
776 if not 'security' in cfg and sxp.child_value(sxp_cfg, 'security'):
777 cfg['security'] = sxp.child_value(sxp_cfg, 'security')
778 elif not cfg.get('security_label'):
779 cfg['security'] = [['access_control',
780 ['policy', security.get_active_policy_name() ],
781 ['label', ACM_LABEL_UNLABELED ]]]
783 if 'security' in cfg and not cfg.get('security_label'):
784 secinfo = cfg['security']
785 # The xm command sends a list formatted like this:
786 # [['access_control', ['policy', 'xm-test'],['label', 'red']],
787 # ['ssidref', 196611]]
788 policy = ""
789 label = ""
790 for idx in range(0, len(secinfo)):
791 if secinfo[idx][0] == "access_control":
792 for aidx in range(1, len(secinfo[idx])):
793 if secinfo[idx][aidx][0] == "policy":
794 policy = secinfo[idx][aidx][1]
795 if secinfo[idx][aidx][0] == "label":
796 label = secinfo[idx][aidx][1]
797 cfg['security_label'] = \
798 security.set_security_label(policy, label)
799 if not sxp.child_value(sxp_cfg, 'security_label'):
800 del cfg['security']
802 sec_lab = cfg['security_label'].split(":")
803 if len(sec_lab) != 3:
804 raise XendConfigError("Badly formatted security label: %s"
805 % cfg['security_label'])
807 old_state = sxp.child_value(sxp_cfg, 'state')
808 if old_state:
809 for i in range(len(CONFIG_OLD_DOM_STATES)):
810 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
812 return cfg
815 def _sxp_to_xapi(self, sxp_cfg):
816 """Read in an SXP Configuration object and
817 populate at much of the Xen API with valid values.
818 """
819 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
821 # _parse_sxp() below will call device_add() and construct devices.
822 # Some devices may require VM's uuid, so setup self['uuid']
823 # beforehand.
824 self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString())
826 cfg = self._parse_sxp(sxp_cfg)
828 for key, typ in XENAPI_CFG_TYPES.items():
829 val = cfg.get(key)
830 if val is not None:
831 self[key] = typ(val)
833 # Convert parameters that can be directly mapped from
834 # the Legacy Config to Xen API Config
836 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
837 try:
838 type_conv = XENAPI_CFG_TYPES.get(apikey)
839 if callable(type_conv):
840 self[apikey] = type_conv(cfg[cfgkey])
841 else:
842 log.warn("Unconverted key: " + apikey)
843 self[apikey] = cfg[cfgkey]
844 except KeyError:
845 pass
847 # Lets try and handle memory correctly
849 MiB = 1024 * 1024
851 if "memory" in cfg:
852 self["memory_static_min"] = 0
853 self["memory_static_max"] = int(cfg["memory"]) * MiB
854 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
855 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
857 if "maxmem" in cfg:
858 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
860 self._memory_sanity_check()
862 def update_with(n, o):
863 if not self.get(n):
864 self[n] = cfg.get(o, '')
866 update_with('PV_bootloader', 'bootloader')
867 update_with('PV_bootloader_args', 'bootloader_args')
869 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
870 if image_sxp:
871 self.update_with_image_sxp(image_sxp)
873 # Convert Legacy HVM parameters to Xen API configuration
874 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
875 if key in cfg:
876 self['platform'][key] = cfg[key]
878 # set device references in the configuration
879 self['devices'] = cfg.get('devices', {})
880 self['console_refs'] = cfg.get('console_refs', [])
881 self['vif_refs'] = cfg.get('vif_refs', [])
882 self['vbd_refs'] = cfg.get('vbd_refs', [])
883 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
885 # coalesce hvm vnc frame buffer with vfb config
886 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
887 # add vfb device if it isn't there already
888 if not self.has_rfb():
889 dev_config = ['vfb']
890 dev_config.append(['vnc', '1'])
891 # copy VNC related params from platform config to vfb dev conf
892 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
893 'vnclisten']:
894 if key in self['platform']:
895 dev_config.append([key, self['platform'][key]])
897 self.device_add('vfb', cfg_sxp = dev_config)
900 def has_rfb(self):
901 for console_uuid in self['console_refs']:
902 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
903 return True
904 if self['devices'][console_uuid][0] == 'vfb':
905 return True
906 return False
908 def _sxp_to_xapi_unsupported(self, sxp_cfg):
909 """Read in an SXP configuration object and populate
910 values are that not related directly supported in
911 the Xen API.
912 """
914 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
916 # Parse and convert parameters used to configure
917 # the image (as well as HVM images)
918 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
919 if image_sxp:
920 image_type = sxp.name(image_sxp)
921 if image_type != 'hvm' and image_type != 'linux':
922 self['platform']['image_type'] = image_type
924 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
925 val = sxp.child_value(image_sxp, key, None)
926 if val is not None and val != '':
927 self['platform'][key] = val
929 notes = sxp.children(image_sxp, 'notes')
930 if notes:
931 self['notes'] = self.notes_from_sxp(notes[0])
933 self._hvm_boot_params_from_sxp(image_sxp)
935 # extract backend value
937 backend = []
938 for c in sxp.children(sxp_cfg, 'backend'):
939 backend.append(sxp.name(sxp.child0(c)))
940 if backend:
941 self['backend'] = backend
943 # Parse and convert other Non Xen API parameters.
944 def _set_cfg_if_exists(sxp_arg):
945 val = sxp.child_value(sxp_cfg, sxp_arg)
946 if val != None:
947 if LEGACY_CFG_TYPES.get(sxp_arg):
948 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
949 else:
950 self[sxp_arg] = val
952 _set_cfg_if_exists('shadow_memory')
953 _set_cfg_if_exists('features')
954 _set_cfg_if_exists('on_xend_stop')
955 _set_cfg_if_exists('on_xend_start')
956 _set_cfg_if_exists('vcpu_avail')
958 # Parse and store runtime configuration
959 _set_cfg_if_exists('start_time')
960 _set_cfg_if_exists('cpu_time')
961 _set_cfg_if_exists('shutdown_reason')
962 _set_cfg_if_exists('up_time')
963 _set_cfg_if_exists('status') # TODO, deprecated
965 def _get_old_state_string(self):
966 """Returns the old xm state string.
967 @rtype: string
968 @return: old state string
969 """
970 state_string = ''
971 for state_name in CONFIG_OLD_DOM_STATES:
972 on_off = self.get(state_name, 0)
973 if on_off:
974 state_string += state_name[0]
975 else:
976 state_string += '-'
978 return state_string
981 def update_config(self, dominfo):
982 """Update configuration with the output from xc.domain_getinfo().
984 @param dominfo: Domain information via xc.domain_getinfo()
985 @type dominfo: dict
986 """
987 self._dominfo_to_xapi(dominfo)
988 self.validate()
990 def update_with_xenapi_config(self, xapi):
991 """Update configuration with a Xen API VM struct
993 @param xapi: Xen API VM Struct
994 @type xapi: dict
995 """
997 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
999 for key, val in xapi.items():
1000 type_conv = XENAPI_CFG_TYPES.get(key)
1001 if type_conv is None:
1002 key = key.lower()
1003 type_conv = XENAPI_CFG_TYPES.get(key)
1004 if callable(type_conv):
1005 self[key] = type_conv(val)
1006 else:
1007 self[key] = val
1009 # XenAPI defines platform as a string-string map. If platform
1010 # configuration exists, convert values to appropriate type.
1011 if 'platform' in xapi:
1012 for key, val in xapi['platform'].items():
1013 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1014 if type_conv is None:
1015 key = key.lower()
1016 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1017 if callable(type_conv):
1018 self['platform'][key] = type_conv(val)
1019 else:
1020 self['platform'][key] = val
1022 self['vcpus_params']['weight'] = \
1023 int(self['vcpus_params'].get('weight', 256))
1024 self['vcpus_params']['cap'] = int(self['vcpus_params'].get('cap', 0))
1026 def cpuid_to_sxp(self, sxpr, field):
1027 regs_list = []
1028 for input, regs in self[field].iteritems():
1029 reg_list = []
1030 for reg, val in regs.iteritems():
1031 reg_list.append([reg, val])
1032 regs_list.append([input, reg_list])
1033 sxpr.append([field, regs_list])
1036 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
1037 legacy_only = True):
1038 """ Get SXP representation of this config object.
1040 Incompat: removed store_mfn, console_mfn
1042 @keyword domain: (optional) XendDomainInfo to get extra information
1043 from such as domid and running devices.
1044 @type domain: XendDomainInfo
1045 @keyword ignore: (optional) list of 'keys' that we do not want
1046 to export.
1047 @type ignore: list of strings
1048 @rtype: list of list (SXP representation)
1049 """
1050 sxpr = ['domain']
1052 # TODO: domid/dom is the same thing but called differently
1053 # depending if it is from xenstore or sxpr.
1055 if domain.getDomid() is not None:
1056 sxpr.append(['domid', domain.getDomid()])
1058 if not legacy_only:
1059 for name, typ in XENAPI_CFG_TYPES.items():
1060 if name in self and self[name] not in (None, []):
1061 if typ == dict:
1062 s = self[name].items()
1063 elif typ == list:
1064 s = self[name]
1065 else:
1066 s = str(self[name])
1067 sxpr.append([name, s])
1069 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
1070 if self.has_key(xenapi) and self[xenapi] not in (None, []):
1071 if type(self[xenapi]) == bool:
1072 # convert booleans to ints before making an sxp item
1073 sxpr.append([legacy, int(self[xenapi])])
1074 else:
1075 sxpr.append([legacy, self[xenapi]])
1077 MiB = 1024*1024
1079 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
1080 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
1082 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
1083 if legacy in ('domid', 'uuid', 'cpus'): # skip these
1084 continue
1085 if self.has_key(legacy) and self[legacy] not in (None, []):
1086 sxpr.append([legacy, self[legacy]])
1088 if self.has_key('security_label'):
1089 sxpr.append(['security_label', self['security_label']])
1091 sxpr.append(['image', self.image_sxpr()])
1092 sxpr.append(['status', domain._stateGet()])
1094 if domain.getDomid() is not None:
1095 sxpr.append(['state', self._get_old_state_string()])
1097 if domain:
1098 if domain.store_mfn:
1099 sxpr.append(['store_mfn', domain.store_mfn])
1100 if domain.console_mfn:
1101 sxpr.append(['console_mfn', domain.console_mfn])
1104 # Marshall devices (running or from configuration)
1105 if not ignore_devices:
1106 txn = xstransact()
1107 try:
1108 for cls in XendDevices.valid_devices():
1109 found = False
1111 # figure if there is a dev controller is valid and running
1112 if domain and domain.getDomid() != None:
1113 try:
1114 controller = domain.getDeviceController(cls)
1115 configs = controller.configurations(txn)
1116 for config in configs:
1117 if sxp.name(config) in ('vbd', 'tap', 'tap2'):
1118 dev_uuid = sxp.child_value(config, 'uuid')
1119 dev_type, dev_cfg = self['devices'][dev_uuid]
1120 if sxp.child_value(config, 'bootable', None) is None:
1121 is_bootable = dev_cfg.get('bootable', 0)
1122 config.append(['bootable', int(is_bootable)])
1123 config.append(['VDI', dev_cfg.get('VDI', '')])
1125 sxpr.append(['device', config])
1127 found = True
1128 except:
1129 log.exception("dumping sxp from device controllers")
1130 pass
1132 # if we didn't find that device, check the existing config
1133 # for a device in the same class
1134 if not found:
1135 for dev_type, dev_info in self.all_devices_sxpr():
1136 if dev_type == cls:
1137 sxpr.append(['device', dev_info])
1139 txn.commit()
1140 except:
1141 txn.abort()
1142 raise
1144 if 'cpuid' in self:
1145 self.cpuid_to_sxp(sxpr, 'cpuid')
1146 if 'cpuid_check' in self:
1147 self.cpuid_to_sxp(sxpr, 'cpuid_check')
1149 log.debug(sxpr)
1151 return sxpr
1153 def _blkdev_name_to_number(self, dev):
1154 if 'ioemu:' in dev:
1155 _, dev = dev.split(':', 1)
1156 try:
1157 dev, _ = dev.split(':', 1)
1158 except ValueError:
1159 pass
1161 try:
1162 devid = int(dev)
1163 except ValueError:
1164 # devid is not a number but a string containing either device
1165 # name (e.g. xvda) or device_type/device_id (e.g. vbd/51728)
1166 dev2 = type(dev) is str and dev.split('/')[-1] or None
1167 if dev2 == None:
1168 log.debug("Could not check the device %s", dev)
1169 return None
1170 try:
1171 devid = int(dev2)
1172 except ValueError:
1173 (xenbus, devid) = blkdev_name_to_number(dev2)
1174 if devid == None:
1175 log.debug("The device %s is not device name", dev2)
1176 return None
1177 return devid
1179 def device_duplicate_check(self, dev_type, dev_info, defined_config, config):
1180 defined_devices_sxpr = self.all_devices_sxpr(target = defined_config)
1182 if dev_type == 'vbd' or dev_type == 'tap' or dev_type == 'tap2':
1183 dev_uname = dev_info.get('uname')
1184 blkdev_name = dev_info.get('dev')
1185 devid = self._blkdev_name_to_number(blkdev_name)
1186 if devid == None or dev_uname == None:
1187 return
1189 for o_dev_type, o_dev_info in defined_devices_sxpr:
1190 if o_dev_type == 'vbd' or o_dev_type == 'tap' or o_dev_type == 'tap2':
1191 blkdev_file = blkdev_uname_to_file(dev_uname)
1192 o_dev_uname = sxp.child_value(o_dev_info, 'uname')
1193 if o_dev_uname != None:
1194 o_blkdev_file = blkdev_uname_to_file(o_dev_uname)
1195 if blkdev_file == o_blkdev_file:
1196 raise XendConfigError('The file "%s" is already used' %
1197 blkdev_file)
1198 if dev_uname == o_dev_uname:
1199 raise XendConfigError('The uname "%s" is already defined' %
1200 dev_uname)
1201 o_blkdev_name = sxp.child_value(o_dev_info, 'dev')
1202 o_devid = self._blkdev_name_to_number(o_blkdev_name)
1203 if o_devid != None and devid == o_devid:
1204 name_array = blkdev_name.split(':', 2)
1205 if len(name_array) == 2 and name_array[1] == 'cdrom':
1207 # Since the device is a cdrom, we are most likely
1208 # inserting, changing, or removing a cd. We can
1209 # update the old device instead of creating a new
1210 # one.
1212 if o_dev_uname != None and dev_uname == None:
1214 # We are removing a cd. We can simply update
1215 # the uname on the existing device.
1217 merge_sxp = sxp.from_string("('vbd' ('uname' ''))")
1218 else:
1219 merge_sxp = config
1221 dev_uuid = sxp.child_value(o_dev_info, 'uuid')
1222 if dev_uuid != None and \
1223 self.device_update(dev_uuid, cfg_sxp = merge_sxp):
1224 return dev_uuid
1226 raise XendConfigError('The device "%s" is already defined' %
1227 blkdev_name)
1229 elif dev_type == 'vif':
1230 dev_mac = dev_info.get('mac')
1232 for o_dev_type, o_dev_info in defined_devices_sxpr:
1233 if dev_type == o_dev_type:
1234 if dev_mac.lower() == sxp.child_value(o_dev_info, 'mac').lower():
1235 raise XendConfigError('The mac "%s" is already defined' %
1236 dev_mac)
1237 return None
1239 def create_dpci_from_sxp(self, pci_devs):
1240 for pci_dev in pci_devs:
1241 dpci_uuid = pci_dev.get('uuid')
1242 log.debug("create_dpci_from_sxp: %s" % pci_dev)
1243 ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
1244 pci_dev['bus'],
1245 pci_dev['slot'],
1246 pci_dev['func'])
1247 if ppci_uuid is None:
1248 continue
1249 dpci_record = {
1250 'VM': self['uuid'],
1251 'PPCI': ppci_uuid,
1252 'hotplug_slot': pci_dev.get('vdevfn', '0x%02x' % AUTO_PHP_SLOT),
1253 'key': pci_dev['key']
1256 dpci_opts = pci_dev.get('opts')
1257 if dpci_opts and len(dpci_opts) > 0:
1258 dpci_record['options'] = dpci_opts
1260 XendDPCI(dpci_uuid, dpci_record)
1262 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
1263 target = None):
1264 """Add a device configuration in SXP format or XenAPI struct format.
1266 For SXP, it could be either:
1268 [device, [vbd, [uname ...]]
1270 or:
1272 [vbd, [uname ..]]
1274 @type cfg_sxp: list of lists (parsed sxp object)
1275 @param cfg_sxp: SXP configuration object
1276 @type cfg_xenapi: dict
1277 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
1278 @param target: write device information to
1279 @type target: None or a dictionary
1280 @rtype: string
1281 @return: Assigned UUID of the device.
1282 """
1283 if target == None:
1284 target = self
1286 if dev_type not in XendDevices.valid_devices():
1287 raise XendConfigError("XendConfig: %s not a valid device type" %
1288 dev_type)
1290 if cfg_sxp == None and cfg_xenapi == None:
1291 raise XendConfigError("XendConfig: device_add requires some "
1292 "config.")
1294 #if cfg_sxp:
1295 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
1296 #if cfg_xenapi:
1297 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
1299 if cfg_sxp:
1300 if sxp.child0(cfg_sxp) == 'device':
1301 config = sxp.child0(cfg_sxp)
1302 else:
1303 config = cfg_sxp
1305 dev_type = sxp.name(config)
1306 dev_info = {}
1308 if dev_type == 'pci':
1309 pci_devs_uuid = sxp.child_value(config, 'uuid',
1310 uuid.createString())
1312 pci_dict = pci_convert_sxp_to_dict(config)
1313 pci_devs = pci_dict['devs']
1315 # create XenAPI DPCI objects.
1316 self.create_dpci_from_sxp(pci_devs)
1318 target['devices'][pci_devs_uuid] = (dev_type,
1319 {'devs': pci_devs,
1320 'uuid': pci_devs_uuid})
1322 log.debug("XendConfig: reading device: %s" % pci_devs)
1324 return pci_devs_uuid
1326 if dev_type == 'vscsi':
1327 vscsi_devs_uuid = sxp.child_value(config, 'uuid',
1328 uuid.createString())
1329 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1330 vscsi_devs = vscsi_dict['devs']
1331 vscsi_mode = vscsi_dict['feature-host']
1332 vscsi_be = vscsi_dict.get('backend', None)
1334 # create XenAPI DSCSI objects.
1335 for vscsi_dev in vscsi_devs:
1336 dscsi_uuid = vscsi_dev.get('uuid')
1337 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1338 if pscsi_uuid is None:
1339 continue
1340 dscsi_record = {
1341 'VM': self['uuid'],
1342 'PSCSI': pscsi_uuid,
1343 'virtual_HCTL': vscsi_dev.get('v-dev')
1345 XendDSCSI(dscsi_uuid, dscsi_record)
1347 vscsi_info = {
1348 'devs': vscsi_devs,
1349 'feature-host': vscsi_mode,
1350 'uuid': vscsi_devs_uuid
1352 if vscsi_be is not None:
1353 vscsi_info['backend'] = vscsi_be
1354 target['devices'][vscsi_devs_uuid] = (dev_type, vscsi_info)
1355 log.debug("XendConfig: reading device: %s,%s" % \
1356 (vscsi_devs, vscsi_mode))
1357 return vscsi_devs_uuid
1359 for opt_val in config[1:]:
1360 try:
1361 opt, val = opt_val
1362 dev_info[opt] = val
1363 except (TypeError, ValueError): # unpack error
1364 pass
1366 if dev_type == 'vbd':
1367 if dev_info.get('dev', '').startswith('ioemu:'):
1368 dev_info['driver'] = 'ioemu'
1369 else:
1370 dev_info['driver'] = 'paravirtualised'
1372 if dev_type == 'tap' or dev_type == 'tap2':
1373 tap_disk_type = dev_info['uname'].split(':')[1]
1374 # tapdisk uname may be 'tap:<driver>' or 'tap:tapdisk:<driver>'
1375 if tap_disk_type == 'tapdisk':
1376 tap_disk_type = dev_info['uname'].split(':')[2]
1377 if tap_disk_type not in blktap_disk_types:
1378 raise XendConfigError("tap:%s not a valid disk type" %
1379 tap_disk_type)
1381 if dev_type == 'vif':
1382 if not dev_info.get('mac'):
1383 dev_info['mac'] = randomMAC()
1385 ret_uuid = self.device_duplicate_check(dev_type, dev_info, target, config)
1386 if ret_uuid != None:
1387 return ret_uuid
1389 if dev_type == 'vif':
1390 if dev_info.get('policy') and dev_info.get('label'):
1391 dev_info['security_label'] = "%s:%s:%s" % \
1392 (xsconstants.ACM_POLICY_ID,
1393 dev_info['policy'],dev_info['label'])
1395 # create uuid if it doesn't exist
1396 dev_uuid = dev_info.get('uuid', None)
1397 if not dev_uuid:
1398 dev_uuid = uuid.createString()
1399 dev_info['uuid'] = dev_uuid
1401 # store dev references by uuid for certain device types
1402 target['devices'][dev_uuid] = (dev_type, dev_info)
1403 if dev_type in ('vif', 'vbd', 'vtpm'):
1404 param = '%s_refs' % dev_type
1405 if param not in target:
1406 target[param] = []
1407 if dev_uuid not in target[param]:
1408 if dev_type == 'vbd' and 'bootable' not in dev_info:
1409 # Compat hack -- mark first disk bootable
1410 dev_info['bootable'] = int(not target[param])
1411 target[param].append(dev_uuid)
1412 elif dev_type == 'tap' or dev_type == 'tap2':
1413 if 'vbd_refs' not in target:
1414 target['vbd_refs'] = []
1415 if dev_uuid not in target['vbd_refs']:
1416 if 'bootable' not in dev_info:
1417 # Compat hack -- mark first disk bootable
1418 dev_info['bootable'] = int(not target['vbd_refs'])
1419 target['vbd_refs'].append(dev_uuid)
1421 elif dev_type == 'vfb':
1422 # Populate other config with aux data that is associated
1423 # with vfb
1425 other_config = {}
1426 for key in XENAPI_CONSOLE_OTHER_CFG:
1427 if key in dev_info:
1428 other_config[key] = dev_info[key]
1429 target['devices'][dev_uuid][1]['other_config'] = other_config
1432 if 'console_refs' not in target:
1433 target['console_refs'] = []
1435 # Treat VFB devices as console devices so they are found
1436 # through Xen API
1437 if dev_uuid not in target['console_refs']:
1438 target['console_refs'].append(dev_uuid)
1440 # Cope with old-format save files which say under vfb
1441 # (type vfb) rather than (vfb 1)
1442 try:
1443 vfb_type = dev_info['type']
1444 except KeyError:
1445 vfb_type = None
1446 log.debug("iwj dev_type=%s vfb type %s" %
1447 (dev_type, `vfb_type`))
1449 if vfb_type == 'vnc' or vfb_type == 'sdl':
1450 dev_info[vfb_type] = 1
1451 del dev_info['type']
1452 log.debug("iwj dev_type=%s vfb setting dev_info['%s']" %
1453 (dev_type, vfb_type))
1454 # Create serial backends now, the location value is bogus, but does not matter
1455 i=0
1456 chardev=0
1457 if dev_info.get('serial') is not None :
1458 chardev = chardev + 1
1459 if dev_info.get('monitor') is not None :
1460 chardev = chardev + 1
1461 if chardev > 0 :
1462 chardev = chardev + 1
1463 while i < chardev :
1464 cfg = self.console_add('vt100', str(i))
1465 c_uuid = uuid.createString()
1466 target['devices'][c_uuid] = ('console', cfg)
1467 target['console_refs'].append(c_uuid)
1468 i = i + 1
1469 elif dev_type == 'console':
1470 if 'console_refs' not in target:
1471 target['console_refs'] = []
1472 if dev_uuid not in target['console_refs']:
1473 target['console_refs'].append(dev_uuid)
1475 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
1476 return dev_uuid
1478 if cfg_xenapi:
1479 dev_info = {}
1480 dev_uuid = ''
1481 if dev_type == 'vif':
1482 dev_info['mac'] = cfg_xenapi.get('MAC')
1483 if not dev_info['mac']:
1484 dev_info['mac'] = randomMAC()
1485 # vifname is the name on the guest, not dom0
1486 # TODO: we don't have the ability to find that out or
1487 # change it from dom0
1488 #if cfg_xenapi.get('device'): # don't add if blank
1489 # dev_info['vifname'] = cfg_xenapi.get('device')
1490 if cfg_xenapi.get('type'):
1491 dev_info['type'] = cfg_xenapi.get('type')
1492 if cfg_xenapi.get('name'):
1493 dev_info['name'] = cfg_xenapi.get('name')
1494 if cfg_xenapi.get('network'):
1495 network = XendAPIStore.get(
1496 cfg_xenapi.get('network'), 'network')
1497 dev_info['bridge'] = network.get_name_label()
1499 if cfg_xenapi.get('security_label'):
1500 dev_info['security_label'] = \
1501 cfg_xenapi.get('security_label')
1503 dev_uuid = cfg_xenapi.get('uuid', None)
1504 if not dev_uuid:
1505 dev_uuid = uuid.createString()
1506 dev_info['uuid'] = dev_uuid
1507 target['devices'][dev_uuid] = (dev_type, dev_info)
1508 target['vif_refs'].append(dev_uuid)
1510 elif dev_type in ('vbd', 'tap', 'tap2'):
1511 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1512 if dev_info['type'] == 'CD':
1513 old_vbd_type = 'cdrom'
1514 else:
1515 old_vbd_type = 'disk'
1517 dev_info['uname'] = cfg_xenapi.get('image', '')
1518 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1519 old_vbd_type)
1520 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1521 dev_info['driver'] = cfg_xenapi.get('driver', '')
1522 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1524 if cfg_xenapi.get('mode') == 'RW':
1525 dev_info['mode'] = 'w'
1526 else:
1527 dev_info['mode'] = 'r'
1529 dev_uuid = cfg_xenapi.get('uuid', None)
1530 if not dev_uuid:
1531 dev_uuid = uuid.createString()
1532 dev_info['uuid'] = dev_uuid
1533 target['devices'][dev_uuid] = (dev_type, dev_info)
1534 target['vbd_refs'].append(dev_uuid)
1536 elif dev_type == 'vtpm':
1537 if cfg_xenapi.get('type'):
1538 dev_info['type'] = cfg_xenapi.get('type')
1540 dev_uuid = cfg_xenapi.get('uuid', None)
1541 if not dev_uuid:
1542 dev_uuid = uuid.createString()
1543 dev_info['uuid'] = dev_uuid
1544 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1545 target['devices'][dev_uuid] = (dev_type, dev_info)
1546 target['vtpm_refs'].append(dev_uuid)
1548 elif dev_type == 'console':
1549 dev_uuid = cfg_xenapi.get('uuid', None)
1550 if not dev_uuid:
1551 dev_uuid = uuid.createString()
1552 dev_info['uuid'] = dev_uuid
1553 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1554 console_other_config = cfg_xenapi.get('other_config', {})
1555 dev_info['other_config'] = console_other_config
1556 if dev_info['protocol'] == 'rfb':
1557 # collapse other config into devinfo for things
1558 # such as vncpasswd, vncunused, etc.
1559 dev_info.update(console_other_config)
1560 dev_info['vnc'] = console_other_config.get('vnc', '0')
1561 dev_info['sdl'] = console_other_config.get('sdl', '0')
1562 target['devices'][dev_uuid] = ('vfb', dev_info)
1563 target['console_refs'].append(dev_uuid)
1565 # if console is rfb, set device_model ensuring qemu
1566 # is invoked for pvfb services
1567 if 'device_model' not in target['platform']:
1568 target['platform']['device_model'] = \
1569 auxbin.pathTo("qemu-dm")
1571 # Finally, if we are a pvfb, we need to make a vkbd
1572 # as well that is not really exposed to Xen API
1573 vkbd_uuid = uuid.createString()
1574 target['devices'][vkbd_uuid] = ('vkbd', {})
1576 elif dev_info['protocol'] == 'vt100':
1577 # if someone tries to create a VT100 console
1578 # via the Xen API, we'll have to ignore it
1579 # because we create one automatically in
1580 # XendDomainInfo._update_consoles
1581 raise XendConfigError('Creating vt100 consoles via '
1582 'Xen API is unsupported')
1584 return dev_uuid
1586 # no valid device to add
1587 return ''
1589 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1590 target = None):
1591 """Add a phantom tap device configuration in XenAPI struct format.
1592 """
1594 if target == None:
1595 target = self
1597 if dev_type not in XendDevices.valid_devices() and \
1598 dev_type not in XendDevices.pseudo_devices():
1599 raise XendConfigError("XendConfig: %s not a valid device type" %
1600 dev_type)
1602 if cfg_xenapi == None:
1603 raise XendConfigError("XendConfig: device_add requires some "
1604 "config.")
1606 if cfg_xenapi:
1607 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1609 if cfg_xenapi:
1610 dev_info = {}
1611 if dev_type in ('vbd', 'tap'):
1612 if dev_type == 'vbd':
1613 dev_info['uname'] = cfg_xenapi.get('image', '')
1614 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1615 elif dev_type == 'tap':
1616 if cfg_xenapi.get('image').find('tap:') == -1:
1617 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1618 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1619 dev_info['uname'] = cfg_xenapi.get('image')
1620 dev_info['mode'] = cfg_xenapi.get('mode')
1621 dev_info['backend'] = '0'
1622 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1623 dev_info['uuid'] = dev_uuid
1624 self['devices'][dev_uuid] = (dev_type, dev_info)
1625 self['vbd_refs'].append(dev_uuid)
1626 return dev_uuid
1628 return ''
1630 def vscsi_convert_sxp_to_dict(self, dev_sxp):
1631 """Convert vscsi device sxp to dict
1632 @param dev_sxp: device configuration
1633 @type dev_sxp: SXP object (parsed config)
1634 @return: dev_config
1635 @rtype: dictionary
1636 """
1637 # Parsing the device SXP's. In most cases, the SXP looks
1638 # like this:
1640 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
1642 # However, for SCSI devices it looks like this:
1644 # [device,
1645 # [vscsi,
1646 # [feature-host, 0],
1647 # [backend, 0],
1648 # [dev,
1649 # [devid, 0], [p-devname, sdb], [p-dev, 1:0:0:1],
1650 # [v-dev, 0:0:0:0], [state, 1]
1651 # ],
1652 # [dev,
1653 # [devid, 0], [p-devname, sdc], [p-dev, 1:0:0:2],
1654 # [v-dev, 0:0:0:1], [satet, 1]
1655 # ]
1656 # ],
1657 # [vscsi,
1658 # [feature-host, 1],
1659 # [backend, 0],
1660 # [dev,
1661 # [devid, 1], [p-devname, sdg], [p-dev, 2:0:0:0],
1662 # [v-dev, 1:0:0:0], [state, 1]
1663 # ],
1664 # [dev,
1665 # [devid, 1], [p-devname, sdh], [p-dev, 2:0:0:1],
1666 # [v-dev, 1:0:0:1], [satet, 1]
1667 # ]
1668 # ]
1669 # ]
1671 # It seems the reasoning for this difference is because
1672 # vscsiif.py needs all the SCSI device configurations with
1673 # same host number at the same time when creating the devices.
1675 # For SCSI device hotplug support, the SXP of SCSI devices is
1676 # extendend like this:
1678 # [device,
1679 # [vscsi,
1680 # [feature-host, 0],
1681 # [backend, 0],
1682 # [dev,
1683 # [devid, 0], [p-devname, sdd], [p-dev, 1:0:0:3],
1684 # [v-dev, 0:0:0:2], [state, 1]
1685 # ]
1686 # ]
1687 # ]
1689 # state xenbusState['Initialising'] indicates that the device is
1690 # being attached, while state xenbusState['Closing'] indicates
1691 # that the device is being detached.
1693 # The Dict looks like this:
1695 # { devs: [ {devid: 0, p-devname: sdd, p-dev: 1:0:0:3,
1696 # v-dev: 0:0:0:2, state: 1} ],
1697 # feature-host: 1 , backend: 0 }
1699 dev_config = {}
1701 vscsi_devs = []
1702 for vscsi_dev in sxp.children(dev_sxp, 'dev'):
1703 vscsi_dev_info = {}
1704 for opt_val in vscsi_dev[1:]:
1705 try:
1706 opt, val = opt_val
1707 vscsi_dev_info[opt] = val
1708 except TypeError:
1709 pass
1710 # append uuid for each vscsi device.
1711 vscsi_uuid = vscsi_dev_info.get('uuid', uuid.createString())
1712 vscsi_dev_info['uuid'] = vscsi_uuid
1713 vscsi_devs.append(vscsi_dev_info)
1714 dev_config['devs'] = vscsi_devs
1716 vscsi_mode = sxp.children(dev_sxp, 'feature-host')[0]
1717 dev_config['feature-host'] = vscsi_mode[1]
1718 try:
1719 vscsi_be = sxp.children(dev_sxp, 'backend')[0]
1720 dev_config['backend'] = vscsi_be[1]
1721 except IndexError:
1722 pass
1724 return dev_config
1726 def console_add(self, protocol, location, other_config = {}):
1727 dev_uuid = uuid.createString()
1728 if protocol == 'vt100':
1729 dev_info = {
1730 'uuid': dev_uuid,
1731 'protocol': protocol,
1732 'location': location,
1733 'other_config': other_config,
1736 if 'devices' not in self:
1737 self['devices'] = {}
1739 self['devices'][dev_uuid] = ('console', dev_info)
1740 self['console_refs'].append(dev_uuid)
1741 return dev_info
1743 return {}
1745 def console_update(self, console_uuid, key, value):
1746 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1747 if dev_uuid == console_uuid:
1748 dev_info[key] = value
1749 # collapse other_config into dev_info for things
1750 # such as vncpasswd, vncunused, etc.
1751 if key == 'other_config':
1752 for k in XENAPI_CONSOLE_OTHER_CFG:
1753 if k in dev_info and k not in value:
1754 del dev_info[k]
1755 dev_info.update(value)
1756 break
1758 def console_get_all(self, protocol):
1759 if protocol == 'vt100':
1760 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1761 if dtype == 'console']
1762 return [c for c in consoles if c.get('protocol') == protocol]
1764 elif protocol == 'rfb':
1765 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1766 if dtype == 'vfb']
1768 # move all non-console key values to other_config before
1769 # returning console config
1770 valid_keys = ['uuid', 'location']
1771 for vfb in vfbs:
1772 other_config = {}
1773 for key, val in vfb.items():
1774 if key not in valid_keys:
1775 other_config[key] = vfb[key]
1776 del vfb[key]
1777 vfb['other_config'] = other_config
1778 vfb['protocol'] = 'rfb'
1780 return vfbs
1782 else:
1783 return []
1785 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1786 """Update an existing device with the new configuration.
1788 @rtype: boolean
1789 @return: Returns True if succesfully found and updated a device conf
1790 """
1791 if dev_uuid in self['devices'] and cfg_sxp:
1792 if sxp.child0(cfg_sxp) == 'device':
1793 config = sxp.child0(cfg_sxp)
1794 else:
1795 config = cfg_sxp
1797 dev_type, dev_info = self['devices'][dev_uuid]
1799 if dev_type == 'pci': # Special case for pci
1800 pci_dict = pci_convert_sxp_to_dict(config)
1801 pci_devs = pci_dict['devs']
1803 # destroy existing XenAPI DPCI objects
1804 for dpci_uuid in XendDPCI.get_by_VM(self['uuid']):
1805 XendAPIStore.deregister(dpci_uuid, "DPCI")
1807 # create XenAPI DPCI objects.
1808 self.create_dpci_from_sxp(pci_devs)
1810 self['devices'][dev_uuid] = (dev_type,
1811 {'devs': pci_devs,
1812 'uuid': dev_uuid})
1813 return True
1815 if dev_type == 'vscsi': # Special case for vscsi
1816 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1817 vscsi_devs = vscsi_dict['devs']
1818 vscsi_mode = vscsi_dict['feature-host']
1819 vscsi_be = vscsi_dict.get('backend', None)
1821 # destroy existing XenAPI DSCSI objects
1822 vscsi_devid = int(dev_info['devs'][0]['devid'])
1823 for dscsi_uuid in XendDSCSI.get_by_VM(self['uuid']):
1824 dscsi_inst = XendAPIStore.get(dscsi_uuid, 'DSCSI')
1825 if vscsi_devid == dscsi_inst.get_virtual_host():
1826 XendAPIStore.deregister(dscsi_uuid, "DSCSI")
1828 # create XenAPI DSCSI objects.
1829 for vscsi_dev in vscsi_devs:
1830 dscsi_uuid = vscsi_dev.get('uuid')
1831 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1832 if pscsi_uuid is None:
1833 continue
1834 dscsi_record = {
1835 'VM': self['uuid'],
1836 'PSCSI': pscsi_uuid,
1837 'virtual_HCTL': vscsi_dev.get('v-dev')
1839 XendDSCSI(dscsi_uuid, dscsi_record)
1841 vscsi_info = {
1842 'devs': vscsi_devs,
1843 'feature-host': vscsi_mode,
1844 'uuid': dev_uuid
1846 if vscsi_be is not None:
1847 vscsi_info['backend'] = vscsi_be
1848 self['devices'][dev_uuid] = (dev_type, vscsi_info)
1849 return True
1851 for opt_val in config[1:]:
1852 try:
1853 opt, val = opt_val
1854 dev_info[opt] = val
1855 except (TypeError, ValueError):
1856 pass # no value for this config option
1858 self['devices'][dev_uuid] = (dev_type, dev_info)
1859 return True
1861 elif dev_uuid in self['devices'] and cfg_xenapi:
1862 dev_type, dev_info = self['devices'][dev_uuid]
1863 for key, val in cfg_xenapi.items():
1864 dev_info[key] = val
1865 self['devices'][dev_uuid] = (dev_type, dev_info)
1866 return True
1868 return False
1871 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None, target = None):
1872 """Get Device SXPR by either giving the device UUID or (type, config).
1874 @rtype: list of lists
1875 @return: device config sxpr
1876 """
1877 sxpr = []
1879 if target == None:
1880 target = self
1882 if dev_uuid != None and dev_uuid in target['devices']:
1883 dev_type, dev_info = target['devices'][dev_uuid]
1885 if dev_type == None or dev_info == None:
1886 raise XendConfigError("Required either UUID or device type and "
1887 "configuration dictionary.")
1889 sxpr.append(dev_type)
1890 if dev_type in ('console', 'vfb'):
1891 config = [(opt, val) for opt, val in dev_info.items()
1892 if opt != 'other_config']
1893 else:
1894 config = [(opt, val) for opt, val in dev_info.items()]
1896 sxpr += config
1898 return sxpr
1900 def ordered_device_refs(self, target = None):
1901 result = []
1903 if target == None:
1904 target = self
1906 # vkbd devices *must* be before vfb devices, otherwise
1907 # there is a race condition when setting up devices
1908 # where the daemon spawned for the vfb may write stuff
1909 # into xenstore vkbd backend, before DevController has
1910 # setup permissions on the vkbd backend path. This race
1911 # results in domain creation failing with 'device already
1912 # connected' messages
1913 result.extend([u for u in target['devices'].keys() if target['devices'][u][0] == 'vkbd'])
1915 result.extend(target.get('console_refs', []) +
1916 target.get('vbd_refs', []) +
1917 target.get('vif_refs', []) +
1918 target.get('vtpm_refs', []))
1920 result.extend([u for u in target['devices'].keys() if u not in result])
1921 return result
1923 def all_devices_sxpr(self, target = None):
1924 """Returns the SXPR for all devices in the current configuration."""
1925 sxprs = []
1927 if target == None:
1928 target = self
1930 if 'devices' not in target:
1931 return sxprs
1933 ordered_refs = self.ordered_device_refs(target = target)
1934 for dev_uuid in ordered_refs:
1935 dev_type, dev_info = target['devices'][dev_uuid]
1936 if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
1937 if dev_type == 'pci':
1938 sxpr = ['pci', ['uuid', dev_info['uuid']]]
1939 elif dev_type == 'vscsi':
1940 sxpr = ['vscsi', ['uuid', dev_info['uuid']],
1941 ['feature-host', dev_info['feature-host']]]
1942 if dev_info.has_key('backend'):
1943 sxpr.append(['backend', dev_info['backend']])
1944 for pci_dev_info in dev_info['devs']:
1945 sxpr.append(dev_dict_to_sxp(pci_dev_info))
1946 sxprs.append((dev_type, sxpr))
1947 else:
1948 sxpr = self.device_sxpr(dev_type = dev_type,
1949 dev_info = dev_info,
1950 target = target)
1951 sxprs.append((dev_type, sxpr))
1953 return sxprs
1955 def image_sxpr(self):
1956 """Returns a backwards compatible image SXP expression that is
1957 used in xenstore's /vm/<uuid>/image value and xm list."""
1958 image = [self.image_type()]
1959 if self.has_key('PV_kernel'):
1960 image.append(['kernel', self['PV_kernel']])
1961 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
1962 image.append(['ramdisk', self['PV_ramdisk']])
1963 if self.has_key('PV_args') and self['PV_args']:
1964 image.append(['args', self['PV_args']])
1965 if self.has_key('superpages'):
1966 image.append(['superpages', self['superpages']])
1968 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
1969 if key in self['platform']:
1970 image.append([key, self['platform'][key]])
1972 if 'notes' in self:
1973 image.append(self.notes_sxp(self['notes']))
1975 return image
1977 def update_with_image_sxp(self, image_sxp, bootloader = False):
1978 # Convert Legacy "image" config to Xen API PV_*
1979 # configuration
1980 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
1982 # user-specified args must come last: previous releases did this and
1983 # some domU kernels rely upon the ordering.
1984 kernel_args = sxp.child_value(image_sxp, 'args', '')
1986 # attempt to extract extra arguments from SXP config
1987 arg_ip = sxp.child_value(image_sxp, 'ip')
1988 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
1989 kernel_args = 'ip=%s ' % arg_ip + kernel_args
1990 arg_root = sxp.child_value(image_sxp, 'root')
1991 if arg_root and not re.search(r'root=', kernel_args):
1992 kernel_args = 'root=%s ' % arg_root + kernel_args
1994 if bootloader:
1995 self['_temp_using_bootloader'] = '1'
1996 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
1997 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
1998 self['_temp_args'] = kernel_args
1999 else:
2000 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
2001 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
2002 self['PV_args'] = kernel_args
2004 self['superpages'] = sxp.child_value(image_sxp, 'superpages',0)
2006 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
2007 val = sxp.child_value(image_sxp, key, None)
2008 if val is not None and val != '':
2009 self['platform'][key] = val
2011 notes = sxp.children(image_sxp, 'notes')
2012 if notes:
2013 self['notes'] = self.notes_from_sxp(notes[0])
2015 self._hvm_boot_params_from_sxp(image_sxp)
2017 def set_notes(self, notes):
2018 'Add parsed elfnotes to image'
2019 self['notes'] = notes
2021 def get_notes(self):
2022 try:
2023 return self['notes'] or {}
2024 except KeyError:
2025 return {}
2027 def notes_from_sxp(self, nsxp):
2028 notes = {}
2029 for note in sxp.children(nsxp):
2030 notes[note[0]] = note[1]
2031 return notes
2033 def notes_sxp(self, notes):
2034 nsxp = ['notes']
2035 for k, v in notes.iteritems():
2036 nsxp.append([k, str(v)])
2037 return nsxp
2039 def _hvm_boot_params_from_sxp(self, image_sxp):
2040 boot = sxp.child_value(image_sxp, 'boot', None)
2041 if boot is not None:
2042 self['HVM_boot_policy'] = 'BIOS order'
2043 self['HVM_boot_params'] = { 'order' : boot }
2045 def is_hvm(self):
2046 return self['HVM_boot_policy'] != ''
2048 def target(self):
2049 return self['target']
2051 def image_type(self):
2052 stored_type = self['platform'].get('image_type')
2053 return stored_type or (self.is_hvm() and 'hvm' or 'linux')
2055 def is_hap(self):
2056 return self['platform'].get('hap', 0)
2058 def update_platform_pci(self):
2059 if not self.is_hvm():
2060 return
2062 pci = []
2063 for dev_type, dev_info in self.all_devices_sxpr():
2064 if dev_type != 'pci':
2065 continue
2066 for dev in sxp.children(dev_info, 'dev'):
2067 domain = sxp.child_value(dev, 'domain')
2068 bus = sxp.child_value(dev, 'bus')
2069 slot = sxp.child_value(dev, 'slot')
2070 func = sxp.child_value(dev, 'func')
2071 vdevfn = sxp.child_value(dev, 'vdevfn')
2072 opts = pci_opts_list_from_sxp(dev)
2073 pci.append([domain, bus, slot, func, vdevfn, opts])
2074 self['platform']['pci'] = pci