ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 19683:d02c3b25c7c0

Revert 19657:9ff5c79b0ceb

Breaks automated localhost migration tests:
for xx in x:
TypeError: iteration over non-sequence

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat May 30 13:21:08 2009 +0100 (2009-05-30)
parents ec2bc4b9fa32
children ffcc665158ae
line source
1 #===========================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2006-2007 XenSource Ltd
16 #============================================================================
18 import logging
19 import re
20 import time
21 import types
23 from xen.xend import sxp
24 from xen.xend import uuid
25 from xen.xend import XendOptions
26 from xen.xend import XendAPIStore
27 from xen.xend.XendPPCI import XendPPCI
28 from xen.xend.XendDPCI import XendDPCI
29 from xen.xend.XendPSCSI import XendPSCSI
30 from xen.xend.XendDSCSI import XendDSCSI
31 from xen.xend.XendError import VmError
32 from xen.xend.XendDevices import XendDevices
33 from xen.xend.PrettyPrint import prettyprintstring
34 from xen.xend.XendConstants import DOM_STATE_HALTED
35 from xen.xend.xenstore.xstransact import xstransact
36 from xen.xend.server.BlktapController import blktap_disk_types
37 from xen.xend.server.netif import randomMAC
38 from xen.util.blkif import blkdev_name_to_number, blkdev_uname_to_file
39 from xen.util.pci import assigned_or_requested_vslot
40 from xen.util import xsconstants
41 import xen.util.auxbin
43 log = logging.getLogger("xend.XendConfig")
44 log.setLevel(logging.WARN)
47 """
48 XendConfig API
50 XendConfig will try to mirror as closely the Xen API VM Struct
51 with extra parameters for those options that are not supported.
53 """
55 def reverse_dict(adict):
56 """Return the reverse mapping of a dictionary."""
57 return dict([(v, k) for k, v in adict.items()])
59 def bool0(v):
60 return v != '0' and v != 'False' and bool(v)
62 # Recursively copy a data struct, scrubbing out VNC passwords.
63 # Will scrub any dict entry with a key of 'vncpasswd' or any
64 # 2-element list whose first member is 'vncpasswd'. It will
65 # also scrub a string matching '(vncpasswd XYZ)'. Everything
66 # else is no-op passthrough
67 def scrub_password(data):
68 if type(data) == dict or type(data) == XendConfig:
69 scrubbed = {}
70 for key in data.keys():
71 if key == "vncpasswd":
72 scrubbed[key] = "XXXXXXXX"
73 else:
74 scrubbed[key] = scrub_password(data[key])
75 return scrubbed
76 elif type(data) == list:
77 if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd':
78 return ['vncpasswd', 'XXXXXXXX']
79 else:
80 scrubbed = []
81 for entry in data:
82 scrubbed.append(scrub_password(entry))
83 return scrubbed
84 elif type(data) == tuple:
85 scrubbed = []
86 for entry in data:
87 scrubbed.append(scrub_password(entry))
88 return tuple(scrubbed)
89 elif type(data) == str:
90 return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data)
91 else:
92 return data
94 #
95 # CPU fields:
96 #
97 # VCPUs_max -- the maximum number of vcpus that this domain may ever have.
98 # aka XendDomainInfo.getVCpuCount().
99 # vcpus -- the legacy configuration name for above.
100 # max_vcpu_id -- vcpus_number - 1. This is given to us by Xen.
101 #
102 # cpus -- the list of pCPUs available to each vCPU.
103 #
104 # vcpu_avail -- a bitmap telling the guest domain whether it may use each of
105 # its VCPUs. This is translated to
106 # <dompath>/cpu/<id>/availability = {online,offline} for use
107 # by the guest domain.
108 # VCPUs_live -- the number of VCPUs currently up, as reported by Xen. This
109 # is changed by changing vcpu_avail, and waiting for the
110 # domain to respond.
111 #
114 # Mapping from XendConfig configuration keys to the old
115 # legacy configuration keys that map directly.
117 XENAPI_CFG_TO_LEGACY_CFG = {
118 'uuid': 'uuid',
119 'VCPUs_max': 'vcpus',
120 'cpus': 'cpus',
121 'name_label': 'name',
122 'actions_after_shutdown': 'on_poweroff',
123 'actions_after_reboot': 'on_reboot',
124 'actions_after_crash': 'on_crash',
125 'PV_bootloader': 'bootloader',
126 'PV_bootloader_args': 'bootloader_args',
127 }
129 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
131 # Platform configuration keys and their types.
132 XENAPI_PLATFORM_CFG_TYPES = {
133 'acpi': int,
134 'apic': int,
135 'boot': str,
136 'device_model': str,
137 'loader': str,
138 'display' : str,
139 'fda': str,
140 'fdb': str,
141 'keymap': str,
142 'isa' : int,
143 'localtime': int,
144 'monitor': int,
145 'nographic': int,
146 'pae' : int,
147 'rtc_timeoffset': int,
148 'serial': str,
149 'sdl': int,
150 'opengl': int,
151 'soundhw': str,
152 'stdvga': int,
153 'videoram': int,
154 'usb': int,
155 'usbdevice': str,
156 'hpet': int,
157 'vnc': int,
158 'vncconsole': int,
159 'vncdisplay': int,
160 'vnclisten': str,
161 'timer_mode': int,
162 'vpt_align': int,
163 'viridian': int,
164 'vncpasswd': str,
165 'vncunused': int,
166 'xauthority': str,
167 'pci': str,
168 'vhpt': int,
169 'guest_os_type': str,
170 'hap': int,
171 'xen_extended_power_mgmt': int,
172 'pci_msitranslate': int,
173 'pci_power_mgmt': int,
174 'xen_platform_pci': int,
175 }
177 # Xen API console 'other_config' keys.
178 XENAPI_CONSOLE_OTHER_CFG = ['vncunused', 'vncdisplay', 'vnclisten',
179 'vncpasswd', 'sdl', 'vnc', 'display', 'xauthority',
180 'keymap', 'opengl']
182 # List of XendConfig configuration keys that have no direct equivalent
183 # in the old world.
185 XENAPI_CFG_TYPES = {
186 'uuid': str,
187 'name_label': str,
188 'name_description': str,
189 'user_version': str,
190 'is_a_template': bool0,
191 'auto_power_on': bool0,
192 'resident_on': str,
193 'memory_static_min': int, # note these are stored in bytes, not KB!
194 'memory_static_max': int,
195 'memory_dynamic_min': int,
196 'memory_dynamic_max': int,
197 'cpus': list,
198 'vcpus_params': dict,
199 'VCPUs_max': int,
200 'VCPUs_at_startup': int,
201 'VCPUs_live': int,
202 'actions_after_shutdown': str,
203 'actions_after_reboot': str,
204 'actions_after_crash': str,
205 'PV_bootloader': str,
206 'PV_kernel': str,
207 'PV_ramdisk': str,
208 'PV_args': str,
209 'PV_bootloader_args': str,
210 'HVM_boot_policy': str,
211 'HVM_boot_params': dict,
212 'PCI_bus': str,
213 'platform': dict,
214 'tools_version': dict,
215 'other_config': dict,
216 'target': int,
217 'security_label': str,
218 'pci': str,
219 'cpuid' : dict,
220 'cpuid_check' : dict,
221 'machine_address_size': int,
222 'suppress_spurious_page_faults': bool0,
223 's3_integrity' : int,
224 'superpages' : int,
225 }
227 # List of legacy configuration keys that have no equivalent in the
228 # Xen API, but are still stored in XendConfig.
230 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
231 # roundtripped (dynamic, unmodified)
232 'shadow_memory',
233 'vcpu_avail',
234 'features',
235 # read/write
236 'on_xend_start',
237 'on_xend_stop',
238 # read-only
239 'domid',
240 'start_time',
241 'cpu_time',
242 'online_vcpus',
243 # write-once
244 'cpu',
245 'cpus',
246 ]
248 LEGACY_CFG_TYPES = {
249 'uuid': str,
250 'name': str,
251 'vcpus': int,
252 'vcpu_avail': long,
253 'memory': int,
254 'shadow_memory': int,
255 'maxmem': int,
256 'start_time': float,
257 'cpu_time': float,
258 'features': str,
259 'localtime': int,
260 'name': str,
261 'on_poweroff': str,
262 'on_reboot': str,
263 'on_crash': str,
264 'on_xend_stop': str,
265 'on_xend_start': str,
266 'online_vcpus': int,
267 'rtc/timeoffset': str,
268 'bootloader': str,
269 'bootloader_args': str,
270 }
272 # Values that should be stored in xenstore's /vm/<uuid> that is used
273 # by Xend. Used in XendDomainInfo to restore running VM state from
274 # xenstore.
275 LEGACY_XENSTORE_VM_PARAMS = [
276 'uuid',
277 'name',
278 'vcpus',
279 'vcpu_avail',
280 'memory',
281 'shadow_memory',
282 'maxmem',
283 'start_time',
284 'name',
285 'on_poweroff',
286 'on_crash',
287 'on_reboot',
288 'on_xend_start',
289 'on_xend_stop',
290 'bootloader',
291 'bootloader_args',
292 ]
294 ##
295 ## Config Choices
296 ##
298 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart',
299 'coredump-destroy', 'coredump-restart')
300 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
301 'crashed', 'dying')
303 class XendConfigError(VmError):
304 def __str__(self):
305 return 'Invalid Configuration: %s' % str(self.value)
307 ##
308 ## XendConfig Class (an extended dictionary)
309 ##
311 class XendConfig(dict):
312 """ The new Xend VM Configuration.
314 Stores the configuration in xenapi compatible format but retains
315 import and export functions for SXP.
316 """
317 def __init__(self, filename = None, sxp_obj = None,
318 xapi = None, dominfo = None):
320 dict.__init__(self)
321 self.update(self._defaults())
323 if filename:
324 try:
325 sxp_obj = sxp.parse(open(filename,'r'))
326 sxp_obj = sxp_obj[0]
327 except IOError, e:
328 raise XendConfigError("Unable to read file: %s" % filename)
330 if sxp_obj:
331 self._sxp_to_xapi(sxp_obj)
332 self._sxp_to_xapi_unsupported(sxp_obj)
333 elif xapi:
334 self.update_with_xenapi_config(xapi)
335 elif dominfo:
336 # output from xc.domain_getinfo
337 self._dominfo_to_xapi(dominfo, update_mem = True)
339 log.debug('XendConfig.init: %s' % scrub_password(self))
341 # validators go here
342 self.validate()
344 """ In time, we should enable this type checking addition. It is great
345 also for tracking bugs and unintended writes to XendDomainInfo.info
346 def __setitem__(self, key, value):
347 type_conv = XENAPI_CFG_TYPES.get(key)
348 if callable(type_conv):
349 try:
350 dict.__setitem__(self, key, type_conv(value))
351 except (ValueError, TypeError):
352 raise XendConfigError("Wrong type for configuration value " +
353 "%s. Expected %s" %
354 (key, type_conv.__name__))
355 else:
356 dict.__setitem__(self, key, value)
357 """
359 def _defaults(self):
360 defaults = {
361 'name_label': 'Domain-Unnamed',
362 'actions_after_shutdown': 'destroy',
363 'actions_after_reboot': 'restart',
364 'actions_after_crash': 'restart',
365 'actions_after_suspend': '',
366 'is_a_template': False,
367 'auto_power_on': False,
368 'is_control_domain': False,
369 'features': '',
370 'PV_bootloader': '',
371 'PV_kernel': '',
372 'PV_ramdisk': '',
373 'PV_args': '',
374 'PV_bootloader_args': '',
375 'HVM_boot_policy': '',
376 'HVM_boot_params': {},
377 'memory_static_min': 0,
378 'memory_dynamic_min': 0,
379 'shadow_memory': 0,
380 'memory_static_max': 0,
381 'memory_dynamic_max': 0,
382 'devices': {},
383 'on_xend_start': 'ignore',
384 'on_xend_stop': 'ignore',
385 'cpus': [],
386 'VCPUs_max': 1,
387 'VCPUs_live': 1,
388 'VCPUs_at_startup': 1,
389 'vcpus_params': {},
390 'console_refs': [],
391 'vif_refs': [],
392 'vbd_refs': [],
393 'vtpm_refs': [],
394 'other_config': {},
395 'platform': {},
396 'target': 0,
397 'superpages': 0,
398 }
400 return defaults
402 #
403 # Here we assume these values exist in the dict.
404 # If they don't we have a bigger problem, lets not
405 # try and 'fix it up' but acutually fix the cause ;-)
406 #
407 def _memory_sanity_check(self):
408 log.trace("_memory_sanity_check memory_static_min: %s, "
409 "memory_static_max: %i, "
410 "memory_dynamic_min: %i, "
411 "memory_dynamic_max: %i",
412 self["memory_static_min"],
413 self["memory_static_max"],
414 self["memory_dynamic_min"],
415 self["memory_dynamic_max"])
417 if not self["memory_static_min"] <= self["memory_static_max"]:
418 raise XendConfigError("memory_static_min must be less " \
419 "than or equal to memory_static_max")
420 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
421 raise XendConfigError("memory_static_min must be less " \
422 "than or equal to memory_dynamic_min")
423 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
424 raise XendConfigError("memory_dynamic_max must be less " \
425 "than or equal to memory_static_max")
426 if not self["memory_dynamic_max"] > 0:
427 raise XendConfigError("memory_dynamic_max must be greater " \
428 "than zero")
429 if not self["memory_static_max"] > 0:
430 raise XendConfigError("memory_static_max must be greater " \
431 "than zero")
433 def _actions_sanity_check(self):
434 for event in ['shutdown', 'reboot', 'crash']:
435 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
436 raise XendConfigError('Invalid event handling mode: ' +
437 event)
439 def _vcpus_sanity_check(self):
440 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
441 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
442 if 'online_vcpus' in self:
443 self['VCPUs_live'] = self['online_vcpus']
445 def _uuid_sanity_check(self):
446 """Make sure UUID is in proper string format with hyphens."""
447 if 'uuid' not in self or not self['uuid']:
448 self['uuid'] = uuid.createString()
449 else:
450 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
452 def _name_sanity_check(self):
453 if 'name_label' not in self:
454 self['name_label'] = 'Domain-' + self['uuid']
456 def _platform_sanity_check(self):
457 if 'keymap' not in self['platform'] and XendOptions.instance().get_keymap():
458 self['platform']['keymap'] = XendOptions.instance().get_keymap()
460 if self.is_hvm() or self.has_rfb():
461 if 'device_model' not in self['platform']:
462 self['platform']['device_model'] = xen.util.auxbin.pathTo("qemu-dm")
464 if self.is_hvm():
465 if 'timer_mode' not in self['platform']:
466 self['platform']['timer_mode'] = 1
467 if 'viridian' not in self['platform']:
468 self['platform']['viridian'] = 0
469 if 'rtc_timeoffset' not in self['platform']:
470 self['platform']['rtc_timeoffset'] = 0
471 if 'hpet' not in self['platform']:
472 self['platform']['hpet'] = 0
473 if 'xen_platform_pci' not in self['platform']:
474 self['platform']['xen_platform_pci'] = 1
475 if 'vpt_align' not in self['platform']:
476 self['platform']['vpt_align'] = 1
477 if 'loader' not in self['platform']:
478 # Old configs may have hvmloader set as PV_kernel param
479 if self.has_key('PV_kernel') and self['PV_kernel'] != '':
480 self['platform']['loader'] = self['PV_kernel']
481 self['PV_kernel'] = ''
482 else:
483 self['platform']['loader'] = "/usr/lib/xen/boot/hvmloader"
484 log.debug("Loader is %s" % str(self['platform']['loader']))
486 # Compatibility hack, can go away soon.
487 if 'soundhw' not in self['platform'] and \
488 self['platform'].get('enable_audio'):
489 self['platform']['soundhw'] = 'sb16'
491 def validate(self):
492 self._uuid_sanity_check()
493 self._name_sanity_check()
494 self._memory_sanity_check()
495 self._actions_sanity_check()
496 self._vcpus_sanity_check()
497 self._platform_sanity_check()
499 def _dominfo_to_xapi(self, dominfo, update_mem = False):
500 self['domid'] = dominfo['domid']
501 self['online_vcpus'] = dominfo['online_vcpus']
502 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
504 if update_mem:
505 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
506 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
507 self['memory_static_min'] = 0
508 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
509 self._memory_sanity_check()
511 self['cpu_time'] = dominfo['cpu_time']/1e9
512 if dominfo.get('ssidref'):
513 ssidref = int(dominfo.get('ssidref'))
514 import xen.util.xsm.xsm as security
515 self['security_label'] = security.ssidref2security_label(ssidref)
517 self['shutdown_reason'] = dominfo['shutdown_reason']
519 # parse state into Xen API states
520 self['running'] = dominfo['running']
521 self['crashed'] = dominfo['crashed']
522 self['dying'] = dominfo['dying']
523 self['shutdown'] = dominfo['shutdown']
524 self['paused'] = dominfo['paused']
525 self['blocked'] = dominfo['blocked']
527 if 'name' in dominfo:
528 self['name_label'] = dominfo['name']
530 if 'handle' in dominfo:
531 self['uuid'] = uuid.toString(dominfo['handle'])
533 def parse_cpuid(self, cfg, field):
534 def int2bin(n, count=32):
535 return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
537 for input, regs in cfg[field].iteritems():
538 if not regs is dict:
539 cfg[field][input] = dict(regs)
541 cpuid = {}
542 for input in cfg[field]:
543 inputs = input.split(',')
544 if inputs[0][0:2] == '0x':
545 inputs[0] = str(int(inputs[0], 16))
546 if len(inputs) == 2:
547 if inputs[1][0:2] == '0x':
548 inputs[1] = str(int(inputs[1], 16))
549 new_input = ','.join(inputs)
550 cpuid[new_input] = {} # new input
551 for reg in cfg[field][input]:
552 val = cfg[field][input][reg]
553 if val[0:2] == '0x':
554 cpuid[new_input][reg] = int2bin(int(val, 16))
555 else:
556 cpuid[new_input][reg] = val
557 cfg[field] = cpuid
559 def _parse_sxp(self, sxp_cfg):
560 """ Populate this XendConfig using the parsed SXP.
562 @param sxp_cfg: Parsed SXP Configuration
563 @type sxp_cfg: list of lists
564 @rtype: dictionary
565 @return: A dictionary containing the parsed options of the SXP.
566 """
567 cfg = {}
569 for key, typ in XENAPI_CFG_TYPES.items():
570 val = sxp.child_value(sxp_cfg, key)
571 if val is not None:
572 try:
573 cfg[key] = typ(val)
574 except (ValueError, TypeError), e:
575 log.warn('Unable to convert type value for key: %s' % key)
577 # Convert deprecated options to current equivalents.
579 restart = sxp.child_value(sxp_cfg, 'restart')
580 if restart:
581 if restart == 'onreboot':
582 cfg['on_poweroff'] = 'destroy'
583 cfg['on_reboot'] = 'restart'
584 cfg['on_crash'] = 'destroy'
585 elif restart == 'always':
586 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
587 cfg[opt] = 'restart'
588 elif restart == 'never':
589 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
590 cfg[opt] = 'never'
591 else:
592 log.warn('Ignoring unrecognised value for deprecated option:'
593 'restart = \'%s\'', restart)
595 # Handle memory, passed in as MiB
597 if sxp.child_value(sxp_cfg, "memory") != None:
598 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
599 if sxp.child_value(sxp_cfg, "maxmem") != None:
600 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
602 # Convert scheduling parameters to vcpus_params
603 if 'vcpus_params' not in cfg:
604 cfg['vcpus_params'] = {}
605 cfg["vcpus_params"]["weight"] = \
606 int(sxp.child_value(sxp_cfg, "cpu_weight", 256))
607 cfg["vcpus_params"]["cap"] = \
608 int(sxp.child_value(sxp_cfg, "cpu_cap", 0))
610 # Only extract options we know about.
611 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG + \
612 XENAPI_CFG_TO_LEGACY_CFG.values()
614 for key in extract_keys:
615 val = sxp.child_value(sxp_cfg, key)
616 if val != None:
617 try:
618 cfg[key] = LEGACY_CFG_TYPES[key](val)
619 except KeyError:
620 cfg[key] = val
621 except (TypeError, ValueError), e:
622 log.warn("Unable to parse key %s: %s: %s" %
623 (key, str(val), e))
625 if 'platform' not in cfg:
626 cfg['platform'] = {}
627 localtime = sxp.child_value(sxp_cfg, 'localtime')
628 if localtime is not None:
629 cfg['platform']['localtime'] = localtime
631 # Compatibility hack -- can go soon.
632 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
633 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
634 if val is not None:
635 self['platform'][key] = val
637 # Compatibility hack -- can go soon.
638 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
639 if boot_order:
640 cfg['HVM_boot_policy'] = 'BIOS order'
641 cfg['HVM_boot_params'] = { 'order' : boot_order }
644 # Parsing the device SXP's.
645 cfg['devices'] = {}
646 for dev in sxp.children(sxp_cfg, 'device'):
647 config = sxp.child0(dev)
648 dev_type = sxp.name(config)
649 self.device_add(dev_type, cfg_sxp = config, target = cfg)
651 # Extract missing data from configuration entries
652 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
653 if image_sxp:
654 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
655 if image_vcpus != None:
656 try:
657 if 'VCPUs_max' not in cfg:
658 cfg['VCPUs_max'] = int(image_vcpus)
659 elif cfg['VCPUs_max'] != int(image_vcpus):
660 cfg['VCPUs_max'] = int(image_vcpus)
661 log.warn('Overriding vcpus from %d to %d using image'
662 'vcpus value.', cfg['VCPUs_max'])
663 except ValueError, e:
664 raise XendConfigError('integer expeceted: %s: %s' %
665 image_sxp, e)
667 # Deprecated cpu configuration
668 if 'cpu' in cfg:
669 if 'cpus' in cfg:
670 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
671 else:
672 cfg['cpus'] = str(cfg['cpu'])
674 # Convert 'cpus' to list of list of ints
675 cpus_list = []
676 if 'cpus' in cfg:
677 # Convert the following string to list of ints.
678 # The string supports a list of ranges (0-3),
679 # seperated by commas, and negation (^1).
680 # Precedence is settled by order of the string:
681 # "0-3,^1" -> [0,2,3]
682 # "0-3,^1,1" -> [0,1,2,3]
683 def cnv(s):
684 l = []
685 for c in s.split(','):
686 if c.find('-') != -1:
687 (x, y) = c.split('-')
688 for i in range(int(x), int(y)+1):
689 l.append(int(i))
690 else:
691 # remove this element from the list
692 if c[0] == '^':
693 l = [x for x in l if x != int(c[1:])]
694 else:
695 l.append(int(c))
696 return l
698 if type(cfg['cpus']) == list:
699 if len(cfg['cpus']) > 0 and type(cfg['cpus'][0]) == list:
700 # If sxp_cfg was created from config.sxp,
701 # the form of 'cpus' is list of list of string.
702 # Convert 'cpus' to list of list of ints.
703 # Conversion examples:
704 # [['1']] -> [[1]]
705 # [['0','2'],['1','3']] -> [[0,2],[1,3]]
706 try:
707 for c1 in cfg['cpus']:
708 cpus = []
709 for c2 in c1:
710 cpus.append(int(c2))
711 cpus_list.append(cpus)
712 except ValueError, e:
713 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
714 else:
715 # Conversion examples:
716 # ["1"] -> [[1]]
717 # ["0,2","1,3"] -> [[0,2],[1,3]]
718 # ["0-3,^1","1-4,^2"] -> [[0,2,3],[1,3,4]]
719 try:
720 for c in cfg['cpus']:
721 cpus = cnv(c)
722 cpus_list.append(cpus)
723 except ValueError, e:
724 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
726 if len(cpus_list) != cfg['vcpus']:
727 raise XendConfigError('vcpus and the item number of cpus are not same')
728 else:
729 # Conversion examples:
730 # vcpus=1:
731 # "1" -> [[1]]
732 # "0-3,^1" -> [[0,2,3]]
733 # vcpus=2:
734 # "1" -> [[1],[1]]
735 # "0-3,^1" -> [[0,2,3],[0,2,3]]
736 try:
737 cpus = cnv(cfg['cpus'])
738 for v in range(0, cfg['vcpus']):
739 cpus_list.append(cpus)
740 except ValueError, e:
741 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
742 else:
743 # Generation examples:
744 # vcpus=1:
745 # -> [[]]
746 # vcpus=2:
747 # -> [[],[]]
748 for v in range(0, cfg['vcpus']):
749 cpus_list.append(list())
751 cfg['cpus'] = cpus_list
753 # Parse cpuid
754 if 'cpuid' in cfg:
755 self.parse_cpuid(cfg, 'cpuid')
756 if 'cpuid_check' in cfg:
757 self.parse_cpuid(cfg, 'cpuid_check')
759 import xen.util.xsm.xsm as security
760 if security.on() == xsconstants.XS_POLICY_USE:
761 from xen.util.acmpolicy import ACM_LABEL_UNLABELED
762 if not 'security' in cfg and sxp.child_value(sxp_cfg, 'security'):
763 cfg['security'] = sxp.child_value(sxp_cfg, 'security')
764 elif not cfg.get('security_label'):
765 cfg['security'] = [['access_control',
766 ['policy', security.get_active_policy_name() ],
767 ['label', ACM_LABEL_UNLABELED ]]]
769 if 'security' in cfg and not cfg.get('security_label'):
770 secinfo = cfg['security']
771 # The xm command sends a list formatted like this:
772 # [['access_control', ['policy', 'xm-test'],['label', 'red']],
773 # ['ssidref', 196611]]
774 policy = ""
775 label = ""
776 for idx in range(0, len(secinfo)):
777 if secinfo[idx][0] == "access_control":
778 for aidx in range(1, len(secinfo[idx])):
779 if secinfo[idx][aidx][0] == "policy":
780 policy = secinfo[idx][aidx][1]
781 if secinfo[idx][aidx][0] == "label":
782 label = secinfo[idx][aidx][1]
783 cfg['security_label'] = \
784 security.set_security_label(policy, label)
785 if not sxp.child_value(sxp_cfg, 'security_label'):
786 del cfg['security']
788 sec_lab = cfg['security_label'].split(":")
789 if len(sec_lab) != 3:
790 raise XendConfigError("Badly formatted security label: %s"
791 % cfg['security_label'])
793 old_state = sxp.child_value(sxp_cfg, 'state')
794 if old_state:
795 for i in range(len(CONFIG_OLD_DOM_STATES)):
796 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
798 return cfg
801 def _sxp_to_xapi(self, sxp_cfg):
802 """Read in an SXP Configuration object and
803 populate at much of the Xen API with valid values.
804 """
805 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
807 # _parse_sxp() below will call device_add() and construct devices.
808 # Some devices may require VM's uuid, so setup self['uuid']
809 # beforehand.
810 self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString())
812 cfg = self._parse_sxp(sxp_cfg)
814 for key, typ in XENAPI_CFG_TYPES.items():
815 val = cfg.get(key)
816 if val is not None:
817 self[key] = typ(val)
819 # Convert parameters that can be directly mapped from
820 # the Legacy Config to Xen API Config
822 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
823 try:
824 type_conv = XENAPI_CFG_TYPES.get(apikey)
825 if callable(type_conv):
826 self[apikey] = type_conv(cfg[cfgkey])
827 else:
828 log.warn("Unconverted key: " + apikey)
829 self[apikey] = cfg[cfgkey]
830 except KeyError:
831 pass
833 # Lets try and handle memory correctly
835 MiB = 1024 * 1024
837 if "memory" in cfg:
838 self["memory_static_min"] = 0
839 self["memory_static_max"] = int(cfg["memory"]) * MiB
840 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
841 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
843 if "maxmem" in cfg:
844 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
846 self._memory_sanity_check()
848 def update_with(n, o):
849 if not self.get(n):
850 self[n] = cfg.get(o, '')
852 update_with('PV_bootloader', 'bootloader')
853 update_with('PV_bootloader_args', 'bootloader_args')
855 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
856 if image_sxp:
857 self.update_with_image_sxp(image_sxp)
859 # Convert Legacy HVM parameters to Xen API configuration
860 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
861 if key in cfg:
862 self['platform'][key] = cfg[key]
864 # set device references in the configuration
865 self['devices'] = cfg.get('devices', {})
866 self['console_refs'] = cfg.get('console_refs', [])
867 self['vif_refs'] = cfg.get('vif_refs', [])
868 self['vbd_refs'] = cfg.get('vbd_refs', [])
869 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
871 # coalesce hvm vnc frame buffer with vfb config
872 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
873 # add vfb device if it isn't there already
874 if not self.has_rfb():
875 dev_config = ['vfb']
876 dev_config.append(['vnc', '1'])
877 # copy VNC related params from platform config to vfb dev conf
878 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
879 'vnclisten']:
880 if key in self['platform']:
881 dev_config.append([key, self['platform'][key]])
883 self.device_add('vfb', cfg_sxp = dev_config)
886 def has_rfb(self):
887 for console_uuid in self['console_refs']:
888 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
889 return True
890 if self['devices'][console_uuid][0] == 'vfb':
891 return True
892 return False
894 def _sxp_to_xapi_unsupported(self, sxp_cfg):
895 """Read in an SXP configuration object and populate
896 values are that not related directly supported in
897 the Xen API.
898 """
900 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
902 # Parse and convert parameters used to configure
903 # the image (as well as HVM images)
904 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
905 if image_sxp:
906 image_type = sxp.name(image_sxp)
907 if image_type != 'hvm' and image_type != 'linux':
908 self['platform']['image_type'] = image_type
910 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
911 val = sxp.child_value(image_sxp, key, None)
912 if val is not None and val != '':
913 self['platform'][key] = val
915 notes = sxp.children(image_sxp, 'notes')
916 if notes:
917 self['notes'] = self.notes_from_sxp(notes[0])
919 self._hvm_boot_params_from_sxp(image_sxp)
921 # extract backend value
923 backend = []
924 for c in sxp.children(sxp_cfg, 'backend'):
925 backend.append(sxp.name(sxp.child0(c)))
926 if backend:
927 self['backend'] = backend
929 # Parse and convert other Non Xen API parameters.
930 def _set_cfg_if_exists(sxp_arg):
931 val = sxp.child_value(sxp_cfg, sxp_arg)
932 if val != None:
933 if LEGACY_CFG_TYPES.get(sxp_arg):
934 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
935 else:
936 self[sxp_arg] = val
938 _set_cfg_if_exists('shadow_memory')
939 _set_cfg_if_exists('features')
940 _set_cfg_if_exists('on_xend_stop')
941 _set_cfg_if_exists('on_xend_start')
942 _set_cfg_if_exists('vcpu_avail')
944 # Parse and store runtime configuration
945 _set_cfg_if_exists('start_time')
946 _set_cfg_if_exists('cpu_time')
947 _set_cfg_if_exists('shutdown_reason')
948 _set_cfg_if_exists('up_time')
949 _set_cfg_if_exists('status') # TODO, deprecated
951 def _get_old_state_string(self):
952 """Returns the old xm state string.
953 @rtype: string
954 @return: old state string
955 """
956 state_string = ''
957 for state_name in CONFIG_OLD_DOM_STATES:
958 on_off = self.get(state_name, 0)
959 if on_off:
960 state_string += state_name[0]
961 else:
962 state_string += '-'
964 return state_string
967 def update_config(self, dominfo):
968 """Update configuration with the output from xc.domain_getinfo().
970 @param dominfo: Domain information via xc.domain_getinfo()
971 @type dominfo: dict
972 """
973 self._dominfo_to_xapi(dominfo)
974 self.validate()
976 def update_with_xenapi_config(self, xapi):
977 """Update configuration with a Xen API VM struct
979 @param xapi: Xen API VM Struct
980 @type xapi: dict
981 """
983 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
985 for key, val in xapi.items():
986 type_conv = XENAPI_CFG_TYPES.get(key)
987 if type_conv is None:
988 key = key.lower()
989 type_conv = XENAPI_CFG_TYPES.get(key)
990 if callable(type_conv):
991 self[key] = type_conv(val)
992 else:
993 self[key] = val
995 # XenAPI defines platform as a string-string map. If platform
996 # configuration exists, convert values to appropriate type.
997 if 'platform' in xapi:
998 for key, val in xapi['platform'].items():
999 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1000 if type_conv is None:
1001 key = key.lower()
1002 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1003 if callable(type_conv):
1004 self['platform'][key] = type_conv(val)
1005 else:
1006 self['platform'][key] = val
1008 self['vcpus_params']['weight'] = \
1009 int(self['vcpus_params'].get('weight', 256))
1010 self['vcpus_params']['cap'] = int(self['vcpus_params'].get('cap', 0))
1012 def cpuid_to_sxp(self, sxpr, field):
1013 regs_list = []
1014 for input, regs in self[field].iteritems():
1015 reg_list = []
1016 for reg, val in regs.iteritems():
1017 reg_list.append([reg, val])
1018 regs_list.append([input, reg_list])
1019 sxpr.append([field, regs_list])
1022 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
1023 legacy_only = True):
1024 """ Get SXP representation of this config object.
1026 Incompat: removed store_mfn, console_mfn
1028 @keyword domain: (optional) XendDomainInfo to get extra information
1029 from such as domid and running devices.
1030 @type domain: XendDomainInfo
1031 @keyword ignore: (optional) list of 'keys' that we do not want
1032 to export.
1033 @type ignore: list of strings
1034 @rtype: list of list (SXP representation)
1035 """
1036 sxpr = ['domain']
1038 # TODO: domid/dom is the same thing but called differently
1039 # depending if it is from xenstore or sxpr.
1041 if domain.getDomid() is not None:
1042 sxpr.append(['domid', domain.getDomid()])
1044 if not legacy_only:
1045 for name, typ in XENAPI_CFG_TYPES.items():
1046 if name in self and self[name] not in (None, []):
1047 if typ == dict:
1048 s = self[name].items()
1049 elif typ == list:
1050 s = self[name]
1051 else:
1052 s = str(self[name])
1053 sxpr.append([name, s])
1055 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
1056 if self.has_key(xenapi) and self[xenapi] not in (None, []):
1057 if type(self[xenapi]) == bool:
1058 # convert booleans to ints before making an sxp item
1059 sxpr.append([legacy, int(self[xenapi])])
1060 else:
1061 sxpr.append([legacy, self[xenapi]])
1063 MiB = 1024*1024
1065 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
1066 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
1068 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
1069 if legacy in ('domid', 'uuid', 'cpus'): # skip these
1070 continue
1071 if self.has_key(legacy) and self[legacy] not in (None, []):
1072 sxpr.append([legacy, self[legacy]])
1074 if self.has_key('security_label'):
1075 sxpr.append(['security_label', self['security_label']])
1077 sxpr.append(['image', self.image_sxpr()])
1078 sxpr.append(['status', domain._stateGet()])
1080 if domain.getDomid() is not None:
1081 sxpr.append(['state', self._get_old_state_string()])
1083 if domain:
1084 if domain.store_mfn:
1085 sxpr.append(['store_mfn', domain.store_mfn])
1086 if domain.console_mfn:
1087 sxpr.append(['console_mfn', domain.console_mfn])
1090 # Marshall devices (running or from configuration)
1091 if not ignore_devices:
1092 txn = xstransact()
1093 try:
1094 for cls in XendDevices.valid_devices():
1095 found = False
1097 # figure if there is a dev controller is valid and running
1098 if domain and domain.getDomid() != None:
1099 try:
1100 controller = domain.getDeviceController(cls)
1101 configs = controller.configurations(txn)
1102 for config in configs:
1103 if sxp.name(config) in ('vbd', 'tap'):
1104 # The bootable flag is never written to the
1105 # store as part of the device config.
1106 dev_uuid = sxp.child_value(config, 'uuid')
1107 dev_type, dev_cfg = self['devices'][dev_uuid]
1108 is_bootable = dev_cfg.get('bootable', 0)
1109 config.append(['bootable', int(is_bootable)])
1110 config.append(['VDI', dev_cfg.get('VDI', '')])
1112 sxpr.append(['device', config])
1114 found = True
1115 except:
1116 log.exception("dumping sxp from device controllers")
1117 pass
1119 # if we didn't find that device, check the existing config
1120 # for a device in the same class
1121 if not found:
1122 for dev_type, dev_info in self.all_devices_sxpr():
1123 if dev_type == cls:
1124 sxpr.append(['device', dev_info])
1126 txn.commit()
1127 except:
1128 txn.abort()
1129 raise
1131 if 'cpuid' in self:
1132 self.cpuid_to_sxp(sxpr, 'cpuid')
1133 if 'cpuid_check' in self:
1134 self.cpuid_to_sxp(sxpr, 'cpuid_check')
1136 log.debug(sxpr)
1138 return sxpr
1140 def _blkdev_name_to_number(self, dev):
1141 if 'ioemu:' in dev:
1142 _, dev = dev.split(':', 1)
1143 try:
1144 dev, _ = dev.split(':', 1)
1145 except ValueError:
1146 pass
1148 try:
1149 devid = int(dev)
1150 except ValueError:
1151 # devid is not a number but a string containing either device
1152 # name (e.g. xvda) or device_type/device_id (e.g. vbd/51728)
1153 dev2 = type(dev) is str and dev.split('/')[-1] or None
1154 if dev2 == None:
1155 log.debug("Could not check the device %s", dev)
1156 return None
1157 try:
1158 devid = int(dev2)
1159 except ValueError:
1160 (xenbus, devid) = blkdev_name_to_number(dev2)
1161 if devid == None:
1162 log.debug("The device %s is not device name", dev2)
1163 return None
1164 return devid
1166 def device_duplicate_check(self, dev_type, dev_info, defined_config, config):
1167 defined_devices_sxpr = self.all_devices_sxpr(target = defined_config)
1169 if dev_type == 'vbd' or dev_type == 'tap':
1170 dev_uname = dev_info.get('uname')
1171 blkdev_name = dev_info.get('dev')
1172 devid = self._blkdev_name_to_number(blkdev_name)
1173 if devid == None or dev_uname == None:
1174 return
1176 for o_dev_type, o_dev_info in defined_devices_sxpr:
1177 if o_dev_type == 'vbd' or o_dev_type == 'tap':
1178 blkdev_file = blkdev_uname_to_file(dev_uname)
1179 o_dev_uname = sxp.child_value(o_dev_info, 'uname')
1180 if o_dev_uname != None:
1181 o_blkdev_file = blkdev_uname_to_file(o_dev_uname)
1182 if blkdev_file == o_blkdev_file:
1183 raise XendConfigError('The file "%s" is already used' %
1184 blkdev_file)
1185 if dev_uname == o_dev_uname:
1186 raise XendConfigError('The uname "%s" is already defined' %
1187 dev_uname)
1188 o_blkdev_name = sxp.child_value(o_dev_info, 'dev')
1189 o_devid = self._blkdev_name_to_number(o_blkdev_name)
1190 if o_devid != None and devid == o_devid:
1191 name_array = blkdev_name.split(':', 2)
1192 if len(name_array) == 2 and name_array[1] == 'cdrom':
1194 # Since the device is a cdrom, we are most likely
1195 # inserting, changing, or removing a cd. We can
1196 # update the old device instead of creating a new
1197 # one.
1199 if o_dev_uname != None and dev_uname == None:
1201 # We are removing a cd. We can simply update
1202 # the uname on the existing device.
1204 merge_sxp = sxp.from_string("('vbd' ('uname' ''))")
1205 else:
1206 merge_sxp = config
1208 dev_uuid = sxp.child_value(o_dev_info, 'uuid')
1209 if dev_uuid != None and \
1210 self.device_update(dev_uuid, cfg_sxp = merge_sxp):
1211 return dev_uuid
1213 raise XendConfigError('The device "%s" is already defined' %
1214 blkdev_name)
1216 elif dev_type == 'vif':
1217 dev_mac = dev_info.get('mac')
1219 for o_dev_type, o_dev_info in defined_devices_sxpr:
1220 if dev_type == o_dev_type:
1221 if dev_mac.lower() == sxp.child_value(o_dev_info, 'mac').lower():
1222 raise XendConfigError('The mac "%s" is already defined' %
1223 dev_mac)
1224 return None
1226 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
1227 target = None):
1228 """Add a device configuration in SXP format or XenAPI struct format.
1230 For SXP, it could be either:
1232 [device, [vbd, [uname ...]]
1234 or:
1236 [vbd, [uname ..]]
1238 @type cfg_sxp: list of lists (parsed sxp object)
1239 @param cfg_sxp: SXP configuration object
1240 @type cfg_xenapi: dict
1241 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
1242 @param target: write device information to
1243 @type target: None or a dictionary
1244 @rtype: string
1245 @return: Assigned UUID of the device.
1246 """
1247 if target == None:
1248 target = self
1250 if dev_type not in XendDevices.valid_devices():
1251 raise XendConfigError("XendConfig: %s not a valid device type" %
1252 dev_type)
1254 if cfg_sxp == None and cfg_xenapi == None:
1255 raise XendConfigError("XendConfig: device_add requires some "
1256 "config.")
1258 #if cfg_sxp:
1259 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
1260 #if cfg_xenapi:
1261 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
1263 if cfg_sxp:
1264 if sxp.child0(cfg_sxp) == 'device':
1265 config = sxp.child0(cfg_sxp)
1266 else:
1267 config = cfg_sxp
1269 dev_type = sxp.name(config)
1270 dev_info = {}
1272 if dev_type == 'pci':
1273 pci_devs_uuid = sxp.child_value(config, 'uuid',
1274 uuid.createString())
1276 pci_dict = self.pci_convert_sxp_to_dict(config)
1277 pci_devs = pci_dict['devs']
1279 # create XenAPI DPCI objects.
1280 for pci_dev in pci_devs:
1281 dpci_uuid = pci_dev.get('uuid')
1282 ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
1283 pci_dev['bus'],
1284 pci_dev['slot'],
1285 pci_dev['func'])
1286 if ppci_uuid is None:
1287 continue
1288 dpci_record = {
1289 'VM': self['uuid'],
1290 'PPCI': ppci_uuid,
1291 'hotplug_slot': pci_dev.get('requested_vslot', 0)
1294 dpci_opts = pci_dev.get('opts')
1295 if dpci_opts and len(dpci_opts) > 0:
1296 dpci_record['options'] = dpci_opts
1298 XendDPCI(dpci_uuid, dpci_record)
1300 target['devices'][pci_devs_uuid] = (dev_type,
1301 {'devs': pci_devs,
1302 'uuid': pci_devs_uuid})
1304 log.debug("XendConfig: reading device: %s" % pci_devs)
1306 return pci_devs_uuid
1308 if dev_type == 'vscsi':
1309 vscsi_devs_uuid = sxp.child_value(config, 'uuid',
1310 uuid.createString())
1311 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1312 vscsi_devs = vscsi_dict['devs']
1313 vscsi_mode = vscsi_dict['feature-host']
1314 vscsi_be = vscsi_dict.get('backend', None)
1316 # create XenAPI DSCSI objects.
1317 for vscsi_dev in vscsi_devs:
1318 dscsi_uuid = vscsi_dev.get('uuid')
1319 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1320 if pscsi_uuid is None:
1321 continue
1322 dscsi_record = {
1323 'VM': self['uuid'],
1324 'PSCSI': pscsi_uuid,
1325 'virtual_HCTL': vscsi_dev.get('v-dev')
1327 XendDSCSI(dscsi_uuid, dscsi_record)
1329 vscsi_info = {
1330 'devs': vscsi_devs,
1331 'feature-host': vscsi_mode,
1332 'uuid': vscsi_devs_uuid
1334 if vscsi_be is not None:
1335 vscsi_info['backend'] = vscsi_be
1336 target['devices'][vscsi_devs_uuid] = (dev_type, vscsi_info)
1337 log.debug("XendConfig: reading device: %s,%s" % \
1338 (vscsi_devs, vscsi_mode))
1339 return vscsi_devs_uuid
1341 for opt_val in config[1:]:
1342 try:
1343 opt, val = opt_val
1344 dev_info[opt] = val
1345 except (TypeError, ValueError): # unpack error
1346 pass
1348 if dev_type == 'vbd':
1349 if dev_info.get('dev', '').startswith('ioemu:'):
1350 dev_info['driver'] = 'ioemu'
1351 else:
1352 dev_info['driver'] = 'paravirtualised'
1354 if dev_type == 'tap':
1355 if dev_info['uname'].split(':')[1] not in blktap_disk_types:
1356 raise XendConfigError("tap:%s not a valid disk type" %
1357 dev_info['uname'].split(':')[1])
1359 if dev_type == 'vif':
1360 if not dev_info.get('mac'):
1361 dev_info['mac'] = randomMAC()
1363 ret_uuid = self.device_duplicate_check(dev_type, dev_info, target, config)
1364 if ret_uuid != None:
1365 return ret_uuid
1367 if dev_type == 'vif':
1368 if dev_info.get('policy') and dev_info.get('label'):
1369 dev_info['security_label'] = "%s:%s:%s" % \
1370 (xsconstants.ACM_POLICY_ID,
1371 dev_info['policy'],dev_info['label'])
1373 # create uuid if it doesn't exist
1374 dev_uuid = dev_info.get('uuid', None)
1375 if not dev_uuid:
1376 dev_uuid = uuid.createString()
1377 dev_info['uuid'] = dev_uuid
1379 # store dev references by uuid for certain device types
1380 target['devices'][dev_uuid] = (dev_type, dev_info)
1381 if dev_type in ('vif', 'vbd', 'vtpm'):
1382 param = '%s_refs' % dev_type
1383 if param not in target:
1384 target[param] = []
1385 if dev_uuid not in target[param]:
1386 if dev_type == 'vbd' and 'bootable' not in dev_info:
1387 # Compat hack -- mark first disk bootable
1388 dev_info['bootable'] = int(not target[param])
1389 target[param].append(dev_uuid)
1390 elif dev_type == 'tap':
1391 if 'vbd_refs' not in target:
1392 target['vbd_refs'] = []
1393 if dev_uuid not in target['vbd_refs']:
1394 if 'bootable' not in dev_info:
1395 # Compat hack -- mark first disk bootable
1396 dev_info['bootable'] = int(not target['vbd_refs'])
1397 target['vbd_refs'].append(dev_uuid)
1399 elif dev_type == 'vfb':
1400 # Populate other config with aux data that is associated
1401 # with vfb
1403 other_config = {}
1404 for key in XENAPI_CONSOLE_OTHER_CFG:
1405 if key in dev_info:
1406 other_config[key] = dev_info[key]
1407 target['devices'][dev_uuid][1]['other_config'] = other_config
1410 if 'console_refs' not in target:
1411 target['console_refs'] = []
1413 # Treat VFB devices as console devices so they are found
1414 # through Xen API
1415 if dev_uuid not in target['console_refs']:
1416 target['console_refs'].append(dev_uuid)
1418 # Cope with old-format save files which say under vfb
1419 # (type vfb) rather than (vfb 1)
1420 try:
1421 vfb_type = dev_info['type']
1422 except KeyError:
1423 vfb_type = None
1424 log.debug("iwj dev_type=%s vfb type %s" %
1425 (dev_type, `vfb_type`))
1427 if vfb_type == 'vnc' or vfb_type == 'sdl':
1428 dev_info[vfb_type] = 1
1429 del dev_info['type']
1430 log.debug("iwj dev_type=%s vfb setting dev_info['%s']" %
1431 (dev_type, vfb_type))
1433 elif dev_type == 'console':
1434 if 'console_refs' not in target:
1435 target['console_refs'] = []
1436 if dev_uuid not in target['console_refs']:
1437 target['console_refs'].append(dev_uuid)
1439 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
1440 return dev_uuid
1442 if cfg_xenapi:
1443 dev_info = {}
1444 dev_uuid = ''
1445 if dev_type == 'vif':
1446 dev_info['mac'] = cfg_xenapi.get('MAC')
1447 if not dev_info['mac']:
1448 dev_info['mac'] = randomMAC()
1449 # vifname is the name on the guest, not dom0
1450 # TODO: we don't have the ability to find that out or
1451 # change it from dom0
1452 #if cfg_xenapi.get('device'): # don't add if blank
1453 # dev_info['vifname'] = cfg_xenapi.get('device')
1454 if cfg_xenapi.get('type'):
1455 dev_info['type'] = cfg_xenapi.get('type')
1456 if cfg_xenapi.get('name'):
1457 dev_info['name'] = cfg_xenapi.get('name')
1458 if cfg_xenapi.get('network'):
1459 network = XendAPIStore.get(
1460 cfg_xenapi.get('network'), 'network')
1461 dev_info['bridge'] = network.get_name_label()
1463 if cfg_xenapi.get('security_label'):
1464 dev_info['security_label'] = \
1465 cfg_xenapi.get('security_label')
1467 dev_uuid = cfg_xenapi.get('uuid', None)
1468 if not dev_uuid:
1469 dev_uuid = uuid.createString()
1470 dev_info['uuid'] = dev_uuid
1471 target['devices'][dev_uuid] = (dev_type, dev_info)
1472 target['vif_refs'].append(dev_uuid)
1474 elif dev_type in ('vbd', 'tap'):
1475 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1476 if dev_info['type'] == 'CD':
1477 old_vbd_type = 'cdrom'
1478 else:
1479 old_vbd_type = 'disk'
1481 dev_info['uname'] = cfg_xenapi.get('image', '')
1482 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1483 old_vbd_type)
1484 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1485 dev_info['driver'] = cfg_xenapi.get('driver', '')
1486 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1488 if cfg_xenapi.get('mode') == 'RW':
1489 dev_info['mode'] = 'w'
1490 else:
1491 dev_info['mode'] = 'r'
1493 dev_uuid = cfg_xenapi.get('uuid', None)
1494 if not dev_uuid:
1495 dev_uuid = uuid.createString()
1496 dev_info['uuid'] = dev_uuid
1497 target['devices'][dev_uuid] = (dev_type, dev_info)
1498 target['vbd_refs'].append(dev_uuid)
1500 elif dev_type == 'vtpm':
1501 if cfg_xenapi.get('type'):
1502 dev_info['type'] = cfg_xenapi.get('type')
1504 dev_uuid = cfg_xenapi.get('uuid', None)
1505 if not dev_uuid:
1506 dev_uuid = uuid.createString()
1507 dev_info['uuid'] = dev_uuid
1508 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1509 target['devices'][dev_uuid] = (dev_type, dev_info)
1510 target['vtpm_refs'].append(dev_uuid)
1512 elif dev_type == 'console':
1513 dev_uuid = cfg_xenapi.get('uuid', None)
1514 if not dev_uuid:
1515 dev_uuid = uuid.createString()
1516 dev_info['uuid'] = dev_uuid
1517 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1518 console_other_config = cfg_xenapi.get('other_config', {})
1519 dev_info['other_config'] = console_other_config
1520 if dev_info['protocol'] == 'rfb':
1521 # collapse other config into devinfo for things
1522 # such as vncpasswd, vncunused, etc.
1523 dev_info.update(console_other_config)
1524 dev_info['vnc'] = console_other_config.get('vnc', '0')
1525 dev_info['sdl'] = console_other_config.get('sdl', '0')
1526 target['devices'][dev_uuid] = ('vfb', dev_info)
1527 target['console_refs'].append(dev_uuid)
1529 # if console is rfb, set device_model ensuring qemu
1530 # is invoked for pvfb services
1531 if 'device_model' not in target['platform']:
1532 target['platform']['device_model'] = \
1533 xen.util.auxbin.pathTo("qemu-dm")
1535 # Finally, if we are a pvfb, we need to make a vkbd
1536 # as well that is not really exposed to Xen API
1537 vkbd_uuid = uuid.createString()
1538 target['devices'][vkbd_uuid] = ('vkbd', {})
1540 elif dev_info['protocol'] == 'vt100':
1541 # if someone tries to create a VT100 console
1542 # via the Xen API, we'll have to ignore it
1543 # because we create one automatically in
1544 # XendDomainInfo._update_consoles
1545 raise XendConfigError('Creating vt100 consoles via '
1546 'Xen API is unsupported')
1548 return dev_uuid
1550 # no valid device to add
1551 return ''
1553 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1554 target = None):
1555 """Add a phantom tap device configuration in XenAPI struct format.
1556 """
1558 if target == None:
1559 target = self
1561 if dev_type not in XendDevices.valid_devices() and \
1562 dev_type not in XendDevices.pseudo_devices():
1563 raise XendConfigError("XendConfig: %s not a valid device type" %
1564 dev_type)
1566 if cfg_xenapi == None:
1567 raise XendConfigError("XendConfig: device_add requires some "
1568 "config.")
1570 if cfg_xenapi:
1571 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1573 if cfg_xenapi:
1574 dev_info = {}
1575 if dev_type in ('vbd', 'tap'):
1576 if dev_type == 'vbd':
1577 dev_info['uname'] = cfg_xenapi.get('image', '')
1578 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1579 elif dev_type == 'tap':
1580 if cfg_xenapi.get('image').find('tap:') == -1:
1581 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1582 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1583 dev_info['uname'] = cfg_xenapi.get('image')
1584 dev_info['mode'] = cfg_xenapi.get('mode')
1585 dev_info['backend'] = '0'
1586 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1587 dev_info['uuid'] = dev_uuid
1588 self['devices'][dev_uuid] = (dev_type, dev_info)
1589 self['vbd_refs'].append(dev_uuid)
1590 return dev_uuid
1592 return ''
1594 def pci_convert_dict_to_sxp(self, dev, state, sub_state = None):
1595 sxp = ['pci', ['dev'] + map(lambda (x, y): [x, y], dev.items()),
1596 ['state', state]]
1597 if sub_state != None:
1598 sxp.append(['sub_state', sub_state])
1599 return sxp
1601 def pci_convert_sxp_to_dict(self, dev_sxp):
1602 """Convert pci device sxp to dict
1603 @param dev_sxp: device configuration
1604 @type dev_sxp: SXP object (parsed config)
1605 @return: dev_config
1606 @rtype: dictionary
1607 """
1608 # Parsing the device SXP's. In most cases, the SXP looks
1609 # like this:
1611 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
1613 # However, for PCI devices it looks like this:
1615 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2]]]
1617 # It seems the reasoning for this difference is because
1618 # pciif.py needs all the PCI device configurations at
1619 # the same time when creating the devices.
1621 # To further complicate matters, Xen 2.0 configuration format
1622 # uses the following for pci device configuration:
1624 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
1626 # For PCI device hotplug support, the SXP of PCI devices is
1627 # extendend like this:
1629 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2],
1630 # [vslot, 0]],
1631 # [state, 'Initialising']]]
1633 # 'vslot' shows the virtual hotplug slot number which the PCI device
1634 # is inserted in. This is only effective for HVM domains.
1636 # state 'Initialising' indicates that the device is being attached,
1637 # while state 'Closing' indicates that the device is being detached.
1639 # The Dict looks like this:
1641 # { devs: [{domain: 0, bus: 0, slot: 1, func: 2, vslot: 0}],
1642 # states: ['Initialising'] }
1644 dev_config = {}
1646 pci_devs = []
1647 for pci_dev in sxp.children(dev_sxp, 'dev'):
1648 pci_dev_info = {}
1649 for opt_val in pci_dev[1:]:
1650 try:
1651 opt, val = opt_val
1652 pci_dev_info[opt] = val
1653 except (TypeError, ValueError):
1654 pass
1655 # append uuid to each pci device that does't already have one.
1656 if not pci_dev_info.has_key('uuid'):
1657 dpci_uuid = pci_dev_info.get('uuid', uuid.createString())
1658 pci_dev_info['uuid'] = dpci_uuid
1659 pci_devs.append(pci_dev_info)
1660 dev_config['devs'] = pci_devs
1662 pci_states = []
1663 for pci_state in sxp.children(dev_sxp, 'state'):
1664 try:
1665 pci_states.append(pci_state[1])
1666 except IndexError:
1667 raise XendError("Error reading state while parsing pci sxp")
1668 dev_config['states'] = pci_states
1670 return dev_config
1672 def vscsi_convert_sxp_to_dict(self, dev_sxp):
1673 """Convert vscsi device sxp to dict
1674 @param dev_sxp: device configuration
1675 @type dev_sxp: SXP object (parsed config)
1676 @return: dev_config
1677 @rtype: dictionary
1678 """
1679 # Parsing the device SXP's. In most cases, the SXP looks
1680 # like this:
1682 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
1684 # However, for SCSI devices it looks like this:
1686 # [device,
1687 # [vscsi,
1688 # [feature-host, 0],
1689 # [backend, 0],
1690 # [dev,
1691 # [devid, 0], [p-devname, sdb], [p-dev, 1:0:0:1],
1692 # [v-dev, 0:0:0:0], [state, 1]
1693 # ],
1694 # [dev,
1695 # [devid, 0], [p-devname, sdc], [p-dev, 1:0:0:2],
1696 # [v-dev, 0:0:0:1], [satet, 1]
1697 # ]
1698 # ],
1699 # [vscsi,
1700 # [feature-host, 1],
1701 # [backend, 0],
1702 # [dev,
1703 # [devid, 1], [p-devname, sdg], [p-dev, 2:0:0:0],
1704 # [v-dev, 1:0:0:0], [state, 1]
1705 # ],
1706 # [dev,
1707 # [devid, 1], [p-devname, sdh], [p-dev, 2:0:0:1],
1708 # [v-dev, 1:0:0:1], [satet, 1]
1709 # ]
1710 # ]
1711 # ]
1713 # It seems the reasoning for this difference is because
1714 # vscsiif.py needs all the SCSI device configurations with
1715 # same host number at the same time when creating the devices.
1717 # For SCSI device hotplug support, the SXP of SCSI devices is
1718 # extendend like this:
1720 # [device,
1721 # [vscsi,
1722 # [feature-host, 0],
1723 # [backend, 0],
1724 # [dev,
1725 # [devid, 0], [p-devname, sdd], [p-dev, 1:0:0:3],
1726 # [v-dev, 0:0:0:2], [state, 1]
1727 # ]
1728 # ]
1729 # ]
1731 # state xenbusState['Initialising'] indicates that the device is
1732 # being attached, while state xenbusState['Closing'] indicates
1733 # that the device is being detached.
1735 # The Dict looks like this:
1737 # { devs: [ {devid: 0, p-devname: sdd, p-dev: 1:0:0:3,
1738 # v-dev: 0:0:0:2, state: 1} ],
1739 # feature-host: 1 , backend: 0 }
1741 dev_config = {}
1743 vscsi_devs = []
1744 for vscsi_dev in sxp.children(dev_sxp, 'dev'):
1745 vscsi_dev_info = {}
1746 for opt_val in vscsi_dev[1:]:
1747 try:
1748 opt, val = opt_val
1749 vscsi_dev_info[opt] = val
1750 except TypeError:
1751 pass
1752 # append uuid for each vscsi device.
1753 vscsi_uuid = vscsi_dev_info.get('uuid', uuid.createString())
1754 vscsi_dev_info['uuid'] = vscsi_uuid
1755 vscsi_devs.append(vscsi_dev_info)
1756 dev_config['devs'] = vscsi_devs
1758 vscsi_mode = sxp.children(dev_sxp, 'feature-host')[0]
1759 dev_config['feature-host'] = vscsi_mode[1]
1760 try:
1761 vscsi_be = sxp.children(dev_sxp, 'backend')[0]
1762 dev_config['backend'] = vscsi_be[1]
1763 except IndexError:
1764 pass
1766 return dev_config
1768 def console_add(self, protocol, location, other_config = {}):
1769 dev_uuid = uuid.createString()
1770 if protocol == 'vt100':
1771 dev_info = {
1772 'uuid': dev_uuid,
1773 'protocol': protocol,
1774 'location': location,
1775 'other_config': other_config,
1778 if 'devices' not in self:
1779 self['devices'] = {}
1781 self['devices'][dev_uuid] = ('console', dev_info)
1782 self['console_refs'].append(dev_uuid)
1783 return dev_info
1785 return {}
1787 def console_update(self, console_uuid, key, value):
1788 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1789 if dev_uuid == console_uuid:
1790 dev_info[key] = value
1791 # collapse other_config into dev_info for things
1792 # such as vncpasswd, vncunused, etc.
1793 if key == 'other_config':
1794 for k in XENAPI_CONSOLE_OTHER_CFG:
1795 if k in dev_info and k not in value:
1796 del dev_info[k]
1797 dev_info.update(value)
1798 break
1800 def console_get_all(self, protocol):
1801 if protocol == 'vt100':
1802 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1803 if dtype == 'console']
1804 return [c for c in consoles if c.get('protocol') == protocol]
1806 elif protocol == 'rfb':
1807 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1808 if dtype == 'vfb']
1810 # move all non-console key values to other_config before
1811 # returning console config
1812 valid_keys = ['uuid', 'location']
1813 for vfb in vfbs:
1814 other_config = {}
1815 for key, val in vfb.items():
1816 if key not in valid_keys:
1817 other_config[key] = vfb[key]
1818 del vfb[key]
1819 vfb['other_config'] = other_config
1820 vfb['protocol'] = 'rfb'
1822 return vfbs
1824 else:
1825 return []
1827 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1828 """Update an existing device with the new configuration.
1830 @rtype: boolean
1831 @return: Returns True if succesfully found and updated a device conf
1832 """
1833 if dev_uuid in self['devices'] and cfg_sxp:
1834 if sxp.child0(cfg_sxp) == 'device':
1835 config = sxp.child0(cfg_sxp)
1836 else:
1837 config = cfg_sxp
1839 dev_type, dev_info = self['devices'][dev_uuid]
1841 if dev_type == 'pci': # Special case for pci
1842 pci_dict = self.pci_convert_sxp_to_dict(config)
1843 pci_devs = pci_dict['devs']
1845 # destroy existing XenAPI DPCI objects
1846 for dpci_uuid in XendDPCI.get_by_VM(self['uuid']):
1847 XendAPIStore.deregister(dpci_uuid, "DPCI")
1849 # create XenAPI DPCI objects.
1850 for pci_dev in pci_devs:
1851 dpci_uuid = pci_dev.get('uuid')
1852 ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
1853 pci_dev['bus'],
1854 pci_dev['slot'],
1855 pci_dev['func'])
1856 if ppci_uuid is None:
1857 continue
1858 dpci_record = {
1859 'VM': self['uuid'],
1860 'PPCI': ppci_uuid,
1861 'hotplug_slot': pci_dev.get('requested_vslot', 0)
1864 dpci_opts = pci_dev.get('opts')
1865 if dpci_opts and len(dpci_opts) > 0:
1866 dpci_record['options'] = dpci_opts
1868 XendDPCI(dpci_uuid, dpci_record)
1870 self['devices'][dev_uuid] = (dev_type,
1871 {'devs': pci_devs,
1872 'uuid': dev_uuid})
1873 return True
1875 if dev_type == 'vscsi': # Special case for vscsi
1876 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1877 vscsi_devs = vscsi_dict['devs']
1878 vscsi_mode = vscsi_dict['feature-host']
1879 vscsi_be = vscsi_dict.get('backend', None)
1881 # destroy existing XenAPI DSCSI objects
1882 vscsi_devid = int(dev_info['devs'][0]['devid'])
1883 for dscsi_uuid in XendDSCSI.get_by_VM(self['uuid']):
1884 dscsi_inst = XendAPIStore.get(dscsi_uuid, 'DSCSI')
1885 if vscsi_devid == dscsi_inst.get_virtual_host():
1886 XendAPIStore.deregister(dscsi_uuid, "DSCSI")
1888 # create XenAPI DSCSI objects.
1889 for vscsi_dev in vscsi_devs:
1890 dscsi_uuid = vscsi_dev.get('uuid')
1891 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1892 if pscsi_uuid is None:
1893 continue
1894 dscsi_record = {
1895 'VM': self['uuid'],
1896 'PSCSI': pscsi_uuid,
1897 'virtual_HCTL': vscsi_dev.get('v-dev')
1899 XendDSCSI(dscsi_uuid, dscsi_record)
1901 vscsi_info = {
1902 'devs': vscsi_devs,
1903 'feature-host': vscsi_mode,
1904 'uuid': dev_uuid
1906 if vscsi_be is not None:
1907 vscsi_info['backend'] = vscsi_be
1908 self['devices'][dev_uuid] = (dev_type, vscsi_info)
1909 return True
1911 for opt_val in config[1:]:
1912 try:
1913 opt, val = opt_val
1914 dev_info[opt] = val
1915 except (TypeError, ValueError):
1916 pass # no value for this config option
1918 self['devices'][dev_uuid] = (dev_type, dev_info)
1919 return True
1921 elif dev_uuid in self['devices'] and cfg_xenapi:
1922 dev_type, dev_info = self['devices'][dev_uuid]
1923 for key, val in cfg_xenapi.items():
1924 dev_info[key] = val
1925 self['devices'][dev_uuid] = (dev_type, dev_info)
1926 return True
1928 return False
1931 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None, target = None):
1932 """Get Device SXPR by either giving the device UUID or (type, config).
1934 @rtype: list of lists
1935 @return: device config sxpr
1936 """
1937 sxpr = []
1939 if target == None:
1940 target = self
1942 if dev_uuid != None and dev_uuid in target['devices']:
1943 dev_type, dev_info = target['devices'][dev_uuid]
1945 if dev_type == None or dev_info == None:
1946 raise XendConfigError("Required either UUID or device type and "
1947 "configuration dictionary.")
1949 sxpr.append(dev_type)
1950 if dev_type in ('console', 'vfb'):
1951 config = [(opt, val) for opt, val in dev_info.items()
1952 if opt != 'other_config']
1953 else:
1954 config = [(opt, val) for opt, val in dev_info.items()]
1956 sxpr += config
1958 return sxpr
1960 def ordered_device_refs(self, target = None):
1961 result = []
1963 if target == None:
1964 target = self
1966 # vkbd devices *must* be before vfb devices, otherwise
1967 # there is a race condition when setting up devices
1968 # where the daemon spawned for the vfb may write stuff
1969 # into xenstore vkbd backend, before DevController has
1970 # setup permissions on the vkbd backend path. This race
1971 # results in domain creation failing with 'device already
1972 # connected' messages
1973 result.extend([u for u in target['devices'].keys() if target['devices'][u][0] == 'vkbd'])
1975 result.extend(target.get('console_refs', []) +
1976 target.get('vbd_refs', []) +
1977 target.get('vif_refs', []) +
1978 target.get('vtpm_refs', []))
1980 result.extend([u for u in target['devices'].keys() if u not in result])
1981 return result
1983 def all_devices_sxpr(self, target = None):
1984 """Returns the SXPR for all devices in the current configuration."""
1985 sxprs = []
1987 if target == None:
1988 target = self
1990 if 'devices' not in target:
1991 return sxprs
1993 ordered_refs = self.ordered_device_refs(target = target)
1994 for dev_uuid in ordered_refs:
1995 dev_type, dev_info = target['devices'][dev_uuid]
1996 if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
1997 if dev_type == 'pci':
1998 sxpr = ['pci', ['uuid', dev_info['uuid']]]
1999 elif dev_type == 'vscsi':
2000 sxpr = ['vscsi', ['uuid', dev_info['uuid']],
2001 ['feature-host', dev_info['feature-host']]]
2002 if dev_info.has_key('backend'):
2003 sxpr.append(['backend', dev_info['backend']])
2004 for pci_dev_info in dev_info['devs']:
2005 pci_dev_sxpr = ['dev']
2006 for opt, val in pci_dev_info.items():
2007 pci_dev_sxpr.append([opt, val])
2008 sxpr.append(pci_dev_sxpr)
2009 sxprs.append((dev_type, sxpr))
2010 else:
2011 sxpr = self.device_sxpr(dev_type = dev_type,
2012 dev_info = dev_info,
2013 target = target)
2014 sxprs.append((dev_type, sxpr))
2016 return sxprs
2018 def image_sxpr(self):
2019 """Returns a backwards compatible image SXP expression that is
2020 used in xenstore's /vm/<uuid>/image value and xm list."""
2021 image = [self.image_type()]
2022 if self.has_key('PV_kernel'):
2023 image.append(['kernel', self['PV_kernel']])
2024 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
2025 image.append(['ramdisk', self['PV_ramdisk']])
2026 if self.has_key('PV_args') and self['PV_args']:
2027 image.append(['args', self['PV_args']])
2028 if self.has_key('superpages'):
2029 image.append(['superpages', self['superpages']])
2031 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
2032 if key in self['platform']:
2033 image.append([key, self['platform'][key]])
2035 if 'notes' in self:
2036 image.append(self.notes_sxp(self['notes']))
2038 return image
2040 def update_with_image_sxp(self, image_sxp, bootloader = False):
2041 # Convert Legacy "image" config to Xen API PV_*
2042 # configuration
2043 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
2045 # user-specified args must come last: previous releases did this and
2046 # some domU kernels rely upon the ordering.
2047 kernel_args = sxp.child_value(image_sxp, 'args', '')
2049 # attempt to extract extra arguments from SXP config
2050 arg_ip = sxp.child_value(image_sxp, 'ip')
2051 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
2052 kernel_args = 'ip=%s ' % arg_ip + kernel_args
2053 arg_root = sxp.child_value(image_sxp, 'root')
2054 if arg_root and not re.search(r'root=', kernel_args):
2055 kernel_args = 'root=%s ' % arg_root + kernel_args
2057 if bootloader:
2058 self['_temp_using_bootloader'] = '1'
2059 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
2060 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
2061 self['_temp_args'] = kernel_args
2062 else:
2063 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
2064 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
2065 self['PV_args'] = kernel_args
2067 self['superpages'] = sxp.child_value(image_sxp, 'superpages',0)
2069 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
2070 val = sxp.child_value(image_sxp, key, None)
2071 if val is not None and val != '':
2072 self['platform'][key] = val
2074 notes = sxp.children(image_sxp, 'notes')
2075 if notes:
2076 self['notes'] = self.notes_from_sxp(notes[0])
2078 self._hvm_boot_params_from_sxp(image_sxp)
2080 def set_notes(self, notes):
2081 'Add parsed elfnotes to image'
2082 self['notes'] = notes
2084 def get_notes(self):
2085 try:
2086 return self['notes'] or {}
2087 except KeyError:
2088 return {}
2090 def notes_from_sxp(self, nsxp):
2091 notes = {}
2092 for note in sxp.children(nsxp):
2093 notes[note[0]] = note[1]
2094 return notes
2096 def notes_sxp(self, notes):
2097 nsxp = ['notes']
2098 for k, v in notes.iteritems():
2099 nsxp.append([k, str(v)])
2100 return nsxp
2102 def _hvm_boot_params_from_sxp(self, image_sxp):
2103 boot = sxp.child_value(image_sxp, 'boot', None)
2104 if boot is not None:
2105 self['HVM_boot_policy'] = 'BIOS order'
2106 self['HVM_boot_params'] = { 'order' : boot }
2108 def is_hvm(self):
2109 return self['HVM_boot_policy'] != ''
2111 def target(self):
2112 return self['target']
2114 def image_type(self):
2115 stored_type = self['platform'].get('image_type')
2116 return stored_type or (self.is_hvm() and 'hvm' or 'linux')
2118 def is_hap(self):
2119 return self['platform'].get('hap', 0)
2121 def update_platform_pci(self):
2122 if not self.is_hvm():
2123 return
2125 pci = []
2126 for dev_type, dev_info in self.all_devices_sxpr():
2127 if dev_type != 'pci':
2128 continue
2129 for dev in sxp.children(dev_info, 'dev'):
2130 domain = sxp.child_value(dev, 'domain')
2131 bus = sxp.child_value(dev, 'bus')
2132 slot = sxp.child_value(dev, 'slot')
2133 func = sxp.child_value(dev, 'func')
2134 vslot = assigned_or_requested_vslot(dev)
2135 opts = ''
2136 for opt in sxp.child_value(dev, 'opts', []):
2137 if opts:
2138 opts += ','
2139 opts += '%s=%s' % (opt[0], str(opt[1]))
2140 pci.append([domain, bus, slot, func, vslot, opts])
2141 self['platform']['pci'] = pci