debuggers.hg

view tools/python/xen/xend/XendConfig.py @ 20989:560277d2fd20

xend: Remove redundant 'name' from LEGACY_CFG_TYPES and LEGACY_XENSTORE_VM_PARAMS

Two 'name's are defined in LEGACY_CFG_TYPES of XendConfig.py.
LEGACY_XENSTORE_VM_PARAMS also is same.
This patch removes redundant 'name's.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 15 08:19:07 2010 +0000 (2010-02-15)
parents 020e7a7d4474
children 499a11c1c25e
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, XendDSCSI_HBA
32 from xen.xend.XendError import VmError
33 from xen.xend.XendDevices import XendDevices
34 from xen.xend.PrettyPrint import prettyprintstring
35 from xen.xend.XendConstants import DOM_STATE_HALTED, AUTO_PHP_SLOT
36 from xen.xend.xenstore.xstransact import xstransact
37 from xen.xend.server.BlktapController import blktap_disk_types
38 from xen.xend.server.netif import randomMAC
39 from xen.util.blkif import blkdev_name_to_number, blkdev_uname_to_file
40 from xen.util.pci import pci_opts_list_from_sxp, pci_convert_sxp_to_dict
41 from xen.xend.XendSXPDev import dev_dict_to_sxp
42 from xen.util import xsconstants
43 from xen.util import auxbin
44 import xen.util.fileuri
46 log = logging.getLogger("xend.XendConfig")
47 log.setLevel(logging.WARN)
50 """
51 XendConfig API
53 XendConfig will try to mirror as closely the Xen API VM Struct
54 with extra parameters for those options that are not supported.
56 """
58 def reverse_dict(adict):
59 """Return the reverse mapping of a dictionary."""
60 return dict([(v, k) for k, v in adict.items()])
62 def bool0(v):
63 return v != '0' and v != 'False' and bool(v)
65 # Recursively copy a data struct, scrubbing out VNC passwords.
66 # Will scrub any dict entry with a key of 'vncpasswd' or any
67 # 2-element list whose first member is 'vncpasswd'. It will
68 # also scrub a string matching '(vncpasswd XYZ)'. Everything
69 # else is no-op passthrough
70 def scrub_password(data):
71 if type(data) == dict or type(data) == XendConfig:
72 scrubbed = {}
73 for key in data.keys():
74 if key == "vncpasswd":
75 scrubbed[key] = "XXXXXXXX"
76 else:
77 scrubbed[key] = scrub_password(data[key])
78 return scrubbed
79 elif type(data) == list:
80 if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd':
81 return ['vncpasswd', 'XXXXXXXX']
82 else:
83 scrubbed = []
84 for entry in data:
85 scrubbed.append(scrub_password(entry))
86 return scrubbed
87 elif type(data) == tuple:
88 scrubbed = []
89 for entry in data:
90 scrubbed.append(scrub_password(entry))
91 return tuple(scrubbed)
92 elif type(data) == str:
93 return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data)
94 else:
95 return data
97 #
98 # CPU fields:
99 #
100 # VCPUs_max -- the maximum number of vcpus that this domain may ever have.
101 # aka XendDomainInfo.getVCpuCount().
102 # vcpus -- the legacy configuration name for above.
103 # max_vcpu_id -- vcpus_number - 1. This is given to us by Xen.
104 #
105 # cpus -- the list of pCPUs available to each vCPU.
106 #
107 # vcpu_avail -- a bitmap telling the guest domain whether it may use each of
108 # its VCPUs. This is translated to
109 # <dompath>/cpu/<id>/availability = {online,offline} for use
110 # by the guest domain.
111 # VCPUs_live -- the number of VCPUs currently up, as reported by Xen. This
112 # is changed by changing vcpu_avail, and waiting for the
113 # domain to respond.
114 #
117 # Mapping from XendConfig configuration keys to the old
118 # legacy configuration keys that map directly.
120 XENAPI_CFG_TO_LEGACY_CFG = {
121 'uuid': 'uuid',
122 'VCPUs_max': 'vcpus',
123 'cpus': 'cpus',
124 'name_label': 'name',
125 'actions_after_shutdown': 'on_poweroff',
126 'actions_after_reboot': 'on_reboot',
127 'actions_after_crash': 'on_crash',
128 'PV_bootloader': 'bootloader',
129 'PV_bootloader_args': 'bootloader_args',
130 'Description': 'description',
131 }
133 LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
135 # Platform configuration keys and their types.
136 XENAPI_PLATFORM_CFG_TYPES = {
137 'acpi': int,
138 'apic': int,
139 'boot': str,
140 'device_model': str,
141 'loader': str,
142 'display' : str,
143 'fda': str,
144 'fdb': str,
145 'keymap': str,
146 'isa' : int,
147 'localtime': int,
148 'monitor': int,
149 'monitor_path': str,
150 'nographic': int,
151 'nomigrate': int,
152 'pae' : int,
153 'rtc_timeoffset': int,
154 'parallel': str,
155 'serial': str,
156 'sdl': int,
157 'opengl': int,
158 'soundhw': str,
159 'stdvga': int,
160 'videoram': int,
161 'usb': int,
162 'usbdevice': str,
163 'hpet': int,
164 'vnc': int,
165 'vncconsole': int,
166 'vncdisplay': int,
167 'vnclisten': str,
168 'timer_mode': int,
169 'tsc_mode': int,
170 'vpt_align': int,
171 'viridian': int,
172 'vncpasswd': str,
173 'vncunused': int,
174 'xauthority': str,
175 'pci': str,
176 'vhpt': int,
177 'guest_os_type': str,
178 'hap': int,
179 'xen_extended_power_mgmt': int,
180 'pci_msitranslate': int,
181 'pci_power_mgmt': int,
182 'xen_platform_pci': int,
183 "gfx_passthru": int,
184 'oos' : int,
185 }
187 # Xen API console 'other_config' keys.
188 XENAPI_CONSOLE_OTHER_CFG = ['vncunused', 'vncdisplay', 'vnclisten',
189 'vncpasswd', 'sdl', 'vnc', 'display', 'xauthority',
190 'keymap', 'opengl']
192 # List of XendConfig configuration keys that have no direct equivalent
193 # in the old world.
195 XENAPI_CFG_TYPES = {
196 'uuid': str,
197 'name_label': str,
198 'name_description': str,
199 'user_version': str,
200 'is_a_template': bool0,
201 'auto_power_on': bool0,
202 'resident_on': str,
203 'memory_static_min': int, # note these are stored in bytes, not KB!
204 'memory_static_max': int,
205 'memory_dynamic_min': int,
206 'memory_dynamic_max': int,
207 'cpus': list,
208 'vcpus_params': dict,
209 'VCPUs_max': int,
210 'VCPUs_at_startup': int,
211 'VCPUs_live': int,
212 'actions_after_shutdown': str,
213 'actions_after_reboot': str,
214 'actions_after_crash': str,
215 'PV_bootloader': str,
216 'PV_kernel': str,
217 'PV_ramdisk': str,
218 'PV_args': str,
219 'PV_bootloader_args': str,
220 'HVM_boot_policy': str,
221 'HVM_boot_params': dict,
222 'PCI_bus': str,
223 'platform': dict,
224 'tools_version': dict,
225 'other_config': dict,
226 'target': int,
227 'security_label': str,
228 'pci': str,
229 'cpuid' : dict,
230 'cpuid_check' : dict,
231 'machine_address_size': int,
232 'suppress_spurious_page_faults': bool0,
233 's3_integrity' : int,
234 'superpages' : int,
235 'memory_sharing': int,
236 }
238 # List of legacy configuration keys that have no equivalent in the
239 # Xen API, but are still stored in XendConfig.
241 LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
242 # roundtripped (dynamic, unmodified)
243 'shadow_memory',
244 'vcpu_avail',
245 'features',
246 # read/write
247 'on_xend_start',
248 'on_xend_stop',
249 # read-only
250 'domid',
251 'start_time',
252 'cpu_time',
253 'online_vcpus',
254 # write-once
255 'cpu',
256 'cpus',
257 ]
259 LEGACY_CFG_TYPES = {
260 'uuid': str,
261 'name': str,
262 'vcpus': int,
263 'vcpu_avail': long,
264 'memory': int,
265 'shadow_memory': int,
266 'maxmem': int,
267 'start_time': float,
268 'cpu_time': float,
269 'features': str,
270 'localtime': int,
271 'on_poweroff': str,
272 'on_reboot': str,
273 'on_crash': str,
274 'on_xend_stop': str,
275 'on_xend_start': str,
276 'online_vcpus': int,
277 'rtc/timeoffset': str,
278 'bootloader': str,
279 'bootloader_args': str,
280 'description': str,
281 }
283 # Values that should be stored in xenstore's /vm/<uuid> that is used
284 # by Xend. Used in XendDomainInfo to restore running VM state from
285 # xenstore.
286 LEGACY_XENSTORE_VM_PARAMS = [
287 'uuid',
288 'name',
289 'vcpus',
290 'vcpu_avail',
291 'memory',
292 'shadow_memory',
293 'maxmem',
294 'start_time',
295 'on_poweroff',
296 'on_crash',
297 'on_reboot',
298 'on_xend_start',
299 'on_xend_stop',
300 'bootloader',
301 'bootloader_args',
302 ]
304 ##
305 ## Config Choices
306 ##
308 CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart',
309 'coredump-destroy', 'coredump-restart')
310 CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
311 'crashed', 'dying')
313 class XendConfigError(VmError):
314 def __str__(self):
315 return 'Invalid Configuration: %s' % str(self.value)
317 ##
318 ## XendConfig Class (an extended dictionary)
319 ##
321 class XendConfig(dict):
322 """ The new Xend VM Configuration.
324 Stores the configuration in xenapi compatible format but retains
325 import and export functions for SXP.
326 """
327 def __init__(self, filename = None, sxp_obj = None,
328 xapi = None, dominfo = None):
330 dict.__init__(self)
331 self.update(self._defaults())
333 if filename:
334 try:
335 sxp_obj = sxp.parse(open(filename,'r'))
336 sxp_obj = sxp_obj[0]
337 except IOError, e:
338 raise XendConfigError("Unable to read file: %s" % filename)
340 if sxp_obj:
341 self._sxp_to_xapi(sxp_obj)
342 self._sxp_to_xapi_unsupported(sxp_obj)
343 elif xapi:
344 self.update_with_xenapi_config(xapi)
345 elif dominfo:
346 # output from xc.domain_getinfo
347 self._dominfo_to_xapi(dominfo, update_mem = True)
349 self.handle_fileuris()
351 log.debug('XendConfig.init: %s' % scrub_password(self))
353 # validators go here
354 self.validate()
356 """ In time, we should enable this type checking addition. It is great
357 also for tracking bugs and unintended writes to XendDomainInfo.info
358 def __setitem__(self, key, value):
359 type_conv = XENAPI_CFG_TYPES.get(key)
360 if callable(type_conv):
361 try:
362 dict.__setitem__(self, key, type_conv(value))
363 except (ValueError, TypeError):
364 raise XendConfigError("Wrong type for configuration value " +
365 "%s. Expected %s" %
366 (key, type_conv.__name__))
367 else:
368 dict.__setitem__(self, key, value)
369 """
371 def _defaults(self):
372 defaults = {
373 'name_label': 'Domain-Unnamed',
374 'actions_after_shutdown': 'destroy',
375 'actions_after_reboot': 'restart',
376 'actions_after_crash': 'restart',
377 'actions_after_suspend': '',
378 'is_a_template': False,
379 'auto_power_on': False,
380 'is_control_domain': False,
381 'features': '',
382 'PV_bootloader': '',
383 'PV_kernel': '',
384 'PV_ramdisk': '',
385 'PV_args': '',
386 'PV_bootloader_args': '',
387 'HVM_boot_policy': '',
388 'HVM_boot_params': {},
389 'memory_static_min': 0,
390 'memory_dynamic_min': 0,
391 'shadow_memory': 0,
392 'memory_static_max': 0,
393 'memory_dynamic_max': 0,
394 'memory_sharing': 0,
395 'devices': {},
396 'on_xend_start': 'ignore',
397 'on_xend_stop': 'ignore',
398 'cpus': [],
399 'VCPUs_max': 1,
400 'VCPUs_live': 1,
401 'VCPUs_at_startup': 1,
402 'vcpus_params': {},
403 'console_refs': [],
404 'vif_refs': [],
405 'vbd_refs': [],
406 'vtpm_refs': [],
407 'other_config': {},
408 'platform': {},
409 'target': 0,
410 'superpages': 0,
411 'description': '',
412 }
414 return defaults
416 #
417 # Here we assume these values exist in the dict.
418 # If they don't we have a bigger problem, lets not
419 # try and 'fix it up' but acutually fix the cause ;-)
420 #
421 def _memory_sanity_check(self):
422 log.trace("_memory_sanity_check memory_static_min: %s, "
423 "memory_static_max: %i, "
424 "memory_dynamic_min: %i, "
425 "memory_dynamic_max: %i",
426 self["memory_static_min"],
427 self["memory_static_max"],
428 self["memory_dynamic_min"],
429 self["memory_dynamic_max"])
431 if not self["memory_static_min"] <= self["memory_static_max"]:
432 raise XendConfigError("memory_static_min must be less " \
433 "than or equal to memory_static_max")
434 if not self["memory_static_min"] <= self["memory_dynamic_min"]:
435 raise XendConfigError("memory_static_min must be less " \
436 "than or equal to memory_dynamic_min")
437 if not self["memory_dynamic_max"] <= self["memory_static_max"]:
438 raise XendConfigError("memory_dynamic_max must be less " \
439 "than or equal to memory_static_max")
440 if not self["memory_dynamic_max"] > 0:
441 raise XendConfigError("memory_dynamic_max must be greater " \
442 "than zero")
443 if not self["memory_static_max"] > 0:
444 raise XendConfigError("memory_static_max must be greater " \
445 "than zero")
446 if self["memory_sharing"] and not self.is_hvm():
447 raise XendConfigError("memory_sharing can only be enabled " \
448 "for HVM domains")
449 if self["memory_sharing"] and not self.is_hap():
450 raise XendConfigError("memory_sharing can only be enabled " \
451 "for HAP enabled boxes")
453 def _actions_sanity_check(self):
454 for event in ['shutdown', 'reboot', 'crash']:
455 if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
456 raise XendConfigError('Invalid event handling mode: ' +
457 event)
459 def _vcpus_sanity_check(self):
460 if 'VCPUs_max' in self and 'vcpu_avail' not in self:
461 self['vcpu_avail'] = (1 << self['VCPUs_max']) - 1
462 if 'online_vcpus' in self:
463 self['VCPUs_live'] = self['online_vcpus']
465 def _uuid_sanity_check(self):
466 """Make sure UUID is in proper string format with hyphens."""
467 if 'uuid' not in self or not self['uuid']:
468 self['uuid'] = uuid.createString()
469 else:
470 self['uuid'] = uuid.toString(uuid.fromString(self['uuid']))
472 def _name_sanity_check(self):
473 if 'name_label' not in self:
474 self['name_label'] = 'Domain-' + self['uuid']
476 def _platform_sanity_check(self):
477 if 'keymap' not in self['platform'] and XendOptions.instance().get_keymap():
478 self['platform']['keymap'] = XendOptions.instance().get_keymap()
480 if self.is_hvm() or self.has_rfb():
481 if 'device_model' not in self['platform']:
482 self['platform']['device_model'] = auxbin.pathTo("qemu-dm")
483 # device_model may be set to 'qemu-dm' or 'stubdom-dm' w/o a path
484 if os.path.dirname(self['platform']['device_model']) == "":
485 self['platform']['device_model'] = \
486 auxbin.pathTo(self['platform']['device_model'])
487 if not os.path.exists(self['platform']['device_model']):
488 raise VmError("device model '%s' not found" % str(self['platform']['device_model']))
490 if 'tsc_mode' not in self['platform']:
491 self['platform']['tsc_mode'] = 0
493 if 'nomigrate' not in self['platform']:
494 self['platform']['nomigrate'] = 0
496 if self.is_hvm():
497 if 'timer_mode' not in self['platform']:
498 self['platform']['timer_mode'] = 1
499 if 'viridian' not in self['platform']:
500 self['platform']['viridian'] = 0
501 if 'rtc_timeoffset' not in self['platform']:
502 self['platform']['rtc_timeoffset'] = 0
503 if 'hpet' not in self['platform']:
504 self['platform']['hpet'] = 0
505 if 'xen_platform_pci' not in self['platform']:
506 self['platform']['xen_platform_pci'] = 1
507 if 'vpt_align' not in self['platform']:
508 self['platform']['vpt_align'] = 1
509 if 'loader' not in self['platform']:
510 # Old configs may have hvmloader set as PV_kernel param
511 if self.has_key('PV_kernel') and self['PV_kernel'] != '':
512 if self['PV_kernel'] == 'hvmloader':
513 self['PV_kernel'] = auxbin.pathTo("hvmloader")
514 self['platform']['loader'] = self['PV_kernel']
515 self['PV_kernel'] = ''
516 else:
517 self['platform']['loader'] = auxbin.pathTo("hvmloader")
518 log.debug("Loader is %s" % str(self['platform']['loader']))
519 elif self['platform']['loader'] == 'hvmloader':
520 self['platform']['loader'] = auxbin.pathTo("hvmloader")
521 if not os.path.exists(self['platform']['loader']):
522 raise VmError("kernel '%s' not found" % str(self['platform']['loader']))
524 # Compatibility hack, can go away soon.
525 if 'soundhw' not in self['platform'] and \
526 self['platform'].get('enable_audio'):
527 self['platform']['soundhw'] = 'sb16'
529 def _vfb_sanity_check(self):
530 if 'keymap' in self['platform']:
531 for con in self['console_refs']:
532 if self['devices'][con][0] == 'vfb':
533 if 'keymap' not in self['devices'][con][1]:
534 self['devices'][con][1]['keymap'] = \
535 self['platform']['keymap']
537 def validate(self):
538 self._uuid_sanity_check()
539 self._name_sanity_check()
540 self._memory_sanity_check()
541 self._actions_sanity_check()
542 self._vcpus_sanity_check()
543 self._platform_sanity_check()
544 self._vfb_sanity_check()
546 def _dominfo_to_xapi(self, dominfo, update_mem = False):
547 self['domid'] = dominfo['domid']
548 self['online_vcpus'] = dominfo['online_vcpus']
549 self['VCPUs_max'] = dominfo['max_vcpu_id'] + 1
551 if update_mem:
552 self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
553 self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
554 self['memory_static_min'] = 0
555 self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
556 self._memory_sanity_check()
558 self['cpu_time'] = dominfo['cpu_time']/1e9
559 if dominfo.get('ssidref'):
560 ssidref = int(dominfo.get('ssidref'))
561 import xen.util.xsm.xsm as security
562 self['security_label'] = security.ssidref2security_label(ssidref)
564 self['shutdown_reason'] = dominfo['shutdown_reason']
566 # parse state into Xen API states
567 self['running'] = dominfo['running']
568 self['crashed'] = dominfo['crashed']
569 self['dying'] = dominfo['dying']
570 self['shutdown'] = dominfo['shutdown']
571 self['paused'] = dominfo['paused']
572 self['blocked'] = dominfo['blocked']
574 if 'name' in dominfo:
575 self['name_label'] = dominfo['name']
577 if 'handle' in dominfo:
578 self['uuid'] = uuid.toString(dominfo['handle'])
580 def _convert_cpus_to_list(self, s):
581 # Convert the following string to list of ints.
582 # The string supports a list of ranges (0-3),
583 # seperated by commas, and negation (^1).
584 # Precedence is settled by order of the string:
585 # "0-3,^1" -> [0,2,3]
586 # "0-3,^1,1" -> [0,1,2,3]
587 l = []
588 if s == "":
589 return l
590 for c in s.split(','):
591 if c.find('-') != -1:
592 (x, y) = c.split('-')
593 for i in range(int(x), int(y)+1):
594 l.append(int(i))
595 else:
596 # remove this element from the list
597 if c[0] == '^':
598 l = [x for x in l if x != int(c[1:])]
599 else:
600 l.append(int(c))
601 return l
603 def parse_cpuid(self, cfg, field):
604 def int2bin(n, count=32):
605 return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
607 for input, regs in cfg[field].iteritems():
608 if not regs is dict:
609 cfg[field][input] = dict(regs)
611 cpuid = {}
612 for input in cfg[field]:
613 inputs = input.split(',')
614 if inputs[0][0:2] == '0x':
615 inputs[0] = str(int(inputs[0], 16))
616 if len(inputs) == 2:
617 if inputs[1][0:2] == '0x':
618 inputs[1] = str(int(inputs[1], 16))
619 new_input = ','.join(inputs)
620 cpuid[new_input] = {} # new input
621 for reg in cfg[field][input]:
622 val = cfg[field][input][reg]
623 if val[0:2] == '0x':
624 cpuid[new_input][reg] = int2bin(int(val, 16))
625 else:
626 cpuid[new_input][reg] = val
627 cfg[field] = cpuid
629 def _parse_sxp(self, sxp_cfg):
630 """ Populate this XendConfig using the parsed SXP.
632 @param sxp_cfg: Parsed SXP Configuration
633 @type sxp_cfg: list of lists
634 @rtype: dictionary
635 @return: A dictionary containing the parsed options of the SXP.
636 """
637 cfg = {}
639 for key, typ in XENAPI_CFG_TYPES.items():
640 val = sxp.child_value(sxp_cfg, key)
641 if val is not None:
642 try:
643 cfg[key] = typ(val)
644 except (ValueError, TypeError), e:
645 log.warn('Unable to convert type value for key: %s' % key)
647 # Convert deprecated options to current equivalents.
649 restart = sxp.child_value(sxp_cfg, 'restart')
650 if restart:
651 if restart == 'onreboot':
652 cfg['on_poweroff'] = 'destroy'
653 cfg['on_reboot'] = 'restart'
654 cfg['on_crash'] = 'destroy'
655 elif restart == 'always':
656 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
657 cfg[opt] = 'restart'
658 elif restart == 'never':
659 for opt in ('on_poweroff', 'on_reboot', 'on_crash'):
660 cfg[opt] = 'never'
661 else:
662 log.warn('Ignoring unrecognised value for deprecated option:'
663 'restart = \'%s\'', restart)
665 # Handle memory, passed in as MiB
667 if sxp.child_value(sxp_cfg, "memory") != None:
668 cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
669 if sxp.child_value(sxp_cfg, "maxmem") != None:
670 cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
672 # Convert scheduling parameters to vcpus_params
673 if 'vcpus_params' not in cfg:
674 cfg['vcpus_params'] = {}
675 cfg["vcpus_params"]["weight"] = \
676 int(sxp.child_value(sxp_cfg, "cpu_weight", 256))
677 cfg["vcpus_params"]["cap"] = \
678 int(sxp.child_value(sxp_cfg, "cpu_cap", 0))
680 # Only extract options we know about.
681 extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG + \
682 XENAPI_CFG_TO_LEGACY_CFG.values()
684 for key in extract_keys:
685 val = sxp.child_value(sxp_cfg, key)
686 if val != None:
687 try:
688 cfg[key] = LEGACY_CFG_TYPES[key](val)
689 except KeyError:
690 cfg[key] = val
691 except (TypeError, ValueError), e:
692 log.warn("Unable to parse key %s: %s: %s" %
693 (key, str(val), e))
695 if 'platform' not in cfg:
696 cfg['platform'] = {}
697 localtime = sxp.child_value(sxp_cfg, 'localtime')
698 if localtime is not None:
699 cfg['platform']['localtime'] = localtime
701 # Compatibility hack -- can go soon.
702 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
703 val = sxp.child_value(sxp_cfg, "platform_" + key, None)
704 if val is not None:
705 self['platform'][key] = val
707 # Compatibility hack -- can go soon.
708 boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
709 if boot_order:
710 cfg['HVM_boot_policy'] = 'BIOS order'
711 cfg['HVM_boot_params'] = { 'order' : boot_order }
714 # Parsing the device SXP's.
715 cfg['devices'] = {}
716 for dev in sxp.children(sxp_cfg, 'device'):
717 config = sxp.child0(dev)
718 dev_type = sxp.name(config)
719 self.device_add(dev_type, cfg_sxp = config, target = cfg)
721 # Extract missing data from configuration entries
722 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
723 if image_sxp:
724 image_vcpus = sxp.child_value(image_sxp, 'vcpus')
725 if image_vcpus != None:
726 try:
727 if 'VCPUs_max' not in cfg:
728 cfg['VCPUs_max'] = int(image_vcpus)
729 elif cfg['VCPUs_max'] != int(image_vcpus):
730 cfg['VCPUs_max'] = int(image_vcpus)
731 log.warn('Overriding vcpus from %d to %d using image'
732 'vcpus value.', cfg['VCPUs_max'])
733 except ValueError, e:
734 raise XendConfigError('integer expeceted: %s: %s' %
735 image_sxp, e)
737 # Deprecated cpu configuration
738 if 'cpu' in cfg:
739 if 'cpus' in cfg:
740 cfg['cpus'] = "%s,%s" % (str(cfg['cpu']), cfg['cpus'])
741 else:
742 cfg['cpus'] = str(cfg['cpu'])
744 # Convert 'cpus' to list of list of ints
745 cpus_list = []
746 if 'cpus' in cfg:
747 if type(cfg['cpus']) == list:
748 if len(cfg['cpus']) > 0 and type(cfg['cpus'][0]) == list:
749 # If sxp_cfg was created from config.sxp,
750 # the form of 'cpus' is list of list of string.
751 # Convert 'cpus' to list of list of ints.
752 # Conversion examples:
753 # [['1']] -> [[1]]
754 # [['0','2'],['1','3']] -> [[0,2],[1,3]]
755 try:
756 for c1 in cfg['cpus']:
757 cpus = []
758 for c2 in c1:
759 cpus.append(int(c2))
760 cpus_list.append(cpus)
761 except ValueError, e:
762 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
763 else:
764 # Conversion examples:
765 # ["1"] -> [[1]]
766 # ["0,2","1,3"] -> [[0,2],[1,3]]
767 # ["0-3,^1","1-4,^2"] -> [[0,2,3],[1,3,4]]
768 try:
769 for c in cfg['cpus']:
770 cpus = self._convert_cpus_to_list(c)
771 cpus_list.append(cpus)
772 except ValueError, e:
773 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
775 if len(cpus_list) != cfg['vcpus']:
776 raise XendConfigError('vcpus and the item number of cpus are not same')
777 else:
778 # Conversion examples:
779 # vcpus=1:
780 # "1" -> [[1]]
781 # "0-3,^1" -> [[0,2,3]]
782 # vcpus=2:
783 # "1" -> [[1],[1]]
784 # "0-3,^1" -> [[0,2,3],[0,2,3]]
785 try:
786 cpus = self._convert_cpus_to_list(cfg['cpus'])
787 for v in range(0, cfg['vcpus']):
788 cpus_list.append(cpus)
789 except ValueError, e:
790 raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
791 else:
792 # Generation examples:
793 # vcpus=1:
794 # -> [[]]
795 # vcpus=2:
796 # -> [[],[]]
797 for v in range(0, cfg['vcpus']):
798 cpus_list.append(list())
800 cfg['cpus'] = cpus_list
802 # Parse cpuid
803 if 'cpuid' in cfg:
804 self.parse_cpuid(cfg, 'cpuid')
805 if 'cpuid_check' in cfg:
806 self.parse_cpuid(cfg, 'cpuid_check')
808 import xen.util.xsm.xsm as security
809 if security.on() == xsconstants.XS_POLICY_USE:
810 from xen.util.acmpolicy import ACM_LABEL_UNLABELED
811 if not 'security' in cfg and sxp.child_value(sxp_cfg, 'security'):
812 cfg['security'] = sxp.child_value(sxp_cfg, 'security')
813 elif not cfg.get('security_label'):
814 cfg['security'] = [['access_control',
815 ['policy', security.get_active_policy_name() ],
816 ['label', ACM_LABEL_UNLABELED ]]]
818 if 'security' in cfg and not cfg.get('security_label'):
819 secinfo = cfg['security']
820 # The xm command sends a list formatted like this:
821 # [['access_control', ['policy', 'xm-test'],['label', 'red']],
822 # ['ssidref', 196611]]
823 policy = ""
824 label = ""
825 for idx in range(0, len(secinfo)):
826 if secinfo[idx][0] == "access_control":
827 for aidx in range(1, len(secinfo[idx])):
828 if secinfo[idx][aidx][0] == "policy":
829 policy = secinfo[idx][aidx][1]
830 if secinfo[idx][aidx][0] == "label":
831 label = secinfo[idx][aidx][1]
832 cfg['security_label'] = \
833 security.set_security_label(policy, label)
834 if not sxp.child_value(sxp_cfg, 'security_label'):
835 del cfg['security']
837 old_state = sxp.child_value(sxp_cfg, 'state')
838 if old_state:
839 for i in range(len(CONFIG_OLD_DOM_STATES)):
840 cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
842 return cfg
845 def _sxp_to_xapi(self, sxp_cfg):
846 """Read in an SXP Configuration object and
847 populate at much of the Xen API with valid values.
848 """
849 log.debug('_sxp_to_xapi(%s)' % scrub_password(sxp_cfg))
851 # _parse_sxp() below will call device_add() and construct devices.
852 # Some devices may require VM's uuid, so setup self['uuid']
853 # beforehand.
854 self['uuid'] = sxp.child_value(sxp_cfg, 'uuid', uuid.createString())
856 cfg = self._parse_sxp(sxp_cfg)
858 for key, typ in XENAPI_CFG_TYPES.items():
859 val = cfg.get(key)
860 if val is not None:
861 self[key] = typ(val)
863 # Convert parameters that can be directly mapped from
864 # the Legacy Config to Xen API Config
866 for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
867 try:
868 type_conv = XENAPI_CFG_TYPES.get(apikey)
869 if callable(type_conv):
870 self[apikey] = type_conv(cfg[cfgkey])
871 else:
872 log.warn("Unconverted key: " + apikey)
873 self[apikey] = cfg[cfgkey]
874 except KeyError:
875 pass
877 # Lets try and handle memory correctly
879 MiB = 1024 * 1024
881 if "memory" in cfg:
882 self["memory_static_min"] = 0
883 self["memory_static_max"] = int(cfg["memory"]) * MiB
884 self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
885 self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
887 if "maxmem" in cfg:
888 self["memory_static_max"] = int(cfg["maxmem"]) * MiB
890 self._memory_sanity_check()
892 def update_with(n, o):
893 if not self.get(n):
894 self[n] = cfg.get(o, '')
896 update_with('PV_bootloader', 'bootloader')
897 update_with('PV_bootloader_args', 'bootloader_args')
898 update_with('Description', 'description')
900 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
901 if image_sxp:
902 self.update_with_image_sxp(image_sxp)
904 # Convert Legacy HVM parameters to Xen API configuration
905 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
906 if key in cfg:
907 self['platform'][key] = cfg[key]
909 # set device references in the configuration
910 self['devices'] = cfg.get('devices', {})
911 self['console_refs'] = cfg.get('console_refs', [])
912 self['vif_refs'] = cfg.get('vif_refs', [])
913 self['vbd_refs'] = cfg.get('vbd_refs', [])
914 self['vtpm_refs'] = cfg.get('vtpm_refs', [])
916 # coalesce hvm vnc frame buffer with vfb config
917 if self.is_hvm() and int(self['platform'].get('vnc', 0)) != 0:
918 # add vfb device if it isn't there already
919 if not self.has_rfb():
920 dev_config = ['vfb']
921 dev_config.append(['vnc', '1'])
922 # copy VNC related params from platform config to vfb dev conf
923 for key in ['vncpasswd', 'vncunused', 'vncdisplay',
924 'vnclisten', 'keymap']:
925 if key in self['platform']:
926 dev_config.append([key, self['platform'][key]])
928 self.device_add('vfb', cfg_sxp = dev_config)
931 def has_rfb(self):
932 for console_uuid in self['console_refs']:
933 if self['devices'][console_uuid][1].get('protocol') == 'rfb':
934 return True
935 if self['devices'][console_uuid][0] == 'vfb':
936 return True
937 return False
939 def _sxp_to_xapi_unsupported(self, sxp_cfg):
940 """Read in an SXP configuration object and populate
941 values are that not related directly supported in
942 the Xen API.
943 """
945 log.debug('_sxp_to_xapi_unsupported(%s)' % scrub_password(sxp_cfg))
947 # Parse and convert parameters used to configure
948 # the image (as well as HVM images)
949 image_sxp = sxp.child_value(sxp_cfg, 'image', [])
950 if image_sxp:
951 image_type = sxp.name(image_sxp)
952 if image_type != 'hvm' and image_type != 'linux':
953 self['platform']['image_type'] = image_type
955 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
956 val = sxp.child_value(image_sxp, key, None)
957 if val is not None and val != '':
958 self['platform'][key] = val
960 notes = sxp.children(image_sxp, 'notes')
961 if notes:
962 self['notes'] = self.notes_from_sxp(notes[0])
964 self._hvm_boot_params_from_sxp(image_sxp)
966 # extract backend value
968 backend = []
969 for c in sxp.children(sxp_cfg, 'backend'):
970 backend.append(sxp.name(sxp.child0(c)))
971 if backend:
972 self['backend'] = backend
974 # Parse and convert other Non Xen API parameters.
975 def _set_cfg_if_exists(sxp_arg):
976 val = sxp.child_value(sxp_cfg, sxp_arg)
977 if val != None:
978 if LEGACY_CFG_TYPES.get(sxp_arg):
979 self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
980 else:
981 self[sxp_arg] = val
983 _set_cfg_if_exists('shadow_memory')
984 _set_cfg_if_exists('features')
985 _set_cfg_if_exists('on_xend_stop')
986 _set_cfg_if_exists('on_xend_start')
987 _set_cfg_if_exists('vcpu_avail')
988 _set_cfg_if_exists('change_home_server')
989 _set_cfg_if_exists('description')
991 # Parse and store runtime configuration
992 _set_cfg_if_exists('start_time')
993 _set_cfg_if_exists('cpu_time')
994 _set_cfg_if_exists('shutdown_reason')
995 _set_cfg_if_exists('up_time')
996 _set_cfg_if_exists('status') # TODO, deprecated
998 def _get_old_state_string(self):
999 """Returns the old xm state string.
1000 @rtype: string
1001 @return: old state string
1002 """
1003 state_string = ''
1004 for state_name in CONFIG_OLD_DOM_STATES:
1005 on_off = self.get(state_name, 0)
1006 if on_off:
1007 state_string += state_name[0]
1008 else:
1009 state_string += '-'
1011 return state_string
1014 def update_config(self, dominfo):
1015 """Update configuration with the output from xc.domain_getinfo().
1017 @param dominfo: Domain information via xc.domain_getinfo()
1018 @type dominfo: dict
1019 """
1020 self._dominfo_to_xapi(dominfo)
1021 self.validate()
1023 def update_with_xenapi_config(self, xapi):
1024 """Update configuration with a Xen API VM struct
1026 @param xapi: Xen API VM Struct
1027 @type xapi: dict
1028 """
1030 log.debug('update_with_xenapi_config: %s' % scrub_password(xapi))
1032 for key, val in xapi.items():
1033 type_conv = XENAPI_CFG_TYPES.get(key)
1034 if type_conv is None:
1035 key = key.lower()
1036 type_conv = XENAPI_CFG_TYPES.get(key)
1037 if callable(type_conv):
1038 self[key] = type_conv(val)
1039 else:
1040 self[key] = val
1042 # XenAPI defines platform as a string-string map. If platform
1043 # configuration exists, convert values to appropriate type.
1044 if 'platform' in xapi:
1045 for key, val in xapi['platform'].items():
1046 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1047 if type_conv is None:
1048 key = key.lower()
1049 type_conv = XENAPI_PLATFORM_CFG_TYPES.get(key)
1050 if callable(type_conv):
1051 self['platform'][key] = type_conv(val)
1052 else:
1053 self['platform'][key] = val
1055 self['vcpus_params']['weight'] = \
1056 int(self['vcpus_params'].get('weight', 256))
1057 self['vcpus_params']['cap'] = \
1058 int(self['vcpus_params'].get('cap', 0))
1060 for key, val in self['vcpus_params'].items():
1061 if key.startswith('cpumap'):
1062 self['vcpus_params'][key] = \
1063 ','.join(map(str, self._convert_cpus_to_list(val)))
1065 def cpuid_to_sxp(self, sxpr, field):
1066 regs_list = []
1067 for input, regs in self[field].iteritems():
1068 reg_list = []
1069 for reg, val in regs.iteritems():
1070 reg_list.append([reg, val])
1071 regs_list.append([input, reg_list])
1072 sxpr.append([field, regs_list])
1075 def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
1076 legacy_only = True):
1077 """ Get SXP representation of this config object.
1079 Incompat: removed store_mfn, console_mfn
1081 @keyword domain: (optional) XendDomainInfo to get extra information
1082 from such as domid and running devices.
1083 @type domain: XendDomainInfo
1084 @keyword ignore: (optional) list of 'keys' that we do not want
1085 to export.
1086 @type ignore: list of strings
1087 @rtype: list of list (SXP representation)
1088 """
1089 sxpr = ['domain']
1091 # TODO: domid/dom is the same thing but called differently
1092 # depending if it is from xenstore or sxpr.
1094 if domain.getDomid() is not None:
1095 sxpr.append(['domid', domain.getDomid()])
1097 if legacy_only:
1098 sxpr.append(['cpu_weight', int(self['vcpus_params'].get('weight', 256))])
1099 sxpr.append(['cpu_cap', int(self['vcpus_params'].get('cap', 0))])
1100 else:
1101 for name, typ in XENAPI_CFG_TYPES.items():
1102 if name in self and self[name] not in (None, []):
1103 if typ == dict:
1104 s = self[name].items()
1105 elif typ == list:
1106 s = self[name]
1107 else:
1108 s = str(self[name])
1109 sxpr.append([name, s])
1111 for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
1112 if self.has_key(xenapi) and self[xenapi] not in (None, []):
1113 if type(self[xenapi]) == bool:
1114 # convert booleans to ints before making an sxp item
1115 sxpr.append([legacy, int(self[xenapi])])
1116 else:
1117 sxpr.append([legacy, self[xenapi]])
1119 MiB = 1024*1024
1121 sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
1122 sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
1124 for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
1125 if legacy in ('domid', 'uuid', 'cpus'): # skip these
1126 continue
1127 if self.has_key(legacy) and self[legacy] not in (None, []):
1128 sxpr.append([legacy, self[legacy]])
1130 if self.has_key('security_label'):
1131 sxpr.append(['security_label', self['security_label']])
1133 sxpr.append(['image', self.image_sxpr()])
1134 sxpr.append(['status', domain._stateGet()])
1136 if domain.getDomid() is not None:
1137 sxpr.append(['state', self._get_old_state_string()])
1139 if domain:
1140 if domain.store_mfn:
1141 sxpr.append(['store_mfn', domain.store_mfn])
1142 if domain.console_mfn:
1143 sxpr.append(['console_mfn', domain.console_mfn])
1146 # Marshall devices (running or from configuration)
1147 if not ignore_devices:
1148 txn = xstransact()
1149 try:
1150 for cls in XendDevices.valid_devices():
1151 found = False
1153 # figure if there is a dev controller is valid and running
1154 if domain and domain.getDomid() != None:
1155 try:
1156 controller = domain.getDeviceController(cls)
1157 configs = controller.configurations(txn)
1158 for config in configs:
1159 if sxp.name(config) in ('vbd', 'tap', 'tap2'):
1160 dev_uuid = sxp.child_value(config, 'uuid')
1161 dev_type, dev_cfg = self['devices'][dev_uuid]
1162 if sxp.child_value(config, 'bootable', None) is None:
1163 is_bootable = dev_cfg.get('bootable', 0)
1164 config.append(['bootable', int(is_bootable)])
1165 config.append(['VDI', dev_cfg.get('VDI', '')])
1167 sxpr.append(['device', config])
1169 found = True
1170 except:
1171 log.exception("dumping sxp from device controllers")
1172 pass
1174 # if we didn't find that device, check the existing config
1175 # for a device in the same class
1176 if not found:
1177 for dev_type, dev_info in self.all_devices_sxpr():
1178 if dev_type == cls:
1179 sxpr.append(['device', dev_info])
1181 txn.commit()
1182 except:
1183 txn.abort()
1184 raise
1186 if 'cpuid' in self:
1187 self.cpuid_to_sxp(sxpr, 'cpuid')
1188 if 'cpuid_check' in self:
1189 self.cpuid_to_sxp(sxpr, 'cpuid_check')
1191 if self.has_key('change_home_server'):
1192 sxpr.append(['change_home_server', self['change_home_server']])
1194 log.debug(sxpr)
1196 return sxpr
1198 def _blkdev_name_to_number(self, dev):
1199 if 'ioemu:' in dev:
1200 _, dev = dev.split(':', 1)
1201 try:
1202 dev, _ = dev.split(':', 1)
1203 except ValueError:
1204 pass
1206 try:
1207 devid = int(dev)
1208 except ValueError:
1209 # devid is not a number but a string containing either device
1210 # name (e.g. xvda) or device_type/device_id (e.g. vbd/51728)
1211 dev2 = type(dev) is str and dev.split('/')[-1] or None
1212 if dev2 == None:
1213 log.debug("Could not check the device %s", dev)
1214 return None
1215 try:
1216 devid = int(dev2)
1217 except ValueError:
1218 (xenbus, devid) = blkdev_name_to_number(dev2)
1219 if devid == None:
1220 log.debug("The device %s is not device name", dev2)
1221 return None
1222 return devid
1224 def device_duplicate_check(self, dev_type, dev_info, defined_config, config):
1225 defined_devices_sxpr = self.all_devices_sxpr(target = defined_config)
1227 if dev_type == 'vbd' or dev_type == 'tap' or dev_type == 'tap2':
1228 dev_uname = dev_info.get('uname')
1229 blkdev_name = dev_info.get('dev')
1230 devid = self._blkdev_name_to_number(blkdev_name)
1231 if devid == None or dev_uname == None:
1232 return
1234 for o_dev_type, o_dev_info in defined_devices_sxpr:
1235 if o_dev_type == 'vbd' or o_dev_type == 'tap' or o_dev_type == 'tap2':
1236 blkdev_file = blkdev_uname_to_file(dev_uname)
1237 o_dev_uname = sxp.child_value(o_dev_info, 'uname')
1238 if o_dev_uname and o_dev_uname != None:
1239 o_blkdev_file = blkdev_uname_to_file(o_dev_uname)
1240 if blkdev_file == o_blkdev_file:
1241 raise XendConfigError('The file "%s" is already used' %
1242 blkdev_file)
1243 if dev_uname and dev_uname == o_dev_uname:
1244 raise XendConfigError('The uname "%s" is already defined' %
1245 dev_uname)
1246 o_blkdev_name = sxp.child_value(o_dev_info, 'dev')
1247 o_devid = self._blkdev_name_to_number(o_blkdev_name)
1248 if o_devid != None and devid == o_devid:
1249 name_array = blkdev_name.split(':', 2)
1250 if len(name_array) == 2 and name_array[1] == 'cdrom':
1252 # Since the device is a cdrom, we are most likely
1253 # inserting, changing, or removing a cd. We can
1254 # update the old device instead of creating a new
1255 # one.
1257 if o_dev_uname != None and dev_uname == None:
1259 # We are removing a cd. We can simply update
1260 # the uname on the existing device.
1262 merge_sxp = sxp.from_string("('vbd' ('uname' ''))")
1263 else:
1264 merge_sxp = config
1266 dev_uuid = sxp.child_value(o_dev_info, 'uuid')
1267 if dev_uuid != None and \
1268 self.device_update(dev_uuid, cfg_sxp = merge_sxp):
1269 return dev_uuid
1271 raise XendConfigError('The device "%s" is already defined' %
1272 blkdev_name)
1274 elif dev_type == 'vif':
1275 dev_mac = dev_info.get('mac')
1277 for o_dev_type, o_dev_info in defined_devices_sxpr:
1278 if dev_type == o_dev_type:
1279 if dev_mac.lower() == sxp.child_value(o_dev_info, 'mac').lower():
1280 raise XendConfigError('The mac "%s" is already defined' %
1281 dev_mac)
1282 return None
1284 def create_dpci_from_sxp(self, pci_devs):
1285 for pci_dev in pci_devs:
1286 dpci_uuid = pci_dev.get('uuid')
1287 log.debug("create_dpci_from_sxp: %s" % pci_dev)
1288 ppci_uuid = XendPPCI.get_by_sbdf(pci_dev['domain'],
1289 pci_dev['bus'],
1290 pci_dev['slot'],
1291 pci_dev['func'])
1292 if ppci_uuid is None:
1293 continue
1294 dpci_record = {
1295 'VM': self['uuid'],
1296 'PPCI': ppci_uuid,
1297 'hotplug_slot': pci_dev.get('vdevfn', '0x%02x' % AUTO_PHP_SLOT),
1298 'key': pci_dev['key']
1301 dpci_opts = pci_dev.get('opts')
1302 if dpci_opts and len(dpci_opts) > 0:
1303 dpci_record['options'] = dpci_opts
1305 XendDPCI(dpci_uuid, dpci_record)
1307 def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None,
1308 target = None):
1309 """Add a device configuration in SXP format or XenAPI struct format.
1311 For SXP, it could be either:
1313 [device, [vbd, [uname ...]]
1315 or:
1317 [vbd, [uname ..]]
1319 @type cfg_sxp: list of lists (parsed sxp object)
1320 @param cfg_sxp: SXP configuration object
1321 @type cfg_xenapi: dict
1322 @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
1323 @param target: write device information to
1324 @type target: None or a dictionary
1325 @rtype: string
1326 @return: Assigned UUID of the device.
1327 """
1328 if target == None:
1329 target = self
1331 if dev_type not in XendDevices.valid_devices():
1332 raise XendConfigError("XendConfig: %s not a valid device type" %
1333 dev_type)
1335 if cfg_sxp == None and cfg_xenapi == None:
1336 raise XendConfigError("XendConfig: device_add requires some "
1337 "config.")
1339 #if cfg_sxp:
1340 # log.debug("XendConfig.device_add: %s" % str(cfg_sxp))
1341 #if cfg_xenapi:
1342 # log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
1344 if cfg_sxp:
1345 if sxp.child0(cfg_sxp) == 'device':
1346 config = sxp.child0(cfg_sxp)
1347 else:
1348 config = cfg_sxp
1350 dev_type = sxp.name(config)
1351 dev_info = {}
1353 if dev_type == 'pci':
1354 pci_devs_uuid = sxp.child_value(config, 'uuid',
1355 uuid.createString())
1357 pci_dict = pci_convert_sxp_to_dict(config)
1358 pci_devs = pci_dict['devs']
1360 # create XenAPI DPCI objects.
1361 self.create_dpci_from_sxp(pci_devs)
1363 target['devices'][pci_devs_uuid] = (dev_type,
1364 {'devs': pci_devs,
1365 'uuid': pci_devs_uuid})
1367 log.debug("XendConfig: reading device: %s" % pci_devs)
1369 return pci_devs_uuid
1371 if dev_type == 'vscsi':
1372 vscsi_devs_uuid = sxp.child_value(config, 'uuid',
1373 uuid.createString())
1374 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1375 vscsi_devs = vscsi_dict['devs']
1376 vscsi_mode = vscsi_dict['feature-host']
1377 vscsi_be = vscsi_dict.get('backend', None)
1379 # create XenAPI DSCSI_HBA objects.
1380 dscsi_HBA_record = {
1381 'VM': self['uuid'],
1382 'virtual_host': int(vscsi_devs[0]['v-dev'].split(':')[0]),
1383 'assignment_mode': vscsi_mode and 'HOST' or 'LUN'
1385 XendDSCSI_HBA(vscsi_devs_uuid, dscsi_HBA_record)
1387 # create XenAPI DSCSI objects.
1388 for vscsi_dev in vscsi_devs:
1389 dscsi_uuid = vscsi_dev.get('uuid')
1390 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1391 if pscsi_uuid is None:
1392 continue
1393 dscsi_record = {
1394 'VM': self['uuid'],
1395 'PSCSI': pscsi_uuid,
1396 'HBA': vscsi_devs_uuid,
1397 'virtual_HCTL': vscsi_dev.get('v-dev')
1399 XendDSCSI(dscsi_uuid, dscsi_record)
1401 vscsi_info = {
1402 'devs': vscsi_devs,
1403 'feature-host': vscsi_mode,
1404 'uuid': vscsi_devs_uuid
1406 if vscsi_be is not None:
1407 vscsi_info['backend'] = vscsi_be
1408 target['devices'][vscsi_devs_uuid] = (dev_type, vscsi_info)
1409 log.debug("XendConfig: reading device: %s,%s" % \
1410 (vscsi_devs, vscsi_mode))
1411 return vscsi_devs_uuid
1413 if dev_type == 'vusb':
1414 vusb_devs_uuid = sxp.child_value(config, 'uuid',
1415 uuid.createString())
1416 vusb_dict = self.vusb_convert_sxp_to_dict(config)
1417 vusb_dict['uuid'] = vusb_devs_uuid
1418 target['devices'][vusb_devs_uuid] = (dev_type, vusb_dict)
1419 return vusb_devs_uuid
1421 for opt_val in config[1:]:
1422 try:
1423 opt, val = opt_val
1424 dev_info[opt] = val
1425 except (TypeError, ValueError): # unpack error
1426 pass
1428 if dev_type == 'vbd':
1429 if dev_info.get('dev', '').startswith('ioemu:'):
1430 dev_info['driver'] = 'ioemu'
1431 else:
1432 dev_info['driver'] = 'paravirtualised'
1434 if dev_type == 'tap' or dev_type == 'tap2':
1435 tap_disk_type = dev_info['uname'].split(':')[1]
1436 # tapdisk uname may be 'tap:<driver>' or 'tap:tapdisk:<driver>'
1437 if tap_disk_type == 'tapdisk':
1438 tap_disk_type = dev_info['uname'].split(':')[2]
1439 if tap_disk_type not in blktap_disk_types:
1440 raise XendConfigError("tap:%s not a valid disk type" %
1441 tap_disk_type)
1443 if dev_type == 'vif':
1444 if not dev_info.get('mac'):
1445 dev_info['mac'] = randomMAC()
1447 ret_uuid = self.device_duplicate_check(dev_type, dev_info, target, config)
1448 if ret_uuid != None:
1449 return ret_uuid
1451 if dev_type == 'vif':
1452 if dev_info.get('policy') and dev_info.get('label'):
1453 dev_info['security_label'] = "%s:%s:%s" % \
1454 (xsconstants.ACM_POLICY_ID,
1455 dev_info['policy'],dev_info['label'])
1457 # create uuid if it doesn't exist
1458 dev_uuid = dev_info.get('uuid', None)
1459 if not dev_uuid:
1460 dev_uuid = uuid.createString()
1461 dev_info['uuid'] = dev_uuid
1463 # store dev references by uuid for certain device types
1464 target['devices'][dev_uuid] = (dev_type, dev_info)
1465 if dev_type in ('vif', 'vbd', 'vtpm'):
1466 param = '%s_refs' % dev_type
1467 if param not in target:
1468 target[param] = []
1469 if dev_uuid not in target[param]:
1470 if dev_type == 'vbd':
1471 if 'bootable' not in dev_info:
1472 # Compat hack -- mark first disk bootable
1473 dev_info['bootable'] = int(not target[param])
1474 else:
1475 # ensure type of bootable is int (on xend restart
1476 # it's of type str)
1477 dev_info['bootable'] = int(dev_info['bootable'])
1478 target[param].append(dev_uuid)
1479 elif dev_type == 'tap' or dev_type == 'tap2':
1480 if 'vbd_refs' not in target:
1481 target['vbd_refs'] = []
1482 if dev_uuid not in target['vbd_refs']:
1483 if 'bootable' not in dev_info:
1484 # Compat hack -- mark first disk bootable
1485 dev_info['bootable'] = int(not target['vbd_refs'])
1486 else:
1487 # ensure type of bootable is int (on xend restart it's
1488 # of type str)
1489 dev_info['bootable'] = int(dev_info['bootable'])
1490 target['vbd_refs'].append(dev_uuid)
1492 elif dev_type == 'vfb':
1493 # Populate other config with aux data that is associated
1494 # with vfb
1496 other_config = {}
1497 for key in XENAPI_CONSOLE_OTHER_CFG:
1498 if key in dev_info:
1499 other_config[key] = dev_info[key]
1500 target['devices'][dev_uuid][1]['other_config'] = other_config
1503 if 'console_refs' not in target:
1504 target['console_refs'] = []
1506 # Treat VFB devices as console devices so they are found
1507 # through Xen API
1508 if dev_uuid not in target['console_refs']:
1509 target['console_refs'].append(dev_uuid)
1511 # Cope with old-format save files which say under vfb
1512 # (type vfb) rather than (vfb 1)
1513 try:
1514 vfb_type = dev_info['type']
1515 except KeyError:
1516 vfb_type = None
1517 log.debug("iwj dev_type=%s vfb type %s" %
1518 (dev_type, `vfb_type`))
1520 if vfb_type == 'vnc' or vfb_type == 'sdl':
1521 dev_info[vfb_type] = 1
1522 del dev_info['type']
1523 log.debug("iwj dev_type=%s vfb setting dev_info['%s']" %
1524 (dev_type, vfb_type))
1525 # Create serial backends now, the location value is bogus, but does not matter
1526 i=0
1527 chardev=0
1528 if dev_info.get('serial') is not None :
1529 chardev = chardev + 1
1530 if dev_info.get('monitor') is not None :
1531 chardev = chardev + 1
1532 if chardev > 0 :
1533 chardev = chardev + 1
1534 while i < chardev :
1535 cfg = self.console_add('vt100', str(i))
1536 c_uuid = uuid.createString()
1537 target['devices'][c_uuid] = ('console', cfg)
1538 target['console_refs'].append(c_uuid)
1539 i = i + 1
1540 elif dev_type == 'console':
1541 if 'console_refs' not in target:
1542 target['console_refs'] = []
1543 if dev_uuid not in target['console_refs']:
1544 target['console_refs'].append(dev_uuid)
1546 log.debug("XendConfig: reading device: %s" % scrub_password(dev_info))
1547 return dev_uuid
1549 if cfg_xenapi:
1550 dev_info = {}
1551 dev_uuid = ''
1552 if dev_type == 'vif':
1553 dev_info['mac'] = cfg_xenapi.get('MAC')
1554 if not dev_info['mac']:
1555 dev_info['mac'] = randomMAC()
1556 # vifname is the name on the guest, not dom0
1557 # TODO: we don't have the ability to find that out or
1558 # change it from dom0
1559 #if cfg_xenapi.get('device'): # don't add if blank
1560 # dev_info['vifname'] = cfg_xenapi.get('device')
1561 if cfg_xenapi.get('type'):
1562 dev_info['type'] = cfg_xenapi.get('type')
1563 if cfg_xenapi.get('name'):
1564 dev_info['name'] = cfg_xenapi.get('name')
1565 if cfg_xenapi.get('network'):
1566 network = XendAPIStore.get(
1567 cfg_xenapi.get('network'), 'network')
1568 dev_info['bridge'] = network.get_name_label()
1570 if cfg_xenapi.get('security_label'):
1571 dev_info['security_label'] = \
1572 cfg_xenapi.get('security_label')
1574 dev_uuid = cfg_xenapi.get('uuid', None)
1575 if not dev_uuid:
1576 dev_uuid = uuid.createString()
1577 dev_info['uuid'] = dev_uuid
1578 target['devices'][dev_uuid] = (dev_type, dev_info)
1579 target['vif_refs'].append(dev_uuid)
1581 elif dev_type in ('vbd', 'tap', 'tap2'):
1582 dev_info['type'] = cfg_xenapi.get('type', 'Disk')
1583 if dev_info['type'] == 'CD':
1584 old_vbd_type = 'cdrom'
1585 else:
1586 old_vbd_type = 'disk'
1588 dev_info['uname'] = cfg_xenapi.get('image', '')
1589 dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
1590 old_vbd_type)
1591 dev_info['bootable'] = int(cfg_xenapi.get('bootable', 0))
1592 dev_info['driver'] = cfg_xenapi.get('driver', '')
1593 dev_info['VDI'] = cfg_xenapi.get('VDI', '')
1595 if cfg_xenapi.get('mode') == 'RW':
1596 dev_info['mode'] = 'w'
1597 else:
1598 dev_info['mode'] = 'r'
1600 dev_uuid = cfg_xenapi.get('uuid', None)
1601 if not dev_uuid:
1602 dev_uuid = uuid.createString()
1603 dev_info['uuid'] = dev_uuid
1604 target['devices'][dev_uuid] = (dev_type, dev_info)
1605 target['vbd_refs'].append(dev_uuid)
1607 elif dev_type == 'vtpm':
1608 if cfg_xenapi.get('type'):
1609 dev_info['type'] = cfg_xenapi.get('type')
1611 dev_uuid = cfg_xenapi.get('uuid', None)
1612 if not dev_uuid:
1613 dev_uuid = uuid.createString()
1614 dev_info['uuid'] = dev_uuid
1615 dev_info['other_config'] = cfg_xenapi.get('other_config', {})
1616 target['devices'][dev_uuid] = (dev_type, dev_info)
1617 target['vtpm_refs'].append(dev_uuid)
1619 elif dev_type == 'console':
1620 dev_uuid = cfg_xenapi.get('uuid', None)
1621 if not dev_uuid:
1622 dev_uuid = uuid.createString()
1623 dev_info['uuid'] = dev_uuid
1624 dev_info['protocol'] = cfg_xenapi.get('protocol', 'rfb')
1625 console_other_config = cfg_xenapi.get('other_config', {})
1626 dev_info['other_config'] = console_other_config
1627 if dev_info['protocol'] == 'rfb':
1628 # collapse other config into devinfo for things
1629 # such as vncpasswd, vncunused, etc.
1630 dev_info.update(console_other_config)
1631 dev_info['vnc'] = console_other_config.get('vnc', '0')
1632 dev_info['sdl'] = console_other_config.get('sdl', '0')
1633 target['devices'][dev_uuid] = ('vfb', dev_info)
1634 target['console_refs'].append(dev_uuid)
1636 # if console is rfb, set device_model ensuring qemu
1637 # is invoked for pvfb services
1638 if 'device_model' not in target['platform']:
1639 target['platform']['device_model'] = \
1640 auxbin.pathTo("qemu-dm")
1642 # Finally, if we are a pvfb, we need to make a vkbd
1643 # as well that is not really exposed to Xen API
1644 vkbd_uuid = uuid.createString()
1645 target['devices'][vkbd_uuid] = ('vkbd', {})
1647 elif dev_info['protocol'] == 'vt100':
1648 # if someone tries to create a VT100 console
1649 # via the Xen API, we'll have to ignore it
1650 # because we create one automatically in
1651 # XendDomainInfo._update_consoles
1652 raise XendConfigError('Creating vt100 consoles via '
1653 'Xen API is unsupported')
1655 return dev_uuid
1657 # no valid device to add
1658 return ''
1660 def phantom_device_add(self, dev_type, cfg_xenapi = None,
1661 target = None):
1662 """Add a phantom tap device configuration in XenAPI struct format.
1663 """
1665 if target == None:
1666 target = self
1668 if dev_type not in XendDevices.valid_devices() and \
1669 dev_type not in XendDevices.pseudo_devices():
1670 raise XendConfigError("XendConfig: %s not a valid device type" %
1671 dev_type)
1673 if cfg_xenapi == None:
1674 raise XendConfigError("XendConfig: device_add requires some "
1675 "config.")
1677 if cfg_xenapi:
1678 log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
1680 if cfg_xenapi:
1681 dev_info = {}
1682 if dev_type in ('vbd', 'tap'):
1683 if dev_type == 'vbd':
1684 dev_info['uname'] = cfg_xenapi.get('image', '')
1685 dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
1686 elif dev_type == 'tap':
1687 if cfg_xenapi.get('image').find('tap:') == -1:
1688 dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
1689 dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
1690 dev_info['uname'] = cfg_xenapi.get('image')
1691 dev_info['mode'] = cfg_xenapi.get('mode')
1692 dev_info['backend'] = '0'
1693 dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
1694 dev_info['uuid'] = dev_uuid
1695 self['devices'][dev_uuid] = (dev_type, dev_info)
1696 self['vbd_refs'].append(dev_uuid)
1697 return dev_uuid
1699 return ''
1701 def vscsi_convert_sxp_to_dict(self, dev_sxp):
1702 """Convert vscsi device sxp to dict
1703 @param dev_sxp: device configuration
1704 @type dev_sxp: SXP object (parsed config)
1705 @return: dev_config
1706 @rtype: dictionary
1707 """
1708 # Parsing the device SXP's. In most cases, the SXP looks
1709 # like this:
1711 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
1713 # However, for SCSI devices it looks like this:
1715 # [device,
1716 # [vscsi,
1717 # [feature-host, 0],
1718 # [backend, 0],
1719 # [dev,
1720 # [devid, 0], [p-devname, sdb], [p-dev, 1:0:0:1],
1721 # [v-dev, 0:0:0:0], [state, 1]
1722 # ],
1723 # [dev,
1724 # [devid, 0], [p-devname, sdc], [p-dev, 1:0:0:2],
1725 # [v-dev, 0:0:0:1], [satet, 1]
1726 # ]
1727 # ],
1728 # [vscsi,
1729 # [feature-host, 1],
1730 # [backend, 0],
1731 # [dev,
1732 # [devid, 1], [p-devname, sdg], [p-dev, 2:0:0:0],
1733 # [v-dev, 1:0:0:0], [state, 1]
1734 # ],
1735 # [dev,
1736 # [devid, 1], [p-devname, sdh], [p-dev, 2:0:0:1],
1737 # [v-dev, 1:0:0:1], [satet, 1]
1738 # ]
1739 # ]
1740 # ]
1742 # It seems the reasoning for this difference is because
1743 # vscsiif.py needs all the SCSI device configurations with
1744 # same host number at the same time when creating the devices.
1746 # For SCSI device hotplug support, the SXP of SCSI devices is
1747 # extendend like this:
1749 # [device,
1750 # [vscsi,
1751 # [feature-host, 0],
1752 # [backend, 0],
1753 # [dev,
1754 # [devid, 0], [p-devname, sdd], [p-dev, 1:0:0:3],
1755 # [v-dev, 0:0:0:2], [state, 1]
1756 # ]
1757 # ]
1758 # ]
1760 # state xenbusState['Initialising'] indicates that the device is
1761 # being attached, while state xenbusState['Closing'] indicates
1762 # that the device is being detached.
1764 # The Dict looks like this:
1766 # { devs: [ {devid: 0, p-devname: sdd, p-dev: 1:0:0:3,
1767 # v-dev: 0:0:0:2, state: 1} ],
1768 # feature-host: 1 , backend: 0 }
1770 dev_config = {}
1772 vscsi_devs = []
1773 for vscsi_dev in sxp.children(dev_sxp, 'dev'):
1774 vscsi_dev_info = {}
1775 for opt_val in vscsi_dev[1:]:
1776 try:
1777 opt, val = opt_val
1778 vscsi_dev_info[opt] = val
1779 except TypeError:
1780 pass
1781 # append uuid for each vscsi device.
1782 vscsi_uuid = vscsi_dev_info.get('uuid', uuid.createString())
1783 vscsi_dev_info['uuid'] = vscsi_uuid
1784 vscsi_devs.append(vscsi_dev_info)
1785 dev_config['devs'] = vscsi_devs
1787 vscsi_mode = sxp.children(dev_sxp, 'feature-host')[0]
1788 dev_config['feature-host'] = vscsi_mode[1]
1789 try:
1790 vscsi_be = sxp.children(dev_sxp, 'backend')[0]
1791 dev_config['backend'] = vscsi_be[1]
1792 except IndexError:
1793 pass
1795 return dev_config
1797 def vusb_convert_sxp_to_dict(self, dev_sxp):
1798 """Convert vusb device sxp to dict
1799 @param dev_sxp: device configuration
1800 @type dev_sxp: SXP object (parsed config)
1801 @return: dev_config
1802 @rtype: dictionary
1803 """
1804 # Parsing USB devices SXP.
1806 # USB device's SXP looks like this:
1808 # [device,
1809 # [vusb,
1810 # [usb-ver, 2],
1811 # [num-ports, 8],
1812 # [port,
1813 # [1, 1-1],
1814 # [2, 1-2],
1815 # [3, ''],
1816 # [4, ''],
1817 # [5, ''],
1818 # [6, ''],
1819 # [7, 6-2.1],
1820 # [8, '']
1821 # ]
1822 # ],
1823 # [vusb,
1824 # [usb-ver, 1],
1825 # [num-ports, 2],
1826 # [port,
1827 # [1, 4-1],
1828 # [2, 4-2]
1829 # ]
1830 # ]
1831 # ]
1833 # The dict looks like this
1835 # { usb-ver: 2,
1836 # num-ports: 8,
1837 # port-1: 1-1,
1838 # port-2: 1-2,
1839 # port-3: "",
1840 # port-4: "",
1841 # port-5: "",
1842 # port-6: "",
1843 # port-7: "",
1844 # port-8: "" }
1846 dev_config = {}
1847 dev_config['usb-ver'] = sxp.child(dev_sxp, 'usb-ver')[1]
1848 dev_config['num-ports'] = sxp.child(dev_sxp, 'num-ports')[1]
1849 ports = sxp.child(dev_sxp, 'port')
1850 for port in ports[1:]:
1851 try:
1852 num, bus = port
1853 dev_config['port-%i' % int(num)] = str(bus)
1854 except TypeError:
1855 pass
1857 return dev_config
1859 def console_add(self, protocol, location, other_config = {}):
1860 dev_uuid = uuid.createString()
1861 if protocol == 'vt100':
1862 dev_info = {
1863 'uuid': dev_uuid,
1864 'protocol': protocol,
1865 'location': location,
1866 'other_config': other_config,
1869 if 'devices' not in self:
1870 self['devices'] = {}
1872 self['devices'][dev_uuid] = ('console', dev_info)
1873 self['console_refs'].append(dev_uuid)
1874 return dev_info
1876 return {}
1878 def console_update(self, console_uuid, key, value):
1879 for dev_uuid, (dev_type, dev_info) in self['devices'].items():
1880 if dev_uuid == console_uuid:
1881 dev_info[key] = value
1882 # collapse other_config into dev_info for things
1883 # such as vncpasswd, vncunused, etc.
1884 if key == 'other_config':
1885 for k in XENAPI_CONSOLE_OTHER_CFG:
1886 if k in dev_info and k not in value:
1887 del dev_info[k]
1888 dev_info.update(value)
1889 break
1891 def console_get_all(self, protocol):
1892 if protocol == 'vt100':
1893 consoles = [dinfo for dtype, dinfo in self['devices'].values()
1894 if dtype == 'console']
1895 return [c for c in consoles if c.get('protocol') == protocol]
1897 elif protocol == 'rfb':
1898 vfbs = [dinfo for dtype, dinfo in self['devices'].values()
1899 if dtype == 'vfb']
1901 # move all non-console key values to other_config before
1902 # returning console config
1903 valid_keys = ['uuid', 'location']
1904 for vfb in vfbs:
1905 other_config = {}
1906 for key, val in vfb.items():
1907 if key not in valid_keys:
1908 other_config[key] = vfb[key]
1909 del vfb[key]
1910 vfb['other_config'] = other_config
1911 vfb['protocol'] = 'rfb'
1913 return vfbs
1915 else:
1916 return []
1918 def device_update(self, dev_uuid, cfg_sxp = [], cfg_xenapi = {}):
1919 """Update an existing device with the new configuration.
1921 @rtype: boolean
1922 @return: Returns True if succesfully found and updated a device conf
1923 """
1924 if dev_uuid in self['devices'] and cfg_sxp:
1925 if sxp.child0(cfg_sxp) == 'device':
1926 config = sxp.child0(cfg_sxp)
1927 else:
1928 config = cfg_sxp
1930 dev_type, dev_info = self['devices'][dev_uuid]
1932 if dev_type == 'pci': # Special case for pci
1933 pci_dict = pci_convert_sxp_to_dict(config)
1934 pci_devs = pci_dict['devs']
1936 # destroy existing XenAPI DPCI objects
1937 for dpci_uuid in XendDPCI.get_by_VM(self['uuid']):
1938 XendAPIStore.deregister(dpci_uuid, "DPCI")
1940 # create XenAPI DPCI objects.
1941 self.create_dpci_from_sxp(pci_devs)
1943 self['devices'][dev_uuid] = (dev_type,
1944 {'devs': pci_devs,
1945 'uuid': dev_uuid})
1946 return True
1948 if dev_type == 'vscsi': # Special case for vscsi
1949 vscsi_dict = self.vscsi_convert_sxp_to_dict(config)
1950 vscsi_devs = vscsi_dict['devs']
1951 vscsi_mode = vscsi_dict['feature-host']
1952 vscsi_be = vscsi_dict.get('backend', None)
1954 # destroy existing XenAPI DSCSI objects
1955 vscsi_devid = int(dev_info['devs'][0]['devid'])
1956 for dscsi_uuid in XendDSCSI.get_by_VM(self['uuid']):
1957 dscsi_inst = XendAPIStore.get(dscsi_uuid, 'DSCSI')
1958 if vscsi_devid == dscsi_inst.get_virtual_host():
1959 XendAPIStore.deregister(dscsi_uuid, "DSCSI")
1961 # destroy existing XenAPI DSCSI_HBA objects
1962 if not vscsi_devs:
1963 XendAPIStore.deregister(dev_uuid, 'DSCSI_HBA')
1965 # create XenAPI DSCSI objects.
1966 for vscsi_dev in vscsi_devs:
1967 dscsi_uuid = vscsi_dev.get('uuid')
1968 pscsi_uuid = XendPSCSI.get_by_HCTL(vscsi_dev['p-dev'])
1969 if pscsi_uuid is None:
1970 continue
1971 dscsi_record = {
1972 'VM': self['uuid'],
1973 'PSCSI': pscsi_uuid,
1974 'HBA': dev_uuid,
1975 'virtual_HCTL': vscsi_dev.get('v-dev')
1977 XendDSCSI(dscsi_uuid, dscsi_record)
1979 vscsi_info = {
1980 'devs': vscsi_devs,
1981 'feature-host': vscsi_mode,
1982 'uuid': dev_uuid
1984 if vscsi_be is not None:
1985 vscsi_info['backend'] = vscsi_be
1986 self['devices'][dev_uuid] = (dev_type, vscsi_info)
1987 return True
1989 for opt_val in config[1:]:
1990 try:
1991 opt, val = opt_val
1992 dev_info[opt] = val
1993 except (TypeError, ValueError):
1994 pass # no value for this config option
1996 self['devices'][dev_uuid] = (dev_type, dev_info)
1997 return True
1999 elif dev_uuid in self['devices'] and cfg_xenapi:
2000 dev_type, dev_info = self['devices'][dev_uuid]
2001 for key, val in cfg_xenapi.items():
2002 dev_info[key] = val
2003 self['devices'][dev_uuid] = (dev_type, dev_info)
2004 return True
2006 return False
2009 def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None, target = None):
2010 """Get Device SXPR by either giving the device UUID or (type, config).
2012 @rtype: list of lists
2013 @return: device config sxpr
2014 """
2015 sxpr = []
2017 if target == None:
2018 target = self
2020 if dev_uuid != None and dev_uuid in target['devices']:
2021 dev_type, dev_info = target['devices'][dev_uuid]
2023 if dev_type == None or dev_info == None:
2024 raise XendConfigError("Required either UUID or device type and "
2025 "configuration dictionary.")
2027 sxpr.append(dev_type)
2028 if dev_type in ('console', 'vfb'):
2029 config = [(opt, val) for opt, val in dev_info.items()
2030 if opt != 'other_config']
2031 else:
2032 config = [(opt, val) for opt, val in dev_info.items()]
2034 sxpr += config
2036 return sxpr
2038 def ordered_device_refs(self, target = None):
2039 result = []
2041 if target == None:
2042 target = self
2044 # vkbd devices *must* be before vfb devices, otherwise
2045 # there is a race condition when setting up devices
2046 # where the daemon spawned for the vfb may write stuff
2047 # into xenstore vkbd backend, before DevController has
2048 # setup permissions on the vkbd backend path. This race
2049 # results in domain creation failing with 'device already
2050 # connected' messages
2051 result.extend([u for u in target['devices'].keys() if target['devices'][u][0] == 'vkbd'])
2053 result.extend(target.get('console_refs', []) +
2054 target.get('vbd_refs', []) +
2055 target.get('vif_refs', []) +
2056 target.get('vtpm_refs', []))
2058 result.extend([u for u in target['devices'].keys() if u not in result])
2059 return result
2061 def all_devices_sxpr(self, target = None):
2062 """Returns the SXPR for all devices in the current configuration."""
2063 sxprs = []
2065 if target == None:
2066 target = self
2068 if 'devices' not in target:
2069 return sxprs
2071 ordered_refs = self.ordered_device_refs(target = target)
2072 for dev_uuid in ordered_refs:
2073 dev_type, dev_info = target['devices'][dev_uuid]
2074 if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
2075 if dev_type == 'pci':
2076 sxpr = ['pci', ['uuid', dev_info['uuid']]]
2077 elif dev_type == 'vscsi':
2078 sxpr = ['vscsi', ['uuid', dev_info['uuid']],
2079 ['feature-host', dev_info['feature-host']]]
2080 if dev_info.has_key('backend'):
2081 sxpr.append(['backend', dev_info['backend']])
2082 for pci_dev_info in dev_info['devs']:
2083 sxpr.append(dev_dict_to_sxp(pci_dev_info))
2084 sxprs.append((dev_type, sxpr))
2085 elif dev_type == 'vusb':
2086 sxpr = ['vusb', ['uuid', dev_info['uuid']],
2087 ['usb-ver', dev_info['usb-ver']],
2088 ['num-ports', dev_info['num-ports']]]
2089 port_sxpr = ['port']
2090 for i in range(1, int(dev_info['num-ports']) + 1):
2091 if dev_info.has_key('port-%i' % i):
2092 port_sxpr.append([i, str(dev_info['port-%i' % i])])
2093 else:
2094 port_sxpr.append([i, ""])
2095 sxpr.append(port_sxpr)
2096 sxprs.append((dev_type, sxpr))
2097 else:
2098 sxpr = self.device_sxpr(dev_type = dev_type,
2099 dev_info = dev_info,
2100 target = target)
2101 sxprs.append((dev_type, sxpr))
2103 return sxprs
2105 def image_sxpr(self):
2106 """Returns a backwards compatible image SXP expression that is
2107 used in xenstore's /vm/<uuid>/image value and xm list."""
2108 image = [self.image_type()]
2109 if self.has_key('PV_kernel'):
2110 image.append(['kernel', self['PV_kernel']])
2111 if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
2112 image.append(['ramdisk', self['PV_ramdisk']])
2113 if self.has_key('PV_args') and self['PV_args']:
2114 image.append(['args', self['PV_args']])
2115 if self.has_key('superpages'):
2116 image.append(['superpages', self['superpages']])
2118 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
2119 if key in self['platform']:
2120 image.append([key, self['platform'][key]])
2122 if 'notes' in self:
2123 image.append(self.notes_sxp(self['notes']))
2125 return image
2127 def update_with_image_sxp(self, image_sxp, bootloader = False):
2128 # Convert Legacy "image" config to Xen API PV_*
2129 # configuration
2130 log.debug("update_with_image_sxp(%s)" % scrub_password(image_sxp))
2132 # user-specified args must come last: previous releases did this and
2133 # some domU kernels rely upon the ordering.
2134 kernel_args = sxp.child_value(image_sxp, 'args', '')
2136 # attempt to extract extra arguments from SXP config
2137 arg_ip = sxp.child_value(image_sxp, 'ip')
2138 if arg_ip and not re.search(r'ip=[^ ]+', kernel_args):
2139 kernel_args = 'ip=%s ' % arg_ip + kernel_args
2140 arg_root = sxp.child_value(image_sxp, 'root')
2141 if arg_root and not re.search(r'root=', kernel_args):
2142 kernel_args = 'root=%s ' % arg_root + kernel_args
2144 if bootloader:
2145 self['_temp_using_bootloader'] = '1'
2146 self['_temp_kernel'] = sxp.child_value(image_sxp, 'kernel','')
2147 self['_temp_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
2148 self['_temp_args'] = kernel_args
2149 self['use_tmp_kernel'] = True
2150 self['use_tmp_ramdisk'] = True
2151 else:
2152 self['PV_kernel'] = sxp.child_value(image_sxp, 'kernel','')
2153 self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
2154 self['PV_args'] = kernel_args
2155 self['use_tmp_kernel'] = False
2156 self['use_tmp_ramdisk'] = False
2158 val = sxp.child_value(image_sxp, 'superpages')
2159 if val is not None:
2160 self['superpages'] = val
2162 val = sxp.child_value(image_sxp, 'memory_sharing')
2163 if val is not None:
2164 self['memory_sharing'] = val
2166 for key in XENAPI_PLATFORM_CFG_TYPES.keys():
2167 val = sxp.child_value(image_sxp, key, None)
2168 if val is not None and val != '':
2169 self['platform'][key] = val
2171 notes = sxp.children(image_sxp, 'notes')
2172 if notes:
2173 self['notes'] = self.notes_from_sxp(notes[0])
2175 self._hvm_boot_params_from_sxp(image_sxp)
2177 def set_notes(self, notes):
2178 'Add parsed elfnotes to image'
2179 self['notes'] = notes
2181 def get_notes(self):
2182 try:
2183 return self['notes'] or {}
2184 except KeyError:
2185 return {}
2187 def notes_from_sxp(self, nsxp):
2188 notes = {}
2189 for note in sxp.children(nsxp):
2190 notes[note[0]] = note[1]
2191 return notes
2193 def notes_sxp(self, notes):
2194 nsxp = ['notes']
2195 for k, v in notes.iteritems():
2196 nsxp.append([k, str(v)])
2197 return nsxp
2199 def _hvm_boot_params_from_sxp(self, image_sxp):
2200 boot = sxp.child_value(image_sxp, 'boot', None)
2201 if boot is not None:
2202 self['HVM_boot_policy'] = 'BIOS order'
2203 self['HVM_boot_params'] = { 'order' : boot }
2205 def is_hvm(self):
2206 return self['HVM_boot_policy'] != ''
2208 def is_stubdom(self):
2209 return (self['PV_kernel'].find('ioemu') >= 0)
2211 def target(self):
2212 return self['target']
2214 def image_type(self):
2215 stored_type = self['platform'].get('image_type')
2216 return stored_type or (self.is_hvm() and 'hvm' or 'linux')
2218 def is_hap(self):
2219 return self['platform'].get('hap', 0)
2221 def is_pv_and_has_pci(self):
2222 for dev_type, dev_info in self.all_devices_sxpr():
2223 if dev_type != 'pci':
2224 continue
2225 return not self.is_hvm()
2226 return False
2228 def update_platform_pci(self):
2229 pci = []
2230 for dev_type, dev_info in self.all_devices_sxpr():
2231 if dev_type != 'pci':
2232 continue
2233 for dev in sxp.children(dev_info, 'dev'):
2234 domain = sxp.child_value(dev, 'domain')
2235 bus = sxp.child_value(dev, 'bus')
2236 slot = sxp.child_value(dev, 'slot')
2237 func = sxp.child_value(dev, 'func')
2238 vdevfn = sxp.child_value(dev, 'vdevfn')
2239 opts = pci_opts_list_from_sxp(dev)
2240 pci.append([domain, bus, slot, func, vdevfn, opts])
2241 self['platform']['pci'] = pci
2243 def handle_fileuris(self):
2244 for arg in [('PV_kernel', 'use_tmp_kernel'),
2245 ('PV_ramdisk', 'use_tmp_ramdisk')]:
2246 if arg[0] in self and self[arg[0]]!='':
2247 self[arg[0]], self[arg[1]] \
2248 = xen.util.fileuri.schemes.decode(self[arg[0]])
2249 log.debug("fileuri '%s' = '%s'" % (arg[0], self[arg[0]][:100]))