diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 4f553b9bc3..081de0cf11 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -730,11 +730,11 @@ class XendAPI: def vm_get_memory_dynamic_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_memory_dynamic_max()) def vm_get_memory_dynamic_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_memory_dynamic_min()) def vm_get_VCPUs_policy(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -798,11 +798,11 @@ class XendAPI: def vm_get_builder(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_builder()) def vm_get_boot_method(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success('') + return xen_api_success(dom.get_boot_method()) def vm_get_kernel_kernel(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -969,8 +969,8 @@ class XendAPI: 'resident_on': XendNode.instance().uuid, 'memory_static_min': xeninfo.get_memory_static_min(), 'memory_static_max': xeninfo.get_memory_static_max(), - 'memory_dynamic_min': xeninfo.get_memory_static_min(), - 'memory_dynamic_max': xeninfo.get_memory_static_max(), + 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(), + 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(), 'memory_actual': xeninfo.get_memory_static_min(), 'vcpus_policy': xeninfo.get_vcpus_policy(), 'vcpus_params': xeninfo.get_vcpus_params(), diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index b7c964d70a..707a9c5c3c 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -18,8 +18,8 @@ import xen.lowlevel.xc from xen.xend import balloon, sxp from xen.xend.XendError import XendError, VmError from xen.xend.XendLogging import log -from xen.xend.XendConstants import * from xen.xend.XendConfig import XendConfig +from xen.xend.XendConstants import * SIGNATURE = "LinuxGuestRecord" XC_SAVE = "xc_save" @@ -137,7 +137,7 @@ def restore(xd, fd, dominfo = None, paused = False): vmconfig = p.get_val() if dominfo: - dominfo.update(XendConfig(sxp = vmconfig), refresh = False) + dominfo.update(XendConfig(sxp_obj = vmconfig), refresh = False) dominfo.resume() else: dominfo = xd.restore_(vmconfig) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index da7898c72c..df124c06ca 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -31,31 +31,34 @@ from xen.xend.XendConstants import DOM_STATE_HALTED XendConfig API XendConfig will try to mirror as closely the Xen API VM Struct - providing a backwards compatibility mode for SXP dumping, loading. + with extra parameters for those options that are not supported. """ +def reverse_dict(adict): + """Return the reverse mapping of a dictionary.""" + return dict([(v, k) for k, v in adict.items()]) -LEGACY_CFG_TO_XENAPI_CFG = { +# Mapping from XendConfig configuration keys to the old +# legacy configuration keys that map directly. + +XENAPI_CFG_TO_LEGACY_CFG = { 'uuid': 'uuid', - 'vcpus': 'vcpus_number', - 'maxmem': 'memory_static_max', - 'memory': 'memory_static_min', - 'name': 'name_label', - 'on_poweroff': 'actions_after_shutdown', - 'on_reboot': 'actions_after_reboot', - 'on_crash': 'actions_after_crash', - 'bootloader': 'boot_method', - 'kernel_kernel': 'kernel_kernel', - 'kernel_initrd': 'kernel_initrd', - 'kernel_args': 'kernel_args', - } + 'vcpus_number': 'vcpus', + 'memory_static_min': 'memory', + 'memory_static_max': 'maxmem', + 'name_label': 'name', + 'actions_after_shutdown': 'on_poweroff', + 'actions_after_reboot': 'on_reboot', + 'actions_after_crash': 'on_crash', + 'platform_localtime': 'localtime', +} -XENAPI_CFG_CUSTOM_TRANSLATE = [ - 'vifs', - 'vbds', - ] +LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) +# Mapping from XendConfig configuration keys to the old +# legacy configuration keys that are found in the 'image' +# SXP object. XENAPI_HVM_CFG = { 'platform_std_vga': 'std-vga', 'platform_serial' : 'serial', @@ -64,7 +67,10 @@ XENAPI_HVM_CFG = { 'platform_keymap' : 'keymap', } -XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [ +# List of XendConfig configuration keys that have no equivalent +# in the old world. + +XENAPI_UNSUPPORTED_BY_LEGACY_CFG = [ 'name_description', 'user_version', 'is_a_template', @@ -85,11 +91,116 @@ XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [ 'platform_clock_offset', 'platform_enable_audio', 'platform_keymap', + 'boot_method', 'builder', 'grub_cmdline', 'pci_bus', 'otherconfig' - ] +] + +# List of legacy configuration keys that have no equivalent in the +# Xen API, but are still stored in XendConfig. + +LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [ + # roundtripped (dynamic, unmodified) + 'shadow_memory', + 'security', + 'vcpu_avail', + 'cpu_weight', + 'cpu_cap', + 'bootloader', + 'bootloader_args', + 'features', + # read/write + 'on_xend_start', + 'on_xend_stop', + # read-only + 'domid', + 'start_time', + 'cpu_time', + 'online_vcpus', + # write-once + 'cpu', + 'cpus', +] + +LEGACY_CFG_TYPES = { + 'uuid': str, + 'name': str, + 'vcpus': int, + 'vcpu_avail': int, + 'memory': int, + 'shadow_memory': int, + 'maxmem': int, + 'start_time': float, + 'cpu_cap': int, + 'cpu_weight': int, + 'cpu_time': float, + 'bootloader': str, + 'bootloader_args': str, + 'features': str, + 'localtime': int, + 'name': str, + 'on_poweroff': str, + 'on_reboot': str, + 'on_crash': str, + 'on_xend_stop': str, + 'on_xend_start': str, +} + +# Values that should be stored in xenstore's /vm/ that is used +# by Xend. Used in XendDomainInfo to restore running VM state from +# xenstore. +LEGACY_XENSTORE_VM_PARAMS = [ + 'uuid', + 'name', + 'vcpus', + 'vcpu_avail', + 'memory', + 'shadow_memory', + 'maxmem', + 'start_time', + 'name', + 'on_poweroff', + 'on_crash', + 'on_reboot', + 'on_xend_start', + 'on_xend_stop', +] + +LEGACY_IMAGE_CFG = [ + ('root', str), + ('ip', str), + ('nographic', int), + ('vnc', int), + ('sdl', int), + ('vncdisplay', int), + ('vncunused', int), +] + +LEGACY_IMAGE_HVM_CFG = [ + ('device_model', str), + ('display', str), + ('xauthority', str), + ('vncconsole', int), + ('pae', int), + ('apic', int), + ('acpi', int), + ('serial', str), +] + +LEGACY_IMAGE_HVM_DEVICES_CFG = [ + ('boot', str), + ('fda', str), + ('fdb', str), + ('soundhw', str), + ('isa', str), + ('vcpus', int), + ('acpi', int), + ('usb', str), + ('usbdevice', str), +] + # configuration params that need to be converted to ints @@ -102,74 +213,11 @@ XENAPI_INT_CFG = [ 'memory_static_max', 'memory_dynamic_min', 'memory_dynamic_max', + 'memory_actual', 'tpm_instance', 'tpm_backend', ] -## -## Xend Configuration Parameters -## - - -# All parameters of VMs that may be configured on-the-fly, or at start-up. -VM_CONFIG_ENTRIES = [ - ('name', str), - ('on_crash', str), - ('on_poweroff', str), - ('on_reboot', str), - ('on_xend_start', str), - ('on_xend_stop', str), -] - -# All entries written to the store. This is VM_CONFIG_ENTRIES, plus those -# entries written to the store that cannot be reconfigured on-the-fly. -VM_STORE_ENTRIES = [ - ('uuid', str), - ('vcpus', int), - ('vcpu_avail', int), - ('memory', int), - ('maxmem', int), - ('start_time', float), -] - -VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES - -# Configuration entries that we expect to round-trip -- be read from the -# config file or xc, written to save-files (i.e. through sxpr), and reused as -# config on restart or restore, all without munging. Some configuration -# entries are munged for backwards compatibility reasons, or because they -# don't come out of xc in the same form as they are specified in the config -# file, so those are handled separately. - -ROUNDTRIPPING_CONFIG_ENTRIES = [ - ('uuid', str), - ('vcpus', int), - ('vcpu_avail', int), - ('cpu_cap', int), - ('cpu_weight', int), - ('memory', int), - ('shadow_memory', int), - ('maxmem', int), - ('bootloader', str), - ('bootloader_args', str), - ('features', str), - ('localtime', int), -] -ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES - -## Static Configuration - -STATIC_CONFIG_ENTRIES = [ - ('cpu', int), - ('cpus', str), - ('image', list), - ('security', list), # TODO: what if null? -] - -DEPRECATED_ENTRIES = [ - ('restart', str), -] - ## ## Config Choices ## @@ -178,245 +226,152 @@ CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart') CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown', 'crashed', 'dying') -## -## Defaults -## - -def DEFAULT_VCPUS(info): - if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1 - else: return 1 - -DEFAULT_CONFIGURATION = ( - ('uuid', lambda info: uuid.createString()), - ('name', lambda info: 'Domain-' + info['uuid']), - - ('on_poweroff', lambda info: 'destroy'), - ('on_reboot', lambda info: 'restart'), - ('on_crash', lambda info: 'restart'), - ('features', lambda info: ''), - - - ('memory', lambda info: 0), - ('shadow_memory',lambda info: 0), - ('maxmem', lambda info: 0), - ('bootloader', lambda info: None), - ('bootloader_args', lambda info: None), - ('backend', lambda info: []), - ('device', lambda info: {}), - ('image', lambda info: None), - ('security', lambda info: []), - ('on_xend_start', lambda info: 'ignore'), - ('on_xend_stop', lambda info: 'ignore'), - - ('cpus', lambda info: []), - ('cpu_cap', lambda info: 0), - ('cpu_weight', lambda info: 256), - ('vcpus', lambda info: DEFAULT_VCPUS(info)), - ('online_vcpus', lambda info: info['vcpus']), - ('max_vcpu_id', lambda info: info['vcpus']-1), - ('vcpu_avail', lambda info: (1</image value and xm list.""" + image = [self['image'].get('type', 'linux')] + if self.has_key('kernel_kernel'): + image.append(['kernel', self['kernel_kernel']]) + if self.has_key('kernel_initrd') and self['kernel_initrd']: + image.append(['ramdisk', self['kernel_initrd']]) + if self.has_key('kernel_args') and self['kernel_args']: + image.append(['args', self['kernel_args']]) + + for arg, conv in LEGACY_IMAGE_CFG: + if self['image'].has_key(arg): + image.append([arg, self['image'][arg]]) + + if 'hvm' in self['image']: + for arg, conv in LEGACY_IMAGE_HVM_CFG: + if self['image']['hvm'].has_key(arg): + image.append([arg, self['image']['hvm'][arg]]) + + if 'hvm' in self['image'] and 'devices' in self['image']['hvm']: + for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: + if self['image']['hvm']['devices'].has_key(arg): + image.append([arg, + self['image']['hvm']['devices'][arg]]) + + return image + + def update_with_image_sxp(self, image_sxp): + # Convert Legacy "image" config to Xen API kernel_* + # configuration + self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','') + self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','') + kernel_args = sxp.child_value(image_sxp, 'args', '') + + # attempt to extract extra arguments from SXP config + arg_ip = sxp.child_value(image_sxp, 'ip') + if arg_ip and not re.search(r'ip=[0-9\.]', kernel_args): + kernel_args += ' ip=%s' % arg_ip + arg_root = sxp.child_value(image_sxp, 'root') + if arg_root and not re.search(r'root=', kernel_args): + kernel_args += ' root=%s' % arg_root + self['kernel_args'] = kernel_args + + # Store image SXP in python dictionary format + image = {} + image['type'] = sxp.name(image_sxp) + for arg, conv in LEGACY_IMAGE_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image[arg] = conv(val) + + image_hvm = {} + for arg, conv in LEGACY_IMAGE_HVM_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image_hvm[arg] = conv(val) + + image_hvm_devices = {} + for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image_hvm_devices[arg] = conv(val) + + if image_hvm or image_hvm_devices: + image['hvm'] = image_hvm + image['hvm']['devices'] = image_hvm_devices + + self['image'] = image + + for apikey, imgkey in XENAPI_HVM_CFG.items(): + val = sxp.child(image_sxp, imgkey, None) + if val != None: + self[apikey] = val + + # # debugging # diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 839acc8da6..b21f762d13 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -433,6 +433,11 @@ class XendDomain: """ log.debug("Adding Domain: %s" % info.getDomid()) self.domains[info.getDomid()] = info + + # update the managed domains with a new XendDomainInfo object + # if we are keeping track of it. + if info.get_uuid() in self.managed_domains: + self._managed_domain_register(info) def _remove_domain(self, info, domid = None): """Remove the domain from the list of running domains @@ -669,7 +674,7 @@ class XendDomain: self.domains_lock.acquire() try: try: - xeninfo = XendConfig(xenapi_vm = xenapi_vm) + xeninfo = XendConfig(xapi = xenapi_vm) dominfo = XendDomainInfo.createDormant(xeninfo) log.debug("Creating new managed domain: %s: %s" % (dominfo.getName(), dominfo.get_uuid())) @@ -873,8 +878,8 @@ class XendDomain: self.domains_lock.acquire() try: try: - xeninfo = XendConfig(sxp = config) - dominfo = XendDomainInfo.createDormant(xeninfo) + domconfig = XendConfig(sxp_obj = config) + dominfo = XendDomainInfo.createDormant(domconfig) log.debug("Creating new managed domain: %s" % dominfo.getName()) self._managed_domain_register(dominfo) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 26428a0304..fdf5dc4d71 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -38,10 +38,9 @@ from xen.util.blkif import blkdev_uname_to_file from xen.util import security from xen.xend import balloon, sxp, uuid, image, arch -from xen.xend import XendRoot, XendNode +from xen.xend import XendRoot, XendNode, XendConfig from xen.xend.XendBootloader import bootloader -from xen.xend.XendConfig import XendConfig from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices from xen.xend.xenstore.xstransact import xstransact, complete @@ -145,7 +144,7 @@ def create(config): """ log.debug("XendDomainInfo.create(%s)", config) - vm = XendDomainInfo(XendConfig(sxp = config)) + vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config)) try: vm.start() except: @@ -175,10 +174,9 @@ def recreate(info, priv): assert not info['dying'] - xeninfo = XendConfig(cfg = info) + xeninfo = XendConfig.XendConfig(dominfo = info) domid = xeninfo['domid'] - uuid1 = xeninfo['handle'] - xeninfo['uuid'] = uuid.toString(uuid1) + uuid1 = uuid.fromString(xeninfo['uuid']) needs_reinitialising = False dompath = GetDomainPath(domid) @@ -236,7 +234,7 @@ def recreate(info, priv): def restore(config): """Create a domain and a VM object to do a restore. - @param config: Domain configuration object + @param config: Domain SXP configuration @type config: list of lists. (see C{create}) @rtype: XendDomainInfo @@ -246,7 +244,8 @@ def restore(config): """ log.debug("XendDomainInfo.restore(%s)", config) - vm = XendDomainInfo(XendConfig(sxp = config), resume = True) + vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config), + resume = True) try: vm.resume() return vm @@ -254,24 +253,24 @@ def restore(config): vm.destroy() raise -def createDormant(xeninfo): +def createDormant(domconfig): """Create a dormant/inactive XenDomainInfo without creating VM. This is for creating instances of persistent domains that are not yet start. - @param xeninfo: Parsed configuration - @type xeninfo: dictionary + @param domconfig: Parsed configuration + @type domconfig: XendConfig object @rtype: XendDomainInfo @return: A up and running XendDomainInfo instance @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.createDormant(%s)", xeninfo) + log.debug("XendDomainInfo.createDormant(%s)", domconfig) # domid does not make sense for non-running domains. - xeninfo.pop('domid', None) - vm = XendDomainInfo(XendConfig(cfg = xeninfo)) + domconfig.pop('domid', None) + vm = XendDomainInfo(domconfig) return vm def domain_by_name(name): @@ -383,14 +382,6 @@ class XendDomainInfo: #if not self._infoIsSet('uuid'): # self.info['uuid'] = uuid.toString(uuid.create()) - #REMOVE: domid logic can be shortened - #if domid is not None: - # self.domid = domid - #elif info.has_key('dom'): - # self.domid = int(info['dom']) - #else: - # self.domid = None - self.vmpath = XS_VMROOT + self.info['uuid'] self.dompath = dompath @@ -403,6 +394,7 @@ class XendDomainInfo: self.vmWatch = None self.shutdownWatch = None self.shutdownStartTime = None + self._resume = resume self.state = DOM_STATE_HALTED self.state_updated = threading.Condition() @@ -416,8 +408,7 @@ class XendDomainInfo: if augment: self._augmentInfo(priv) - self._checkName(self.info['name']) - self.setResume(resume) + self._checkName(self.info['name_label']) # @@ -477,7 +468,7 @@ class XendDomainInfo: if self.domid == 0: raise XendError('Domain 0 cannot be shutdown') - if not reason in DOMAIN_SHUTDOWN_REASONS.values(): + if reason not in DOMAIN_SHUTDOWN_REASONS.values(): raise XendError('Invalid reason: %s' % reason) self._storeDom("control/shutdown", reason) @@ -512,12 +503,14 @@ class XendDomainInfo: """Create a new device. @param dev_config: device configuration - @type dev_config: dictionary (parsed config) + @type dev_config: SXP object (parsed config) """ log.debug("XendDomainInfo.device_create: %s" % dev_config) dev_type = sxp.name(dev_config) - devid = self._createDevice(dev_type, dev_config) - self.info.device_add(dev_type, cfg_sxp = dev_config) + dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) + dev_config_dict = self.info['devices'][dev_uuid][1] + log.debug("XendDomainInfo.device_create: %s" % dev_config_dict) + devid = self._createDevice(dev_type, dev_config_dict) self._waitForDevice(dev_type, devid) return self.getDeviceController(dev_type).sxpr(devid) @@ -525,12 +518,26 @@ class XendDomainInfo: """Configure an existing device. @param dev_config: device configuration - @type dev_config: dictionary (parsed config) + @type dev_config: SXP object (parsed config) @param devid: device id @type devid: int + @return: Returns True if successfully updated device + @rtype: boolean """ deviceClass = sxp.name(dev_config) - self._reconfigureDevice(deviceClass, devid, dev_config) + + # look up uuid of the device + dev_control = self.getDeviceController(deviceClass) + dev_sxpr = dev_control.sxpr(devid) + dev_uuid = sxp.child_value(sxpr, 'uuid') + if not dev_uuid: + return False + + self.info.device_update(dev_uuid, dev_config) + dev_config_dict = self.info['devices'].get(dev_uuid) + if dev_config_dict: + dev_control.reconfigureDevice(devid, dev_config_dict[1]) + return True def waitForDevices(self): """Wait for this domain's configured devices to connect. @@ -567,12 +574,12 @@ class XendDomainInfo: @param target: In MiB. """ log.debug("Setting memory target of domain %s (%d) to %d MiB.", - self.info['name'], self.domid, target) + self.info['name_label'], self.domid, target) if target <= 0: raise XendError('Invalid memory size') - self.info['memory'] = target + self.info['memory_static_min'] = target self.storeVm("memory", target) self._storeDom("memory/target", target << 10) @@ -581,8 +588,8 @@ class XendDomainInfo: # We include the domain name and ID, to help xm. sxpr = ['domain', ['domid', self.domid], - ['name', self.info['name']], - ['vcpu_count', self.info['online_vcpus']]] + ['name', self.info['name_label']], + ['vcpu_count', self.info['vcpus_number']]] for i in range(0, self.info['max_vcpu_id']+1): info = xc.vcpu_getinfo(self.domid, i) @@ -610,30 +617,40 @@ class XendDomainInfo: values taken from the store. This recovers those values known to xend but not to the hypervisor. """ - def useIfNeeded(name, val): - if not self._infoIsSet(name) and val is not None: - self.info[name] = val - + augment_entries = XendConfig.LEGACY_XENSTORE_VM_PARAMS[:] if priv: - entries = VM_STORE_ENTRIES[:] - entries.remove(('memory', int)) - entries.remove(('maxmem', int)) - else: - entries = VM_STORE_ENTRIES - entries.append(('image', str)) - entries.append(('security', str)) + augment_entries.remove('memory') + augment_entries.remove('maxmem') - map(lambda x, y: useIfNeeded(x[0], y), entries, - self._readVMDetails(entries)) + vm_config = self._readVMDetails([(k, XendConfig.LEGACY_CFG_TYPES[k]) + for k in augment_entries]) + + # make returned lists into a dictionary + vm_config = dict(zip(augment_entries, vm_config)) + + for arg in augment_entries: + xapicfg = arg + val = vm_config[arg] + if val != None: + if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: + xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] + self.info[xapiarg] = val + else: + self.info[arg] = val + # read image value + image_sxp = self._readVm('image') + if image_sxp: + self.info.update_with_image_sxp(sxp.from_string(image_sxp)) + + # read devices devices = [] - for devclass in XendDevices.valid_devices(): devconfig = self.getDeviceController(devclass).configurations() if devconfig: devices.extend(map(lambda conf: (devclass, conf), devconfig)) - if not self.info['device'] and devices is not None: + if not self.info['devices'] and devices is not None: for device in devices: self.info.device_add(device[0], cfg_sxp = device) @@ -678,16 +695,16 @@ class XendDomainInfo: def _recreateDomFunc(self, t): t.remove() t.mkdir() - t.set_permissions({ 'dom' : self.domid }) + t.set_permissions({'dom' : self.domid}) t.write('vm', self.vmpath) def _storeDomDetails(self): to_store = { 'domid': str(self.domid), 'vm': self.vmpath, - 'name': self.info['name'], + 'name': self.info['name_label'], 'console/limit': str(xroot.get_console_limit() * 1024), - 'memory/target': str(self.info['memory'] * 1024) + 'memory/target': str(self.info['memory_static_min'] * 1024) } def f(n, v): @@ -713,7 +730,7 @@ class XendDomainInfo: return 'offline' result = {} - for v in range(0, self.info['vcpus']): + for v in range(0, self.info['vcpus_number']): result["cpu/%d/availability" % v] = availability(v) return result @@ -735,19 +752,29 @@ class XendDomainInfo: log.trace("XendDomainInfo.storeChanged"); changed = False + + # Check whether values in the configuration have + # changed in Xenstore. - def f(x, y): - if y is not None and self.info[x[0]] != y: - self.info[x[0]] = y - changed = True + cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash'] + + vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k]) + for k in cfg_vm]) - map(f, VM_CONFIG_PARAMS, self._readVMDetails(VM_CONFIG_PARAMS)) + # convert two lists into a python dictionary + vm_details = dict(zip(cfg_vm, vm_details)) + + for arg, val in vm_details.items(): + if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: + xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] + if val != None and val != self.info[xapiarg]: + self.info[xapiarg] = val + changed= True - im = self._readVm('image') - current_im = self.info['image'] - if (im is not None and - (current_im is None or sxp.to_string(current_im) != im)): - self.info['image'] = sxp.from_string(im) + # Check whether image definition has been updated + image_sxp = self._readVm('image') + if image_sxp and image_sxp != self.info.image_sxpr(): + self.info.update_with_image_sxp(sxp.from_string(image_sxp)) changed = True if changed: @@ -791,11 +818,11 @@ class XendDomainInfo: def setName(self, name): self._checkName(name) - self.info['name'] = name + self.info['name_label'] = name self.storeVm("name", name) def getName(self): - return self.info['name'] + return self.info['name_label'] def getDomainPath(self): return self.dompath @@ -816,7 +843,7 @@ class XendDomainInfo: return self.info['features'] def getVCpuCount(self): - return self.info['vcpus'] + return self.info['vcpus_number'] def setVCpuCount(self, vcpus): self.info['vcpu_avail'] = (1 << vcpus) - 1 @@ -828,19 +855,19 @@ class XendDomainInfo: def getMemoryTarget(self): """Get this domain's target memory size, in KB.""" - return self.info['memory'] * 1024 + return self.info['memory_static_min'] * 1024 def getResume(self): - return "%s" % self.info['resume'] + return str(self._resume) def getCap(self): - return self.info['cpu_cap'] + return self.info.get('cpu_cap', 0) def getWeight(self): return self.info['cpu_weight'] def setResume(self, state): - self.info['resume'] = state + self._resume = state def getRestartCount(self): return self._readVm('xend/restart_count') @@ -891,7 +918,7 @@ class XendDomainInfo: return log.warn('Domain has crashed: name=%s id=%d.', - self.info['name'], self.domid) + self.info['name_label'], self.domid) if xroot.get_enable_dump(): self.dumpCore() @@ -910,7 +937,7 @@ class XendDomainInfo: reason = shutdown_reason(xeninfo['shutdown_reason']) log.info('Domain has shutdown: name=%s id=%d reason=%s.', - self.info['name'], self.domid, reason) + self.info['name_label'], self.domid, reason) self._clearRestart() @@ -945,7 +972,7 @@ class XendDomainInfo: if timeout < 0: log.info( "Domain shutdown timeout expired: name=%s id=%s", - self.info['name'], self.domid) + self.info['name_label'], self.domid) self.destroy() finally: self.refresh_shutdown_lock.release() @@ -965,11 +992,23 @@ class XendDomainInfo: def _maybeRestart(self, reason): # Dispatch to the correct method based upon the configured on_{reason} # behaviour. - {"destroy" : self.destroy, - "restart" : self._restart, - "preserve" : self._preserve, - "rename-restart" : self._renameRestart}[self.info['on_' + reason]]() + actions = {"destroy" : self.destroy, + "restart" : self._restart, + "preserve" : self._preserve, + "rename-restart" : self._renameRestart} + action_conf = { + 'poweroff': 'actions_after_shutdown', + 'reboot': 'actions_after_reboot', + 'crash': 'actions_after_crash', + } + + action_target = self.info.get(action_conf.get(reason)) + func = actions.get(action_target, None) + if func and callable(func): + func() + else: + self.destroy() # default to destroy def _renameRestart(self): self._restart(True) @@ -1008,7 +1047,7 @@ class XendDomainInfo: log.error( 'VM %s restarting too fast (%f seconds since the last ' 'restart). Refusing to restart to avoid loops.', - self.info['name'], timeout) + self.info['name_label'], timeout) self.destroy() return @@ -1055,11 +1094,11 @@ class XendDomainInfo: new_uuid = uuid.createString() new_name = 'Domain-%s' % new_uuid log.info("Renaming dead domain %s (%d, %s) to %s (%s).", - self.info['name'], self.domid, self.info['uuid'], + self.info['name_label'], self.domid, self.info['uuid'], new_name, new_uuid) self._unwatchVm() self._releaseDevices() - self.info['name'] = new_name + self.info['name_label'] = new_name self.info['uuid'] = new_uuid self.vmpath = XS_VMROOT + new_uuid self._storeVmDetails() @@ -1067,7 +1106,7 @@ class XendDomainInfo: def _preserve(self): - log.info("Preserving dead domain %s (%d).", self.info['name'], + log.info("Preserving dead domain %s (%d).", self.info['name_label'], self.domid) self._unwatchVm() self._storeDom('xend/shutdown_completed', 'True') @@ -1084,7 +1123,7 @@ class XendDomainInfo: if not corefile: this_time = time.strftime("%Y-%m%d-%H%M.%S", time.localtime()) corefile = "/var/xen/dump/%s-%s.%s.core" % (this_time, - self.info['name'], self.domid) + self.info['name_label'], self.domid) if os.path.isdir(corefile): raise XendError("Cannot dump core in a directory: %s" % @@ -1095,7 +1134,7 @@ class XendDomainInfo: corefile_incomp = corefile+'-incomplete' os.rename(corefile, corefile_incomp) log.exception("XendDomainInfo.dumpCore failed: id = %s name = %s", - self.domid, self.info['name']) + self.domid, self.info['name_label']) raise XendError("Failed to dump core: %s" % str(ex)) # @@ -1117,8 +1156,8 @@ class XendDomainInfo: @raise: VmError for invalid devices """ - for (devclass, config) in self.info.all_devices_sxpr(): - if devclass in XendDevices.valid_devices(): + for (devclass, config) in self.info.get('devices', {}).values(): + if devclass in XendDevices.valid_devices(): log.info("createDevice: %s : %s" % (devclass, config)) self._createDevice(devclass, config) @@ -1139,7 +1178,7 @@ class XendDomainInfo: # there's nothing more we can do. log.exception( "Device release failed: %s; %s; %s", - self.info['name'], devclass, dev) + self.info['name_label'], devclass, dev) if t.commit(): break @@ -1211,11 +1250,12 @@ class XendDomainInfo: log.debug('XendDomainInfo.constructDomain') - hvm = (self._infoIsSet('image') and - sxp.name(self.info['image']) == "hvm") + image_cfg = self.info.get('image', {}) + hvm = image_cfg.has_key('hvm') + if hvm: info = xc.xeninfo() - if not 'hvm' in info['xen_caps']: + if 'hvm' not in info['xen_caps']: raise VmError("HVM guest support is unavailable: is VT/AMD-V " "supported by your CPU and enabled in your " "BIOS?") @@ -1228,14 +1268,14 @@ class XendDomainInfo: if self.domid < 0: raise VmError('Creating domain failed: name=%s' % - self.info['name']) + self.info['name_label']) self.dompath = GetDomainPath(self.domid) self._recreateDom() # Set maximum number of vcpus in domain - xc.domain_max_vcpus(self.domid, int(self.info['vcpus'])) + xc.domain_max_vcpus(self.domid, int(self.info['vcpus_number'])) def _introduceDomain(self): @@ -1256,7 +1296,7 @@ class XendDomainInfo: # if we have a boot loader but no image, then we need to set things # up by running the boot loader non-interactively - if self._infoIsSet('bootloader') and not self._infoIsSet('image'): + if self.info.get('bootloader') and self.info.get('image'): self._configureBootloader() if not self._infoIsSet('image'): @@ -1264,8 +1304,9 @@ class XendDomainInfo: try: self.image = image.create(self, + self.info, self.info['image'], - self.info.all_devices_sxpr()) + self.info['devices']) localtime = self.info.get('localtime', 0) if localtime is not None and localtime == 1: @@ -1284,12 +1325,12 @@ class XendDomainInfo: # the various headrooms necessary, given the raw configured # values. maxmem, memory, and shadow are all in KiB. maxmem = self.image.getRequiredAvailableMemory( - self.info['maxmem'] * 1024) + self.info['memory_static_min'] * 1024) memory = self.image.getRequiredAvailableMemory( - self.info['memory'] * 1024) + self.info['memory_static_max'] * 1024) shadow = self.image.getRequiredShadowMemory( self.info['shadow_memory'] * 1024, - self.info['maxmem'] * 1024) + self.info['memory_static_max'] * 1024) # Round shadow up to a multiple of a MiB, as shadow_mem_control # takes MiB and we must not round down and end up under-providing. @@ -1317,7 +1358,7 @@ class XendDomainInfo: self._createDevices() - if self.info['bootloader'] not in [None, 'kernel_external']: + if self.info['bootloader']: self.image.cleanupBootloading() self.info['start_time'] = time.time() @@ -1325,7 +1366,7 @@ class XendDomainInfo: self._stateSet(DOM_STATE_RUNNING) except RuntimeError, exn: log.exception("XendDomainInfo.initDomain: exception occurred") - if self.info['bootloader'] not in [None, 'kernel_external'] \ + if self.info['bootloader'] not in (None, 'kernel_external') \ and self.image is not None: self.image.cleanupBootloading() raise VmError(str(exn)) @@ -1338,7 +1379,6 @@ class XendDomainInfo: self.refresh_shutdown_lock.acquire() try: self.unwatchShutdown() - self._releaseDevices() if self.image: @@ -1459,14 +1499,14 @@ class XendDomainInfo: def _configureBootloader(self): """Run the bootloader if we're configured to do so.""" - if not self.info['bootloader']: + if not self.info.get('bootloader'): return blcfg = None # FIXME: this assumes that we want to use the first disk device - for (n, c) in self.info.all_devices_sxpr(): - if not n or not c or not(n in ["vbd", "tap"]): + for devuuid, (devtype, devinfo) in self.info.all_devices_sxpr(): + if not devtype or not devinfo or devtype not in ('vbd', 'tap'): continue - disk = sxp.child_value(c, "uname") + disk = devinfo.get('uname') if disk is None: continue fn = blkdev_uname_to_file(disk) @@ -1478,7 +1518,8 @@ class XendDomainInfo: msg = "Had a bootloader specified, but can't find disk" log.error(msg) raise VmError(msg) - self.info['image'] = blcfg + + self.info.update_with_image_sxp(blcfg) # # VM Functions @@ -1516,7 +1557,8 @@ class XendDomainInfo: if arch.type == "x86": # 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than # the minimum that Xen would allocate if no value were given. - overhead_kb = self.info['vcpus'] * 1024 + self.info['maxmem'] * 4 + overhead_kb = self.info['vcpus_number'] * 1024 + \ + self.info['memory_static_max'] * 4 overhead_kb = ((overhead_kb + 1023) / 1024) * 1024 # The domain might already have some shadow memory overhead_kb -= xc.shadow_mem_control(self.domid) * 1024 @@ -1558,12 +1600,15 @@ class XendDomainInfo: def _storeVmDetails(self): to_store = {} - for k in VM_STORE_ENTRIES: - if self._infoIsSet(k[0]): - to_store[k[0]] = str(self.info[k[0]]) + for key in XendConfig.LEGACY_XENSTORE_VM_PARAMS: + info_key = XendConfig.LEGACY_CFG_TO_XENAPI_CFG.get(key, key) + if self._infoIsSet(info_key): + to_store[key] = str(self.info[info_key]) - if self._infoIsSet('image'): - to_store['image'] = sxp.to_string(self.info['image']) + if self.info.get('image'): + image_sxpr = self.info.image_sxpr() + if image_sxpr: + to_store['image'] = sxp.to_string(image_sxpr) if self._infoIsSet('security'): secinfo = self.info['security'] @@ -1656,6 +1701,7 @@ class XendDomainInfo: #create new security element self.info.update({'security': [['ssidref', str(info['ssidref'])]]}) + #ssidref field not used any longer if 'ssidref' in info: info.pop('ssidref') @@ -1663,8 +1709,7 @@ class XendDomainInfo: # make sure state is reset for info # TODO: we should eventually get rid of old_dom_states - self.info.update(info) - self.info.validate() + self.info.update_config(info) if refresh: self.refreshShutdown(info) @@ -1673,7 +1718,7 @@ class XendDomainInfo: str(self.domid), self.info) def sxpr(self, ignore_store = False): - result = self.info.get_sxp(domain = self, + result = self.info.to_sxp(domain = self, ignore_devices = ignore_store) if not ignore_store and self.dompath: @@ -1695,9 +1740,15 @@ class XendDomainInfo: return dom_uuid def get_memory_static_max(self): - return self.info['maxmem'] + return self.info['memory_static_max'] def get_memory_static_min(self): - return self.info['memory'] + return self.info['memory_static_min'] + def get_memory_dynamic_max(self): + return self.info['memory_dynamic_min'] + def get_memory_dynamic_min(self): + return self.info['memory_static_min'] + + def get_vcpus_policy(self): sched_id = xc.sched_id_get() if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF: @@ -1717,21 +1768,17 @@ class XendDomainInfo: def get_platform_keymap(self): return '' def get_platform_serial(self): - return '' # TODO + return self.info['platform_serial'] def get_platform_localtime(self): - return False # TODO + return self.info['platform_localtime'] def get_platform_clock_offset(self): - return False # TODO + return self.info['platform_clock_offset'] def get_platform_enable_audio(self): - return False # TODO + return self.info['platform_enable_audio'] def get_builder(self): - return 'Linux' # TODO + return self.info['builder'] def get_boot_method(self): - bootloader = self.info['bootloader'] - if not bootloader or bootloader not in XEN_API_BOOT_TYPE: - return 'kernel_external' - return bootloader - + return self.info['boot_method'] def get_kernel_image(self): return self.info['kernel_kernel'] def get_kernel_initrd(self): @@ -1748,25 +1795,26 @@ class XendDomainInfo: return {} # TODO def get_on_shutdown(self): - after_shutdown = self.info.get('on_poweroff') + after_shutdown = self.info.get('action_after_shutdown') if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_shutdown def get_on_reboot(self): - after_reboot = self.info.get('on_reboot') + after_reboot = self.info.get('action_after_reboot') if not after_reboot or after_reboot not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_reboot def get_on_suspend(self): - after_suspend = self.info.get('on_suspend') # TODO: not supported + # TODO: not supported + after_suspend = self.info.get('action_after_suspend') if not after_suspend or after_suspend not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_suspend def get_on_crash(self): - after_crash = self.info.get('on_crash') + after_crash = self.info.get('action_after_crash') if not after_crash or after_crash not in XEN_API_ON_CRASH_BEHAVIOUR: return XEN_API_ON_CRASH_BEHAVIOUR[0] return after_crash @@ -1780,7 +1828,7 @@ class XendDomainInfo: @rtype: dictionary """ - dev_type_config = self.info['device'].get(dev_uuid) + dev_type_config = self.info['devices'].get(dev_uuid) # shortcut if the domain isn't started because # the devcontrollers will have no better information @@ -1840,7 +1888,7 @@ class XendDomainInfo: config['IO_bandwidth_incoming_kbs'] = 0.0 config['IO_bandwidth_outgoing_kbs'] = 0.0 - if dev_class =='vbd': + if dev_class == 'vbd': config['VDI'] = '' # TODO config['device'] = config.get('dev', '') config['driver'] = 'paravirtualised' # TODO @@ -1984,8 +2032,8 @@ class XendDomainInfo: def __str__(self): return '' % \ - (str(self.domid), self.info['name'], - str(self.info['memory']), DOM_STATES[self.state]) + (str(self.domid), self.info['name_label'], + str(self.info['memory_static_min']), DOM_STATES[self.state]) __repr__ = __str__ diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 546e6eca38..98397d76ca 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -23,7 +23,6 @@ import math import signal import xen.lowlevel.xc -from xen.xend import sxp from xen.xend.XendError import VmError, XendError from xen.xend.XendLogging import log from xen.xend.server.netif import randomMAC @@ -31,19 +30,18 @@ from xen.xend.xenstore.xswatch import xswatch from xen.xend import arch from xen.xend import FlatDeviceTree - xc = xen.lowlevel.xc.xc() - MAX_GUEST_CMDLINE = 1024 -def create(vm, imageConfig, deviceConfig): +def create(vm, vmConfig, imageConfig, deviceConfig): """Create an image handler for a vm. @return ImageHandler instance """ - return findImageHandlerClass(imageConfig)(vm, imageConfig, deviceConfig) + return findImageHandlerClass(imageConfig)(vm, vmConfig, imageConfig, + deviceConfig) class ImageHandler: @@ -66,34 +64,20 @@ class ImageHandler: ostype = None - def __init__(self, vm, imageConfig, deviceConfig): + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): self.vm = vm self.kernel = None self.ramdisk = None self.cmdline = None - self.configure(imageConfig, deviceConfig) + self.configure(vmConfig, imageConfig, deviceConfig) - def configure(self, imageConfig, _): + def configure(self, vmConfig, imageConfig, _): """Config actions common to all unix-like domains.""" - - def get_cfg(name, default = None): - return sxp.child_value(imageConfig, name, default) - - self.kernel = get_cfg("kernel") - self.cmdline = "" - ip = get_cfg("ip") - if ip: - self.cmdline += " ip=" + ip - root = get_cfg("root") - if root: - self.cmdline += " root=" + root - args = get_cfg("args") - if args: - self.cmdline += " " + args - self.ramdisk = get_cfg("ramdisk", '') - + self.kernel = vmConfig['kernel_kernel'] + self.cmdline = vmConfig['kernel_args'] + self.ramdisk = vmConfig['kernel_initrd'] self.vm.storeVm(("image/ostype", self.ostype), ("image/kernel", self.kernel), ("image/cmdline", self.cmdline), @@ -214,8 +198,8 @@ class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" - def configure(self, imageConfig, deviceConfig): - LinuxImageHandler.configure(self, imageConfig, deviceConfig) + def configure(self, vmConfig, imageConfig, deviceConfig): + LinuxImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) self.imageConfig = imageConfig def buildDomain(self): @@ -248,25 +232,26 @@ class PPC_LinuxImageHandler(LinuxImageHandler): class HVMImageHandler(ImageHandler): - def __init__(self, vm, imageConfig, deviceConfig): - ImageHandler.__init__(self, vm, imageConfig, deviceConfig) + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): + ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig) self.shutdownWatch = None - def configure(self, imageConfig, deviceConfig): - ImageHandler.configure(self, imageConfig, deviceConfig) + def configure(self, vmConfig, imageConfig, deviceConfig): + ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) info = xc.xeninfo() - if not 'hvm' in info['xen_caps']: + if 'hvm' not in info['xen_caps']: raise VmError("HVM guest support is unavailable: is VT/AMD-V " "supported by your CPU and enabled in your BIOS?") self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig) - self.device_model = sxp.child_value(imageConfig, 'device_model') + self.device_model = imageConfig['hvm'].get('device_model') if not self.device_model: raise VmError("hvm: missing device model") - self.display = sxp.child_value(imageConfig, 'display') - self.xauthority = sxp.child_value(imageConfig, 'xauthority') - self.vncconsole = sxp.child_value(imageConfig, 'vncconsole') + + self.display = imageConfig['hvm'].get('display') + self.xauthority = imageConfig['hvm'].get('xauthority') + self.vncconsole = imageConfig['hvm'].get('vncconsole') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), @@ -276,9 +261,9 @@ class HVMImageHandler(ImageHandler): self.dmargs += self.configVNC(imageConfig) - self.pae = int(sxp.child_value(imageConfig, 'pae', 1)) - self.acpi = int(sxp.child_value(imageConfig, 'acpi', 1)) - self.apic = int(sxp.child_value(imageConfig, 'apic', 1)) + self.pae = imageConfig['hvm'].get('pae', 0) + self.acpi = imageConfig['hvm'].get('acpi', 0) + self.apic = imageConfig['hvm'].get('apic', 0) def buildDomain(self): store_evtchn = self.vm.getStorePort() @@ -312,8 +297,12 @@ class HVMImageHandler(ImageHandler): 'localtime', 'serial', 'stdvga', 'isa', 'vcpus', 'acpi', 'usb', 'usbdevice', 'keymap' ] ret = [] + hvmDeviceConfig = imageConfig['hvm']['devices'] + for a in dmargs: - v = sxp.child_value(imageConfig, a) + v = hvmDeviceConfig.get(a) + if a == 'vcpus': + v = hvmDeviceConfig.get('vcpus_number') # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' @@ -328,7 +317,7 @@ class HVMImageHandler(ImageHandler): ret.append("-%s" % a) ret.append("%s" % v) - if a in ['fda', 'fdb' ]: + if a in ['fda', 'fdb']: if v: if not os.path.isabs(v): raise VmError("Floppy file %s does not exist." % v) @@ -336,26 +325,27 @@ class HVMImageHandler(ImageHandler): # Handle disk/network related options mac = None - ret = ret + ["-domain-name", "%s" % self.vm.info['name']] + ret = ret + ["-domain-name", str(self.vm.info['name_label'])] nics = 0 - for (name, info) in deviceConfig: - if name == 'vbd': - uname = sxp.child_value(info, 'uname') + + for devuuid, (devtype, devinfo) in deviceConfig.items(): + if devtype == 'vbd': + uname = devinfo['uname'] if uname is not None and 'file:' in uname: (_, vbdparam) = string.split(uname, ':', 1) if not os.path.isfile(vbdparam): raise VmError('Disk image does not exist: %s' % vbdparam) - if name == 'vif': - type = sxp.child_value(info, 'type') - if type != 'ioemu': + if devtype == 'vif': + dtype = devinfo.get('type', 'ioemu') + if dtype != 'ioemu': continue nics += 1 - mac = sxp.child_value(info, 'mac') + mac = devinfo.get('mac') if mac == None: mac = randomMAC() - bridge = sxp.child_value(info, 'bridge', 'xenbr0') - model = sxp.child_value(info, 'model', 'rtl8139') + bridge = devinfo.get('bridge', 'xenbr0') + model = devinfo.get('model', 'rtl8139') ret.append("-net") ret.append("nic,vlan=%d,macaddr=%s,model=%s" % (nics, mac, model)) @@ -363,31 +353,32 @@ class HVMImageHandler(ImageHandler): ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) return ret - def configVNC(self, config): + def configVNC(self, imageConfig): # Handle graphics library related options - vnc = sxp.child_value(config, 'vnc') - sdl = sxp.child_value(config, 'sdl') + vnc = imageConfig.get('vnc') + sdl = imageConfig.get('sdl') ret = [] - nographic = sxp.child_value(config, 'nographic') + nographic = imageConfig.get('nographic') # get password from VM config (if password omitted, None) - vncpasswd_vmconfig = sxp.child_value(config, 'vncpasswd') + vncpasswd_vmconfig = imageConfig.get('vncpasswd') if nographic: ret.append('-nographic') return ret if vnc: - vncdisplay = int(sxp.child_value(config, 'vncdisplay', - self.vm.getDomid())) + vncdisplay = imageConfig.get('vncdisplay', + int(self.vm.getDomid())) + vncunused = imageConfig.get('vncunused') - vncunused = sxp.child_value(config, 'vncunused') if vncunused: ret += ['-vncunused'] else: ret += ['-vnc', '%d' % vncdisplay] - vnclisten = sxp.child_value(config, 'vnclisten') + vnclisten = imageConfig.get('vnclisten') + if not(vnclisten): vnclisten = (xen.xend.XendRoot.instance(). get_vnclisten_address()) @@ -423,21 +414,26 @@ class HVMImageHandler(ImageHandler): if self.vncconsole: args = args + ([ "-vncviewer" ]) log.info("spawning device models: %s %s", self.device_model, args) + # keep track of pid and spawned options to kill it later self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) log.info("device model pid: %d", self.pid) def destroy(self): - self.unregister_shutdown_watch(); + self.unregister_shutdown_watch() if not self.pid: return - os.kill(self.pid, signal.SIGKILL) - os.waitpid(self.pid, 0) + try: + os.kill(self.pid, signal.SIGKILL) + os.waitpid(self.pid, 0) + except OSError, e: + log.warning("Unable to kill device model (pid: %d)" % self.pid) + self.pid = 0 def register_shutdown_watch(self): """ add xen store watch on control/shutdown """ - self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", \ - self.hvm_shutdown) + self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", + self.hvm_shutdown) log.debug("hvm shutdown watch registered") def unregister_shutdown_watch(self): @@ -529,10 +525,10 @@ def findImageHandlerClass(image): @param image config @return ImageHandler subclass or None """ - type = sxp.name(image) - if type is None: + image_type = image['type'] + if image_type is None: raise VmError('missing image type') try: - return _handlers[arch.type][type] + return _handlers[arch.type][image_type] except KeyError: - raise VmError('unknown image type: ' + type) + raise VmError('unknown image type: ' + image_type) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index cbe3b18845..646e19d9de 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -17,6 +17,7 @@ #============================================================================ from threading import Event +import types from xen.xend import sxp from xen.xend.XendError import VmError @@ -86,7 +87,7 @@ class DevController: import xen.xend.XendDomain xd = xen.xend.XendDomain.instance() - backdom_name = sxp.child_value(config, 'backend') + backdom_name = config.get('backend') if backdom_name is None: backdom = xen.xend.XendDomain.DOM0_ID else: @@ -223,7 +224,7 @@ class DevController: configDict = self.getDeviceConfiguration(devid) sxpr = [self.deviceClass] for key, val in configDict.items(): - if type(val) == type(list()): + if isinstance(val, (types.ListType, types.TupleType)): for v in val: sxpr.append([key, v]) else: @@ -405,7 +406,7 @@ class DevController: import xen.xend.XendDomain xd = xen.xend.XendDomain.instance() - backdom_name = sxp.child_value(config, 'backend') + backdom_name = config.get('backend') if backdom_name: backdom = xd.domain_lookup_nr(backdom_name) else: diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 6bd49acfc9..16e2c5052d 100644 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -21,7 +21,6 @@ import string from xen.util import blkif from xen.util import security -from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -37,9 +36,9 @@ class BlkifController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - uname = sxp.child_value(config, 'uname', '') - dev = sxp.child_value(config, 'dev', '') - + uname = config.get('uname', '') + dev = config.get('dev', '') + if 'ioemu:' in dev: (_, dev) = string.split(dev, ':', 1) try: @@ -59,17 +58,17 @@ class BlkifController(DevController): except ValueError: (typ, params) = ("", "") - mode = sxp.child_value(config, 'mode', 'r') + mode = config.get('mode', 'r') if mode not in ('r', 'w', 'w!'): raise VmError('Invalid mode') - back = { 'dev' : dev, - 'type' : typ, - 'params' : params, - 'mode' : mode - } + back = {'dev' : dev, + 'type' : typ, + 'params' : params, + 'mode' : mode, + } - uuid = sxp.child_value(config, 'uuid') + uuid = config.get('uuid') if uuid: back['uuid'] = uuid diff --git a/tools/python/xen/xend/server/iopif.py b/tools/python/xen/xend/server/iopif.py index 96651a7c95..3b1a263736 100644 --- a/tools/python/xen/xend/server/iopif.py +++ b/tools/python/xen/xend/server/iopif.py @@ -22,7 +22,6 @@ import types import xen.lowlevel.xc -from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -49,13 +48,12 @@ class IOPortsController(DevController): def __init__(self, vm): DevController.__init__(self, vm) - def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" def get_param(field): try: - val = sxp.child_value(config, field) + val = config.get(field) if not val: raise VmError('ioports: Missing %s config setting' % field) diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py index 6e539dbab9..346ad7cf4d 100644 --- a/tools/python/xen/xend/server/irqif.py +++ b/tools/python/xen/xend/server/irqif.py @@ -45,7 +45,7 @@ class IRQController(DevController): def get_param(field): try: - val = sxp.child_value(config, field) + val = config.get(field) if not val: raise VmError('irq: Missing %s config setting' % field) diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 4c7e359617..a20929a0d9 100644 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -24,7 +24,6 @@ import os import random import re -from xen.xend import sxp from xen.xend import XendRoot from xen.xend.server.DevController import DevController @@ -139,22 +138,15 @@ class NetifController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - def _get_config_ipaddr(config): - val = [] - for ipaddr in sxp.children(config, elt='ip'): - val.append(sxp.child0(ipaddr)) - return val - script = os.path.join(xroot.network_script_dir, - sxp.child_value(config, 'script', - xroot.get_vif_script())) - typ = sxp.child_value(config, 'type') - bridge = sxp.child_value(config, 'bridge') - mac = sxp.child_value(config, 'mac') - vifname = sxp.child_value(config, 'vifname') - rate = sxp.child_value(config, 'rate') - uuid = sxp.child_value(config, 'uuid') - ipaddr = _get_config_ipaddr(config) + config.get('script', xroot.get_vif_script())) + typ = config.get('type') + bridge = config.get('bridge') + mac = config.get('mac') + vifname = config.get('vifname') + rate = config.get('rate') + uuid = config.get('uuid') + ipaddr = config.get('ip') devid = self.allocateDeviceID() diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index eaab90529f..68af9d78cc 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -53,60 +53,29 @@ class PciController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - #log.debug('pci config='+sxp.to_string(config)) - - def get_param(config, field, default=None): + def parse_hex(val): try: - val = sxp.child_value(config, field) - - if not val: - if default==None: - raise VmError('pci: Missing %s config setting' % field) - else: - return default - if isinstance(val, types.StringTypes): return int(val, 16) else: return val - except: - if default==None: - raise VmError('pci: Invalid config setting %s: %s' % - (field, val)) - else: - return default - - back = {} - - val = sxp.child_value(config, 'dev') - if isinstance(val, (types.ListType, types.TupleType)): - pcidevid = 0 - for dev_config in sxp.children(config, 'dev'): - domain = get_param(dev_config, 'domain', 0) - bus = get_param(dev_config,'bus') - slot = get_param(dev_config,'slot') - func = get_param(dev_config,'func') - - self.setupDevice(domain, bus, slot, func) - - back['dev-%i' % pcidevid]="%04x:%02x:%02x.%02x"% \ - (domain, bus, slot, func) - pcidevid+=1 + except ValueError: + return None - back['num_devs']=str(pcidevid) - - else: - # Xen 2.0 configuration compatibility - domain = get_param(config, 'domain', 0) - bus = get_param(config, 'bus') - slot = get_param(config, 'dev') - func = get_param(config, 'func') - + back = {} + pcidevid = 0 + for pci_config in config.get('devs', []): + domain = parse_hex(pci_config.get('domain', 0)) + bus = parse_hex(pci_config.get('bus', 0)) + slot = parse_hex(pci_config.get('slot', 0)) + func = parse_hex(pci_config.get('func', 0)) self.setupDevice(domain, bus, slot, func) + back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \ + (domain, bus, slot, func) + pcidevid += 1 - back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func) - back['num_devs']=str(1) - + back['num_devs']=str(pcidevid) + back['uuid'] = config.get('uuid','') return (0, back, {}) def getDeviceConfiguration(self, devid): @@ -129,7 +98,8 @@ class PciController(DevController): 'slot': '0x%(slot)s' % pci_dev_info, 'func': '0x%(func)s' % pci_dev_info}) - result['dev'] = pci_devs + result['devs'] = pci_devs + result['uuid'] = self.readBackend(devid, 'uuid') return result def configuration(self, devid): @@ -142,7 +112,8 @@ class PciController(DevController): sxpr = [self.deviceClass] # remove devs - devs = configDict.pop('dev', []) + devs = configDict.pop('devs', []) + for dev in devs: dev_sxpr = ['dev'] for dev_item in dev.items(): diff --git a/tools/python/xen/xend/server/pciquirk.py b/tools/python/xen/xend/server/pciquirk.py index ea53eee5b2..c0a4a68c83 100644 --- a/tools/python/xen/xend/server/pciquirk.py +++ b/tools/python/xen/xend/server/pciquirk.py @@ -15,25 +15,24 @@ class PCIQuirk: self.device = device self.subvendor = subvendor self.subdevice = subdevice - self.domain = domain - self.bus = bus - self.slot = slot - self.func = func + self.domain = domain + self.bus = bus + self.slot = slot + self.func = func self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, subdevice) - self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) + self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) + self.quirks = self.__getQuirksByID() - self.quirks = self.__getQuirksByID( ) - - self.__sendQuirks( ) - self.__sendPermDevs( ) + self.__sendQuirks() + self.__sendPermDevs() def __matchPCIdev( self, list ): ret = False if list == None: return False for id in list: - if id.startswith( self.devid[:9] ): # id's vendor and device ID match + if id.startswith(self.devid[:9]): # id's vendor and device ID match skey = id.split(':') size = len(skey) if (size == 2): # subvendor/subdevice not suplied @@ -41,13 +40,13 @@ class PCIQuirk: break elif (size == 4): # check subvendor/subdevice # check subvendor - subven = '%04x' % self.subvendor + subven = '%04x' % self.subvendor if ((skey[2] != 'FFFF') and (skey[2] != 'ffff') and (skey[2] != subven)): continue # check subdevice - subdev = '%04x' % self.subdevice + subdev = '%04x' % self.subdevice if ((skey[3] != 'FFFF') and (skey[3] != 'ffff') and (skey[3] != subdev)): @@ -101,8 +100,8 @@ class PCIQuirk: self.slot, self.func, quirk) ) f.close() except Exception, e: - raise VmError("pci: failed to open/write/close quirks sysfs " + \ - "node - " + str(e)) + raise VmError("pci: failed to open/write/close quirks " + + "sysfs node - " + str(e)) def __devIsUnconstrained( self ): if os.path.exists(PERMISSIVE_CONFIG_FILE): @@ -126,20 +125,22 @@ class PCIQuirk: devices = child_at(child(pci_perm_dev_config, 'unconstrained_dev_ids'),0) if self.__matchPCIdev( devices ): - log.debug("Permissive mode enabled for PCI device [%s]" % self.devid) + log.debug("Permissive mode enabled for PCI device [%s]" % + self.devid) return True - log.debug("Permissive mode NOT enabled for PCI device [%s]" % self.devid) + log.debug("Permissive mode NOT enabled for PCI device [%s]" % + self.devid) return False def __sendPermDevs(self): if self.__devIsUnconstrained( ): - log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % (self.domain, - self.bus, self.slot, self.func)) + log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % + (self.domain, self.bus, self.slot, self.func)) try: f = file(PERMISSIVE_SYSFS_NODE ,"w") f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus, - self.slot, self.func) ) + self.slot, self.func)) f.close() except Exception, e: - raise VmError("pci: failed to open/write/close permissive " + \ - "sysfs node: " + str(e)) + raise VmError("pci: failed to open/write/close permissive " + + "sysfs node: " + str(e)) diff --git a/tools/python/xen/xend/server/tests/test_controllers.py b/tools/python/xen/xend/server/tests/test_controllers.py index 16b7941e5a..aa57f6321c 100644 --- a/tools/python/xen/xend/server/tests/test_controllers.py +++ b/tools/python/xen/xend/server/tests/test_controllers.py @@ -21,13 +21,13 @@ class test_controllers(unittest.TestCase): def testNetif(self): controller = self.controllerInstance(netif.NetifController) - self.assertNetif(controller.getDeviceDetails(['vif']), None) + self.assertNetif(controller.getDeviceDetails({}), None) self.assertNetif( - controller.getDeviceDetails( - ['vif', ['mac', 'aa:bb:cc:dd:ee:ff']]), + controller.getDeviceDetails({'mac': 'aa:bb:cc:dd:ee:ff'}), 'aa:bb:cc:dd:ee:ff') + def assertNetif(self, results, expectedMac): (devid, backdets, frontdets) = results diff --git a/tools/python/xen/xend/server/tpmif.py b/tools/python/xen/xend/server/tpmif.py index 494a197b8e..c2a5f1f64b 100644 --- a/tools/python/xen/xend/server/tpmif.py +++ b/tools/python/xen/xend/server/tpmif.py @@ -18,10 +18,8 @@ # Copyright (C) 2005 XenSource Ltd #============================================================================ -"""Support for virtual TPM interfaces. -""" +"""Support for virtual TPM interfaces.""" -from xen.xend import sxp from xen.xend import XendRoot from xen.xend.XendLogging import log from xen.xend.XendError import XendError @@ -49,12 +47,12 @@ class TPMifController(DevController): """@see DevController.getDeviceDetails""" devid = self.allocateDeviceID() - inst = int(sxp.child_value(config, 'pref_instance', '-1')) + inst = int(config.get('pref_instance', -1)) if inst == -1: - inst = int(sxp.child_value(config, 'instance' , '0')) + inst = int(config.get('instance', 0)) - typ = sxp.child_value(config, 'type') - uuid = sxp.child_value(config, 'uuid') + typ = config.get('type') + uuid = config.get('uuid') log.info("The domain has a TPM with pref. instance %d and devid %d.", inst, devid) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 93d2fe1029..9982dc3388 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -581,8 +581,8 @@ def parse_doms_info(info): return { 'domid' : get_info('domid', str, ''), 'name' : get_info('name', str, '??'), - 'mem' : get_info('memory_dynamic_max', int, 0), - 'vcpus' : get_info('online_vcpus', int, 0), + 'mem' : get_info('memory_dynamic_min', int, 0), + 'vcpus' : get_info('vcpus', int, 0), 'state' : get_info('state', str, ''), 'cpu_time' : get_info('cpu_time', float, 0), 'up_time' : get_info('up_time', float, -1),