ia64/xen-unstable

view tools/python/xen/xend/XendConfig.py @ 19841:c30ace4ad49f

tools: fix inverted logic check

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