diff --git a/virtinst/support.py b/virtinst/support.py index 6a00925b8..a175624a3 100644 --- a/virtinst/support.py +++ b/virtinst/support.py @@ -23,342 +23,6 @@ import libvirt from virtinst import util -# Flags for check_conn_support -(SUPPORT_CONN_STORAGE, - SUPPORT_CONN_FINDPOOLSOURCES, - SUPPORT_CONN_NODEDEV, - SUPPORT_CONN_KEYMAP_AUTODETECT, - SUPPORT_CONN_GETHOSTNAME, - SUPPORT_CONN_DOMAIN_VIDEO, - SUPPORT_CONN_NETWORK, - SUPPORT_CONN_INTERFACE, - SUPPORT_CONN_MAXVCPUS_XML, - SUPPORT_CONN_STREAM, - SUPPORT_CONN_GETVERSION, - SUPPORT_CONN_LIBVERSION, - SUPPORT_CONN_LISTALLDOMAINS, - SUPPORT_CONN_LISTALLNETWORKS, - SUPPORT_CONN_LISTALLSTORAGEPOOLS, - SUPPORT_CONN_LISTALLINTERFACES) = range(1, 17) - -# Flags for check_domain_support -(SUPPORT_DOMAIN_GETVCPUS, - SUPPORT_DOMAIN_XML_SECURE, - SUPPORT_DOMAIN_XML_INACTIVE, - SUPPORT_DOMAIN_MANAGED_SAVE, - SUPPORT_DOMAIN_MIGRATE_DOWNTIME, - SUPPORT_DOMAIN_JOB_INFO, - SUPPORT_DOMAIN_MAXVCPUS_XML, - SUPPORT_DOMAIN_CONSOLE_STREAM, - SUPPORT_DOMAIN_SET_METADATA, - SUPPORT_DOMAIN_CPU_HOST_MODEL) = range(1000, 1010) - -# Flags for check_pool_support -(SUPPORT_STORAGE_CREATEVOLFROM, - SUPPORT_STORAGE_UPLOAD, - SUPPORT_STORAGE_ISACTIVE) = range(2000, 2003) - -# Flags for check_nodedev_support -(SUPPORT_NODEDEV_PCI_DETACH,) = range(3000, 3001) - -# Flags for check_interface_support -(SUPPORT_INTERFACE_XML_INACTIVE, - SUPPORT_INTERFACE_ISACTIVE) = range(4000, 4002) - -# Flags for check_conn_hv_support -(SUPPORT_CONN_HV_VIRTIO, - SUPPORT_CONN_HV_SKIP_DEFAULT_ACPI, - SUPPORT_CONN_HV_SOUND_AC97, - SUPPORT_CONN_HV_SOUND_ICH6, - SUPPORT_CONN_HV_GRAPHICS_SPICE, - SUPPORT_CONN_HV_CHAR_SPICEVMC, - SUPPORT_CONN_HV_DIRECT_INTERFACE, - SUPPORT_CONN_HV_FILESYSTEM) = range(5000, 5008) - -# Flags for check_stream_support -(SUPPORT_STREAM_UPLOAD,) = range(6000, 6001) - -# Flags for check_net_support -(SUPPORT_NET_ISACTIVE,) = range(7000, 7001) - - -# Possible keys: -# -# "version" : Minimum libvirt version required for this feature. Not used -# if 'args' provided -# -# "force_version" : Demand that version check is met for the checked -# libvirt version. Normally we will make a best effort -# attempt, because determining the daemon version depends -# on an api call from 2010. So for things like -# testing API availability (e.g. createXMLFrom) we won't -# force the check, but for things like XML options (AC97) -# we want to be ABSOLUTELY SURE it is supported so we -# don't enable it by default and break guest creation. -# This isn't required for versions after >= 0.7.3 -# -# "function" : Function name to check exists. If object not specified, -# function is checked against libvirt module. -# -# "args": Argument tuple to actually test object.function with. -# -# "flag": A flag to check exists. This will be appended to the argument -# list if args are provided, otherwise we will only check against -# the local libvirt version. -# -# "drv_version" : A list of tuples of the form -# (driver name (e.g qemu, xen, lxc), minimum supported version) -# If a hypervisor is not listed, it is assumed to be NOT -# SUPPORTED. -# -# "drv_libvirt_version" : List of tuples, similar to drv_version, but -# the version number is minimum supported _libvirt_ -# version -# "hv_version" : A list of tuples of the same form as drv_version, however -# listing the actual from the XML. -# example: 'kvm' - - -_support_dict = { - SUPPORT_CONN_STORAGE : { - "function" : "virConnect.listStoragePools", - "args" : (), - }, - - SUPPORT_CONN_NODEDEV : { - "function" : "virConnect.listDevices", - "args" : (None, 0), - }, - - SUPPORT_CONN_FINDPOOLSOURCES : { - "function" : "virConnect.findStoragePoolSources", - }, - - SUPPORT_CONN_KEYMAP_AUTODETECT : { - "drv_version" : [("qemu", 11000)], - }, - - SUPPORT_CONN_GETHOSTNAME : { - "function" : "virConnect.getHostname()", - "args" : (), - }, - - SUPPORT_CONN_DOMAIN_VIDEO : { - "version" : 6005, - }, - - SUPPORT_CONN_NETWORK : { - "function" : "virConnect.listNetworks", - "args" : (), - }, - - SUPPORT_CONN_INTERFACE : { - "function" : "virConnect.listInterfaces", - "args" : (), - }, - - SUPPORT_CONN_MAXVCPUS_XML : { - "version" : 8005, - }, - - SUPPORT_CONN_STREAM : { - # Earliest version with working bindings - "version" : 9003, - "function" : "virConnect.newStream", - "args" : (0,), - }, - - SUPPORT_CONN_GETVERSION : { - "function": "virConnect.getVersion", - "args": (), - }, - - SUPPORT_CONN_LIBVERSION : { - "function": "virConnect.getLibVersion", - "args": (), - }, - - SUPPORT_CONN_LISTALLDOMAINS : { - "function": "virConnect.listAllDomains", - "args": (), - }, - SUPPORT_CONN_LISTALLNETWORKS : { - "function": "virConnect.listAllNetworks", - "args": (), - }, - SUPPORT_CONN_LISTALLSTORAGEPOOLS : { - "function": "virConnect.listAllStoragePools", - "args": (), - }, - SUPPORT_CONN_LISTALLINTERFACES : { - "function": "virConnect.listAllInterfaces", - "args": (), - }, - - - ################# - # Domain checks # - ################# - - SUPPORT_DOMAIN_GETVCPUS : { - "function" : "virDomain.vcpus", - "args" : (), - }, - - SUPPORT_DOMAIN_XML_INACTIVE : { - "function" : "virDomain.XMLDesc", - "args" : (), - "flag" : "VIR_DOMAIN_XML_INACTIVE", - }, - - SUPPORT_DOMAIN_XML_SECURE : { - "function" : "virDomain.XMLDesc", - "args" : (), - "flag" : "VIR_DOMAIN_XML_SECURE", - }, - - SUPPORT_DOMAIN_MANAGED_SAVE : { - "function" : "virDomain.hasManagedSaveImage", - "args" : (0,), - }, - - SUPPORT_DOMAIN_MIGRATE_DOWNTIME : { - "function" : "virDomain.migrateSetMaxDowntime", - # Use a bogus flags value, so that we don't overwrite existing - # downtime value - "args" : (30, 12345678), - }, - - SUPPORT_DOMAIN_JOB_INFO : { - "function" : "virDomain.jobInfo", - "args" : (), - }, - - SUPPORT_DOMAIN_CONSOLE_STREAM : { - "version" : 9003, - }, - - SUPPORT_DOMAIN_SET_METADATA : { - "version" : 9010, - }, - - SUPPORT_DOMAIN_CPU_HOST_MODEL : { - "version" : 9010, - }, - - - ############### - # Pool checks # - ############### - - # This can't ever require a pool object for back compat reasons - SUPPORT_STORAGE_CREATEVOLFROM : { - "function" : "virStoragePool.createXMLFrom", - "version" : 6004, - }, - SUPPORT_STORAGE_ISACTIVE : { - "function" : "virStoragePool.isActive", - "args": (), - }, - - - ################## - # Nodedev checks # - ################## - - # This can't ever require a nodedev object for back compat reasons - SUPPORT_NODEDEV_PCI_DETACH : { - "function" : "virNodeDevice.dettach", - "version" : 6001, - }, - - - #################### - # Interface checks # - #################### - - SUPPORT_INTERFACE_XML_INACTIVE : { - "function" : "virInterface.XMLDesc", - "args" : (), - "flag" : "VIR_INTERFACE_XML_INACTIVE", - }, - SUPPORT_INTERFACE_ISACTIVE : { - "function" : "virInterface.isActive", - "args": (), - }, - - - ################## - # Conn HV checks # - ################## - - SUPPORT_CONN_HV_VIRTIO : { - "drv_version": [("qemu", 0)], - "hv_version" : [("kvm", 0)], - }, - - SUPPORT_CONN_HV_SKIP_DEFAULT_ACPI : { - "drv_version" : [("xen", -3001000)], - }, - - SUPPORT_CONN_HV_SOUND_AC97 : { - "version" : 6000, - "force_version" : True, - "drv_version" : [("qemu", 11000), ], - }, - - SUPPORT_CONN_HV_SOUND_ICH6 : { - "version" : 8008, - "drv_version" : [("qemu", 14000), ], - "rhel6_drv_version" : [("qemu", 12001)], - "rhel6_version" : 8007, - }, - - SUPPORT_CONN_HV_GRAPHICS_SPICE : { - "version" : 8006, - "drv_version" : [("qemu", 14000), ], - }, - - SUPPORT_CONN_HV_CHAR_SPICEVMC : { - "version" : 8008, - "drv_version" : [("qemu", 14000), ], - }, - SUPPORT_CONN_HV_DIRECT_INTERFACE : { - "version" : 8007, - "drv_version" : [("qemu", 0), ], - }, - SUPPORT_CONN_HV_FILESYSTEM : { - "drv_version" : [("qemu", 13000), - ("lxc", 0), - ("openvz", 0), - ("test", 0)], - "drv_libvirt_version" : [("qemu", 8005), - ("lxc", 0), - ("openvz", 0), - ("test", 0)], - }, - - - ################# - # Stream checks # - ################# - - SUPPORT_STREAM_UPLOAD : { - # Latest I tested with, and since we will use it by default - # for URL installs, want to be sure it works - "version" : 9004, - }, - - - ################## - # Network checks # - ################## - - SUPPORT_NET_ISACTIVE : { - "function" : "virNetwork.isActive", - "args": (), - }, -} # RHEL6 has lots of feature backports, and since libvirt doesn't # really offer any XML feature introspection, we have to use hacks to @@ -437,6 +101,295 @@ def _split_function_name(function): return (output[0], output[1]) +class _SupportCheck(object): + """ + @version: Minimum libvirt version required for this feature. Not used + if 'args' provided + @force_version: Demand that version check is met for the checked + libvirt version. Normally we will make a best effort + attempt, because determining the daemon version depends + on an api call from 2010. So for things like + testing API availability (e.g. createXMLFrom) we won't + force the check, but for things like XML options (AC97) + we want to be ABSOLUTELY SURE it is supported so we + don't enable it by default and break guest creation. + This isn't required for versions after >= 0.7.3 + @function: Function name to check exists. If object not specified, + function is checked against libvirt module. + @args: Argument tuple to actually test object.function with. + @flag: A flag to check exists. This will be appended to the argument + list if args are provided, otherwise we will only check against + the local libvirt version. + @drv_version: A list of tuples of the form + (driver name (e.g qemu, xen, lxc), minimum supported version) + If a hypervisor is not listed, it is assumed to be NOT SUPPORTED. + @drv_libvirt_version: List of tuples, similar to drv_version, but + the version number is minimum supported _libvirt_ version + @hv_version: A list of tuples of the same form as drv_version, however + listing the actual from the XML. example: 'kvm' + + @rhel6_version + @rhel6_drv_version: Analog of the above params, but for versions for + RHEL6 qemu, and only if virt-manager is configured with the + rhel defaults switch + """ + def __init__(self, + function=None, args=None, flag=None, + version=None, force_version=None, + drv_version=None, drv_libvirt_version=None, hv_version=None, + rhel6_drv_version=None, rhel6_version=None): + self.function = function + self.args = args + self.flag = flag + self.version = version and int(version) or 0 + self.force_version = bool(force_version) + self.drv_version = drv_version or [] + self.drv_libvirt_version = drv_libvirt_version or [] + self.hv_version = hv_version or [] + + self.rhel6_version = rhel6_version and int(rhel6_version) or 0 + self.rhel6_drv_version = rhel6_drv_version or [] + + def _get_min_lib_version(self): + ret = self.version + rhel6_min = self.rhel6_version or ret + if get_rhel6(): + ret = rhel6_min + return ret + + def _get_drv_version(self): + ret = self.drv_version + rhel6_drv_version = self.rhel6_drv_version or ret + if get_rhel6(): + ret = rhel6_drv_version + return ret + + def check_support(self, conn, data): + minimum_libvirt_version = self._get_min_lib_version() + drv_version = self._get_drv_version() + + object_name, function_name = _split_function_name(self.function) + + if function_name: + # Make sure function is present in either libvirt module or + # object_name class + flag_tuple = () + + if not _has_command(function_name, objname=object_name): + return False + + if self.flag: + found_flag = _get_flag(self.flag) + if not bool(found_flag): + return False + flag_tuple = (found_flag,) + + if self.args is not None: + classobj = None + + # If function requires an object, make sure the passed obj + # is of the correct type + if object_name: + classobj = _get_command(object_name) + if not isinstance(data, classobj): + raise ValueError( + "Passed obj %s with args must be of type %s, was %s" % + (data, str(classobj), type(data))) + + cmd = _get_command(function_name, obj=data) + + # Function with args specified is all the proof we need + ret = _try_command(cmd, self.args + flag_tuple, + check_all_error=bool(flag_tuple)) + return ret + + # Do this after the function check, since there's an ordering issue + # with VirtualConnection + drv_type = conn.get_uri_driver() + actual_lib_ver = conn.local_libvirt_version() + actual_daemon_ver = conn.daemon_version() + actual_drv_ver = conn.conn_version() + if (actual_daemon_ver == 0 and not self.force_version): + # This means the API may not be supported, but we don't care + actual_daemon_ver = 1000000000 + + # Check that local libvirt version is sufficient + if minimum_libvirt_version > actual_lib_ver: + return False + + # Check that daemon version is sufficient + if minimum_libvirt_version > actual_daemon_ver: + return False + + # If driver specific version info specified, try to verify + if drv_version: + found = False + for drv, min_drv_ver in drv_version: + if drv != drv_type: + continue + + if min_drv_ver < 0: + if actual_drv_ver <= -min_drv_ver: + found = True + break + else: + if actual_drv_ver >= min_drv_ver: + found = True + break + + if not found: + return False + + if self.drv_libvirt_version: + found = False + for drv, min_lib_ver in self.drv_libvirt_version: + if drv != drv_type: + continue + + if min_lib_ver < 0: + if actual_lib_ver <= -min_lib_ver: + found = True + break + else: + if actual_lib_ver >= min_lib_ver: + found = True + break + + if not found: + return False + + if self.hv_version: + found = False + hv_type = data + for hv, min_hv_ver in self.hv_version: + if hv != hv_type: + continue + + # No HV specific version info, just use driver version + if min_hv_ver < 0: + if actual_drv_ver <= -min_hv_ver: + found = True + break + else: + if actual_drv_ver >= min_hv_ver: + found = True + break + + if not found: + return False + + return True + + +_support_id = 0 +_support_objs = [] + + +def _make(*args, **kwargs): + global _support_id + _support_id += 1 + obj = _SupportCheck(*args, **kwargs) + _support_objs.append(obj) + return _support_id + + + +SUPPORT_CONN_STORAGE = _make(function="virConnect.listStoragePools", + args=()) +SUPPORT_CONN_NODEDEV = _make(function="virConnect.listDevices", args=(None, 0)) +SUPPORT_CONN_FINDPOOLSOURCES = _make( + function="virConnect.findStoragePoolSources") +SUPPORT_CONN_KEYMAP_AUTODETECT = _make(drv_version=[("qemu", 11000)]) +SUPPORT_CONN_GETHOSTNAME = _make(function="virConnect.getHostname", args=()) +SUPPORT_CONN_DOMAIN_VIDEO = _make(version=6005) +SUPPORT_CONN_NETWORK = _make(function="virConnect.listNetworks", args=()) +SUPPORT_CONN_INTERFACE = _make(function="virConnect.listInterfaces", args=()) +SUPPORT_CONN_MAXVCPUS_XML = _make(version=8005) +# Earliest version with working bindings +SUPPORT_CONN_STREAM = _make(version=9003, + function="virConnect.newStream", + args=(0,)) +SUPPORT_CONN_GETVERSION = _make(function="virConnect.getVersion", args=()) +SUPPORT_CONN_LIBVERSION = _make(function="virConnect.getLibVersion", args=()) +SUPPORT_CONN_LISTALLDOMAINS = _make(function="virConnect.listAllDomains", + args=()) +SUPPORT_CONN_LISTALLNETWORKS = _make(function="virConnect.listAllNetworks", + args=()) +SUPPORT_CONN_LISTALLSTORAGEPOOLS = _make( + function="virConnect.listAllStoragePools", + args=()) +SUPPORT_CONN_LISTALLINTERFACES = _make(function="virConnect.listAllInterfaces", + args=()) + + +# Domain checks +SUPPORT_DOMAIN_GETVCPUS = _make(function="virDomain.vcpus", args=()) +SUPPORT_DOMAIN_XML_INACTIVE = _make(function="virDomain.XMLDesc", args=(), + flag="VIR_DOMAIN_XML_INACTIVE") +SUPPORT_DOMAIN_XML_SECURE = _make(function="virDomain.XMLDesc", args=(), + flag="VIR_DOMAIN_XML_SECURE") +SUPPORT_DOMAIN_MANAGED_SAVE = _make(function="virDomain.hasManagedSaveImage", + args=(0,)) +SUPPORT_DOMAIN_MIGRATE_DOWNTIME = _make( + function="virDomain.migrateSetMaxDowntime", + # Use a bogus flags value, so that we don't overwrite existing + # downtime value + args=(30, 12345678)) +SUPPORT_DOMAIN_JOB_INFO = _make(function="virDomain.jobInfo", args=()) +SUPPORT_DOMAIN_CONSOLE_STREAM = _make(version=9003) +SUPPORT_DOMAIN_SET_METADATA = _make(version=9010) +SUPPORT_DOMAIN_CPU_HOST_MODEL = _make(version=9010) + +# Pool checks +# This can't ever require a pool object for back compat reasons +SUPPORT_STORAGE_CREATEVOLFROM = _make(function="virStoragePool.createXMLFrom", + version=6004) +SUPPORT_STORAGE_ISACTIVE = _make(function="virStoragePool.isActive", args=()) + +# Nodedev checks +# This can't ever require a nodedev object for back compat reasons +SUPPORT_NODEDEV_PCI_DETACH = _make(function="virNodeDevice.dettach", + version=6001) + + +# Interface checks +SUPPORT_INTERFACE_XML_INACTIVE = _make(function="virInterface.XMLDesc", + flag="VIR_INTERFACE_XML_INACTIVE", + args=()) +SUPPORT_INTERFACE_ISACTIVE = _make(function="virInterface.isActive", args=()) + + +# Conn HV checks +SUPPORT_CONN_HV_VIRTIO = _make(drv_version=[("qemu", 0)], + hv_version=[("kvm", 0)]) +SUPPORT_CONN_HV_SKIP_DEFAULT_ACPI = _make(drv_version=[("xen", -3001000)]) +SUPPORT_CONN_HV_SOUND_AC97 = _make(version=6000, + force_version=True, + drv_version=[("qemu", 11000)]) +SUPPORT_CONN_HV_SOUND_ICH6 = _make(version=8008, + drv_version=[("qemu", 14000)], + rhel6_drv_version=[("qemu", 12001)], + rhel6_version=8007) +SUPPORT_CONN_HV_GRAPHICS_SPICE = _make(version=8006, + drv_version=[("qemu", 14000)]) +SUPPORT_CONN_HV_CHAR_SPICEVMC = _make(version=8008, + drv_version=[("qemu", 14000)]) +SUPPORT_CONN_HV_DIRECT_INTERFACE = _make(version=8007, + drv_version=[("qemu", 0)]) +SUPPORT_CONN_HV_FILESYSTEM = _make( + drv_version=[("qemu", 13000), ("lxc", 0), ("openvz", 0), ("test", 0)], + drv_libvirt_version=[("qemu", 8005), ("lxc", 0), + ("openvz", 0), ("test", 0)]) + +# Stream checks +# Latest I tested with, and since we will use it by default +# for URL installs, want to be sure it works +SUPPORT_STREAM_UPLOAD = _make(version=9004) + +# Network checks +SUPPORT_NET_ISACTIVE = _make(function="virNetwork.isActive", args=()) + + def check_support(virtconn, feature, data=None): """ Attempt to determine if a specific libvirt feature is support given @@ -454,145 +407,5 @@ def check_support(virtconn, feature, data=None): if "VirtualConnection" in repr(data): data = data.libvirtconn - support_info = _support_dict[feature] - key_list = support_info.keys() - - def get_value(key): - if key in key_list: - key_list.remove(key) - return support_info.get(key) - - is_rhel6 = get_rhel6() - force_version = get_value("force_version") or False - - minimum_libvirt_version = get_value("version") or 0 - rhel6_min = get_value("rhel6_version") or minimum_libvirt_version - if is_rhel6: - minimum_libvirt_version = rhel6_min - - drv_version = get_value("drv_version") or [] - rhel6_drv_version = get_value("rhel6_drv_version") or drv_version - if is_rhel6: - drv_version = rhel6_drv_version - - drv_libvirt_version = get_value("drv_libvirt_version") or [] - - hv_version = get_value("hv_version") or [] - object_name, function_name = _split_function_name(get_value("function")) - args = get_value("args") - flag = get_value("flag") - - # Make sure there are no keys left in the key_list. This will - # ensure we didn't mistype anything above, or in the support_dict - if key_list: - raise RuntimeError("Unknown keys in the support_dict: %s" % key_list) - - if function_name: - # Make sure function is present in either libvirt module or - # object_name class - flag_tuple = () - - if not _has_command(function_name, objname=object_name): - return False - - if flag: - found_flag = _get_flag(flag) - if not bool(found_flag): - return False - flag_tuple = (found_flag,) - - if args is not None: - classobj = None - - # If function requires an object, make sure the passed obj - # is of the correct type - if object_name: - classobj = _get_command(object_name) - if not isinstance(data, classobj): - raise ValueError( - "Passed obj %s with args must be of type %s, was %s" % - (data, str(classobj), type(data))) - - cmd = _get_command(function_name, obj=data) - - # Function with args specified is all the proof we need - ret = _try_command(cmd, args + flag_tuple, - check_all_error=bool(flag_tuple)) - return ret - - # Do this after the function check, since there's an ordering issue - # with VirtualConnection - drv_type = virtconn.get_uri_driver() - actual_lib_ver = virtconn.local_libvirt_version() - actual_daemon_ver = virtconn.daemon_version() - actual_drv_ver = virtconn.conn_version() - if (actual_daemon_ver == 0 and not force_version): - # This means the API may not be supported, but we don't care - actual_daemon_ver = 1000000000 - - # Check that local libvirt version is sufficient - if minimum_libvirt_version > actual_lib_ver: - return False - - # Check that daemon version is sufficient - if minimum_libvirt_version > actual_daemon_ver: - return False - - # If driver specific version info specified, try to verify - if drv_version: - found = False - for drv, min_drv_ver in drv_version: - if drv != drv_type: - continue - - if min_drv_ver < 0: - if actual_drv_ver <= -min_drv_ver: - found = True - break - else: - if actual_drv_ver >= min_drv_ver: - found = True - break - - if not found: - return False - - if drv_libvirt_version: - found = False - for drv, min_lib_ver in drv_libvirt_version: - if drv != drv_type: - continue - - if min_lib_ver < 0: - if actual_lib_ver <= -min_lib_ver: - found = True - break - else: - if actual_lib_ver >= min_lib_ver: - found = True - break - - if not found: - return False - - if hv_version: - found = False - hv_type = data - for hv, min_hv_ver in hv_version: - if hv != hv_type: - continue - - # No HV specific version info, just use driver version - if min_hv_ver < 0: - if actual_drv_ver <= -min_hv_ver: - found = True - break - else: - if actual_drv_ver >= min_hv_ver: - found = True - break - - if not found: - return False - - return True + sobj = _support_objs[feature - 1] + return sobj.check_support(virtconn, data)