ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 19460:2269d8704139

XenAPI: Implement {get,set}_auto_power_on

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