1# 2# Helper functions for determining if libvirt supports certain features 3# 4# Copyright 2009, 2013, 2014 Red Hat, Inc. 5# 6# This work is licensed under the GNU GPLv2 or later. 7# See the COPYING file in the top-level directory. 8 9import libvirt 10 11from . import xmlutil 12 13 14def _check_function(function, flag, run_args, data): 15 """ 16 Make sure function and option flag is present in the libvirt module. 17 If run_args specified, try actually running the function against 18 the passed 'data' object 19 """ 20 object_name, function_name = function.split(".") 21 classobj = getattr(libvirt, object_name, None) 22 if not classobj: 23 return False 24 if not getattr(classobj, function_name, None): 25 return False 26 27 flag_tuple = None 28 if flag: 29 found_flag = getattr(libvirt, flag, None) 30 if found_flag is None: 31 return False 32 flag_tuple = (found_flag,) 33 34 if run_args is None: 35 return None 36 37 # If function requires an object, make sure the passed obj 38 # is of the correct type 39 if not isinstance(data, classobj): 40 raise ValueError( 41 "Passed obj %s with args must be of type %s, was %s" % 42 (data, str(classobj), type(data))) 43 44 use_args = run_args 45 if flag_tuple: 46 use_args += flag_tuple 47 48 try: 49 getattr(data, function_name)(*run_args) 50 except libvirt.libvirtError as e: 51 if SupportCache.is_error_nosupport(e): 52 return False 53 if bool(flag_tuple): # pragma: no cover 54 return False 55 except Exception as e: # pragma: no cover 56 # Other python exceptions likely mean the bindings are horked 57 return False 58 return True 59 60 61def _version_str_to_int(verstr): 62 if verstr is None: 63 return None 64 if verstr == 0: 65 return 0 66 67 if verstr.count(".") != 2: 68 raise xmlutil.DevError( 69 "version string '%s' needs two '.' in it." % verstr) 70 71 return ((int(verstr.split(".")[0]) * 1000000) + 72 (int(verstr.split(".")[1]) * 1000) + (int(verstr.split(".")[2]))) 73 74 75class _SupportCheck(object): 76 """ 77 @version: Minimum libvirt version required for this feature. Not used 78 if 'args' provided. 79 80 @function: Function name to check exists. Expected to be of the 81 format $obj.$func. Like virDomain.isActive 82 83 @run_args: Argument tuple to actually test 'function' with, and check 84 for an 'unsupported' error from libvirt. 85 86 @flag: A flag to check exists. This will be appended to the argument 87 :list if run_args are provided, otherwise we will only check against 88 that the flag is present in the python bindings. 89 90 @hv_version: A dictionary with hypervisor names for keys, and 91 hypervisor versions as values. This is for saying 'this feature 92 is only supported with qemu version 1.5.0' or similar. If the 93 version is 0, then perform no version check. 94 95 @hv_libvirt_version: Similar to hv_version, but this will check 96 the version of libvirt for a specific hv key. Use this to say 97 'this feature is supported with qemu and libvirt version 1.0.0, 98 and xen with libvirt version 1.1.0' 99 """ 100 def __init__(self, 101 function=None, run_args=None, flag=None, 102 version=None, hv_version=None, hv_libvirt_version=None): 103 self.function = function 104 self.run_args = run_args 105 self.flag = flag 106 self.version = version 107 self.hv_version = hv_version or {} 108 self.hv_libvirt_version = hv_libvirt_version or {} 109 110 if self.function: 111 assert len(function.split(".")) == 2 112 113 versions = ([self.version] + list(self.hv_libvirt_version.values())) 114 for vstr in versions: 115 v = _version_str_to_int(vstr) 116 if vstr is not None and v != 0 and v < 7003: 117 raise xmlutil.DevError( 118 "Cannot enforce " 119 "support checks for libvirt versions less than 0.7.3, " 120 "since required APIs were not available. ver=%s" % vstr) 121 122 def __call__(self, virtconn, data=None): 123 """ 124 Attempt to determine if a specific libvirt feature is support given 125 the passed connection. 126 127 :param virtconn: VirtinstConnection to check feature on 128 :param feature: Feature type to check support for 129 :type feature: One of the SUPPORT_* flags 130 :param data: Option libvirt object to use in feature checking 131 :type data: Could be virDomain, virNetwork, virStoragePool, hv name, etc 132 133 :returns: True if feature is supported, False otherwise 134 """ 135 if "VirtinstConnection" in repr(data): 136 data = data.get_conn_for_api_arg() 137 138 if self.function: 139 ret = _check_function( 140 self.function, self.flag, self.run_args, data) 141 if ret is not None: 142 return ret 143 144 # Do this after the function check, since there's an ordering issue 145 # with VirtinstConnection 146 hv_type = virtconn.get_uri_driver() 147 actual_libvirt_version = virtconn.daemon_version() 148 actual_hv_version = virtconn.conn_version() 149 150 # Check that local libvirt version is sufficient 151 v = _version_str_to_int(self.version) 152 if v and (v > actual_libvirt_version): 153 return False 154 155 if self.hv_version: 156 if hv_type not in self.hv_version: 157 if "all" not in self.hv_version: 158 return False 159 elif (actual_hv_version < 160 _version_str_to_int(self.hv_version[hv_type])): 161 return False 162 163 if self.hv_libvirt_version: 164 if hv_type not in self.hv_libvirt_version: 165 if "all" not in self.hv_libvirt_version: 166 return False 167 elif (actual_libvirt_version < 168 _version_str_to_int(self.hv_libvirt_version[hv_type])): 169 return False 170 171 return True 172 173 174def _make(*args, **kwargs): 175 """ 176 Create a _SupportCheck from the passed args, then turn it into a 177 SupportCache method which captures and caches the returned support 178 value in self._cache 179 """ 180 # pylint: disable=protected-access 181 support_obj = _SupportCheck(*args, **kwargs) 182 183 def cache_wrapper(self, data=None): 184 if support_obj not in self._cache: 185 support_ret = support_obj(self._virtconn, data or self._virtconn) 186 self._cache[support_obj] = support_ret 187 return self._cache[support_obj] 188 189 return cache_wrapper 190 191 192class SupportCache: 193 """ 194 Class containing all support checks and access APIs, and support for 195 caching returned results 196 """ 197 198 @staticmethod 199 def is_libvirt_error_no_domain(err): 200 """ 201 Small helper to check if the passed exception is a libvirt error 202 with code VIR_ERR_NO_DOMAIN 203 """ 204 if not isinstance(err, libvirt.libvirtError): 205 return False # pragma: no cover 206 return err.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN 207 208 @staticmethod 209 def is_error_nosupport(err): 210 """ 211 Check if passed exception indicates that the called libvirt command isn't 212 supported 213 214 :param err: Exception raised from command call 215 :returns: True if command isn't supported, False if we can't determine 216 """ 217 if not isinstance(err, libvirt.libvirtError): 218 return False # pragma: no cover 219 220 if (err.get_error_code() == libvirt.VIR_ERR_RPC or 221 err.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT): 222 return True 223 224 return False # pragma: no cover 225 226 227 def __init__(self, virtconn): 228 self._cache = {} 229 self._virtconn = virtconn 230 231 conn_domain = _make( 232 function="virConnect.listAllDomains", run_args=()) 233 conn_storage = _make( 234 function="virConnect.listAllStoragePools", run_args=()) 235 conn_nodedev = _make( 236 function="virConnect.listDevices", run_args=(None, 0)) 237 conn_network = _make( 238 function="virConnect.listNetworks", run_args=()) 239 240 conn_stream = _make(function="virConnect.newStream", run_args=(0,)) 241 conn_working_xen_events = _make(hv_version={"xen": "4.0.0", "all": 0}) 242 # This is an arbitrary check to say whether it's a good idea to 243 # default to qcow2. It might be fine for xen or qemu older than the versions 244 # here, but until someone tests things I'm going to be a bit conservative. 245 conn_default_qcow2 = _make(hv_version={"qemu": "1.2.0", "test": 0}) 246 conn_autosocket = _make(hv_libvirt_version={"qemu": "1.0.6"}) 247 conn_pm_disable = _make(hv_version={"qemu": "1.2.0", "test": 0}) 248 conn_qcow2_lazy_refcounts = _make( 249 version="1.1.0", hv_version={"qemu": "1.2.0", "test": 0}) 250 conn_hyperv_vapic = _make( 251 version="1.1.0", hv_version={"qemu": "1.1.0", "test": 0}) 252 conn_hyperv_clock = _make( 253 version="1.2.2", hv_version={"qemu": "1.5.3", "test": 0}) 254 conn_domain_capabilities = _make( 255 function="virConnect.getDomainCapabilities", 256 run_args=(None, None, None, None)) 257 conn_vmport = _make( 258 version="1.2.16", hv_version={"qemu": "2.2.0", "test": 0}) 259 conn_mem_stats_period = _make( 260 function="virDomain.setMemoryStatsPeriod", 261 version="1.1.1", hv_version={"qemu": 0, "test": "5.6.0"}) 262 # spice GL is actually enabled with libvirt 1.3.3, but 3.1.0 is the 263 # first version that sorts out the qemu:///system + cgroup issues 264 conn_graphics_listen_none = _make(version="2.0.0") 265 conn_rng_urandom = _make(version="1.3.4") 266 conn_usb3_ports = _make(version="1.3.5") 267 conn_machvirt_pci_default = _make(version="3.0.0") 268 conn_qemu_xhci = _make(version="3.3.0", hv_version={"qemu": "2.9.0"}) 269 conn_vnc_none_auth = _make(hv_version={"qemu": "2.9.0"}) 270 conn_device_boot_order = _make(hv_version={"qemu": 0, "test": 0}) 271 conn_riscv_virt_pci_default = _make(version="5.3.0", hv_version={"qemu": "4.0.0"}) 272 273 # We choose qemu 2.11.0 as the first version to target for q35 default. 274 # That's not really based on anything except reasonably modern at the 275 # time of these patches. 276 qemu_q35_default = _make(hv_version={"qemu": "2.11.0", "test": "0"}) 277 278 # This is for disk <driver name=qemu>. xen supports this, but it's 279 # limited to arbitrary new enough xen, since I know libxl can handle it 280 # but I don't think the old xend driver does. 281 conn_disk_driver_name_qemu = _make( 282 hv_version={"qemu": 0, "xen": "4.2.0"}, 283 hv_libvirt_version={"qemu": 0, "xen": "1.1.0"}) 284 285 # Domain checks 286 domain_xml_inactive = _make(function="virDomain.XMLDesc", run_args=(), 287 flag="VIR_DOMAIN_XML_INACTIVE") 288 domain_xml_secure = _make(function="virDomain.XMLDesc", run_args=(), 289 flag="VIR_DOMAIN_XML_SECURE") 290 domain_managed_save = _make( 291 function="virDomain.hasManagedSaveImage", 292 run_args=(0,)) 293 domain_job_info = _make(function="virDomain.jobInfo", run_args=()) 294 domain_list_snapshots = _make( 295 function="virDomain.listAllSnapshots", run_args=()) 296 domain_memory_stats = _make( 297 function="virDomain.memoryStats", run_args=()) 298 domain_state = _make(function="virDomain.state", run_args=()) 299 domain_open_graphics = _make(function="virDomain.openGraphicsFD", 300 version="1.2.8", hv_version={"qemu": 0}) 301 302 # Pool checks 303 pool_metadata_prealloc = _make( 304 flag="VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA", 305 version="1.0.1") 306 307 308 def _check_version(self, version): 309 """ 310 Check libvirt version. Useful for the test suite so we don't need 311 to keep adding new support checks. 312 """ 313 sobj = _SupportCheck(version=version) 314 return sobj(self._virtconn, None) 315