support: Rework support check invocations

SupportCache.check_support(SUPPORT_FOOBAR, args) becomes
SupportCache.foobar(args)

And SupportCache absorbs the caching infrastructure from
VirtinstConnection.

For now we add some hackery to hide the API change from callers, but
this will be undone in the next patch
This commit is contained in:
Cole Robinson
2019-06-07 14:48:59 -04:00
parent 3d2f678c0f
commit 566a4681a8
4 changed files with 98 additions and 108 deletions

View File

@@ -127,7 +127,7 @@ class SkipChecks:
msg = check()
skip = bool(msg)
else:
skip = not conn._check_version(check) # pylint: disable=protected-access
skip = not conn.support._check_version(check) # pylint: disable=protected-access
msg = "Skipping check due to version < %s" % check
if skip:

View File

@@ -426,11 +426,11 @@ class vmmConnection(vmmGObject):
# API support helpers #
#######################
for _supportname in [_supportname for _supportname in
dir(virtinst.VirtinstConnection) if
_supportname.startswith("SUPPORT_")]:
locals()[_supportname] = getattr(virtinst.VirtinstConnection,
_supportname)
def __getattr__(self, attr):
if attr.startswith("SUPPORT_"):
return getattr(self._backend.support, attr.split("_", 1)[1].lower())
raise AttributeError
def check_support(self, *args):
# pylint: disable=no-value-for-parameter
return self._backend.check_support(*args)

View File

@@ -57,7 +57,6 @@ class VirtinstConnection(object):
self._uriobj = URI(self._uri)
self._caps = None
self._support_cache = {}
self._fetch_cache = {}
# These let virt-manager register a callback which provides its
@@ -68,7 +67,7 @@ class VirtinstConnection(object):
self.cb_fetch_all_nodedevs = None
self.cb_cache_new_pool = None
self.support = support.SupportCache()
self.support = support.SupportCache(weakref.proxy(self))
##############
@@ -79,6 +78,9 @@ class VirtinstConnection(object):
if attr in self.__dict__:
return self.__dict__[attr]
if attr.startswith("SUPPORT_"):
return getattr(self.support, attr.split("_", 1)[1].lower())
# Proxy virConnect API calls
libvirtconn = self.__dict__.get("_libvirtconn")
return getattr(libvirtconn, attr)
@@ -380,30 +382,13 @@ class VirtinstConnection(object):
# Support check helpers #
#########################
for _supportname in [_supportname for _supportname in
dir(support.SupportCache) if
_supportname.startswith("SUPPORT_")]:
locals()[_supportname] = getattr(support.SupportCache, _supportname)
def check_support(self, features, data=None):
def _check_support(key):
if key not in self._support_cache:
self._support_cache[key] = self.support.check_support(
self, key, data or self)
return self._support_cache[key]
for f in util.listify(features):
# 'and' condition over the feature list
if not _check_support(f):
if not f(data):
return False
return True
def _check_version(self, version):
# Entry point for the test suite to do simple version checks,
# actual code should only use check_support
return self.support.check_version(self, version)
def support_remote_url_install(self):
if self._magic_uri:
return False

View File

@@ -162,16 +162,31 @@ class _SupportCheck(object):
"support checks for libvirt versions less than 0.7.3, "
"since required APIs were not available. ver=%s" % vstr)
def check_support(self, conn, data):
def __call__(self, virtconn, data=None):
"""
Attempt to determine if a specific libvirt feature is support given
the passed connection.
:param virtconn: VirtinstConnection to check feature on
:param feature: Feature type to check support for
:type feature: One of the SUPPORT_* flags
:param data: Option libvirt object to use in feature checking
:type data: Could be virDomain, virNetwork, virStoragePool, hv name, etc
:returns: True if feature is supported, False otherwise
"""
if "VirtinstConnection" in repr(data):
data = data.get_conn_for_api_arg()
ret = _check_function(self.function, self.flag, self.run_args, data)
if ret is not None:
return ret
# Do this after the function check, since there's an ordering issue
# with VirtinstConnection
hv_type = conn.get_uri_driver()
actual_libvirt_version = conn.daemon_version()
actual_hv_version = conn.conn_version()
hv_type = virtconn.get_uri_driver()
actual_libvirt_version = virtconn.daemon_version()
actual_hv_version = virtconn.conn_version()
# Check that local libvirt version is sufficient
v = _version_str_to_int(self.version)
@@ -197,145 +212,135 @@ class _SupportCheck(object):
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
"""
Create a _SupportCheck from the passed args, then turn it into a
SupportCache method which captures and caches the returned support
value in self._cache
"""
# pylint: disable=protected-access
support_obj = _SupportCheck(*args, **kwargs)
def cache_wrapper(self, data=None):
if support_obj not in self._cache:
support_ret = support_obj(self._virtconn, data or self._virtconn)
self._cache[support_obj] = support_ret
return self._cache[support_obj]
return cache_wrapper
class SupportCache:
"""
Class containing all support checks and access APIs
Class containing all support checks and access APIs, and support for
caching returned results
"""
def __init__(self, virtconn):
self._cache = {}
self._virtconn = virtconn
SUPPORT_CONN_STORAGE = _make(
conn_storage = _make(
function="virConnect.listStoragePools", run_args=())
SUPPORT_CONN_NODEDEV = _make(
conn_nodedev = _make(
function="virConnect.listDevices", run_args=(None, 0))
SUPPORT_CONN_NETWORK = _make(function="virConnect.listNetworks", run_args=())
SUPPORT_CONN_INTERFACE = _make(
conn_network = _make(function="virConnect.listNetworks", run_args=())
conn_interface = _make(
function="virConnect.listInterfaces", run_args=())
SUPPORT_CONN_STREAM = _make(function="virConnect.newStream", run_args=(0,))
SUPPORT_CONN_LISTALLDOMAINS = _make(
conn_stream = _make(function="virConnect.newStream", run_args=(0,))
conn_listalldomains = _make(
function="virConnect.listAllDomains", run_args=())
SUPPORT_CONN_LISTALLNETWORKS = _make(
conn_listallnetworks = _make(
function="virConnect.listAllNetworks", run_args=())
SUPPORT_CONN_LISTALLSTORAGEPOOLS = _make(
conn_listallstoragepools = _make(
function="virConnect.listAllStoragePools", run_args=())
SUPPORT_CONN_LISTALLINTERFACES = _make(
conn_listallinterfaces = _make(
function="virConnect.listAllInterfaces", run_args=())
SUPPORT_CONN_LISTALLDEVICES = _make(
conn_listalldevices = _make(
function="virConnect.listAllDevices", run_args=())
SUPPORT_CONN_WORKING_XEN_EVENTS = _make(hv_version={"xen": "4.0.0", "all": 0})
conn_working_xen_events = _make(hv_version={"xen": "4.0.0", "all": 0})
# This is an arbitrary check to say whether it's a good idea to
# default to qcow2. It might be fine for xen or qemu older than the versions
# here, but until someone tests things I'm going to be a bit conservative.
SUPPORT_CONN_DEFAULT_QCOW2 = _make(hv_version={"qemu": "1.2.0", "test": 0})
SUPPORT_CONN_AUTOSOCKET = _make(hv_libvirt_version={"qemu": "1.0.6"})
SUPPORT_CONN_PM_DISABLE = _make(hv_version={"qemu": "1.2.0", "test": 0})
SUPPORT_CONN_QCOW2_LAZY_REFCOUNTS = _make(
conn_default_qcow2 = _make(hv_version={"qemu": "1.2.0", "test": 0})
conn_autosocket = _make(hv_libvirt_version={"qemu": "1.0.6"})
conn_pm_disable = _make(hv_version={"qemu": "1.2.0", "test": 0})
conn_qcow2_lazy_refcounts = _make(
version="1.1.0", hv_version={"qemu": "1.2.0", "test": 0})
SUPPORT_CONN_HYPERV_VAPIC = _make(
conn_hyperv_vapic = _make(
version="1.1.0", hv_version={"qemu": "1.1.0", "test": 0})
SUPPORT_CONN_HYPERV_CLOCK = _make(
conn_hyperv_clock = _make(
version="1.2.2", hv_version={"qemu": "1.5.3", "test": 0})
SUPPORT_CONN_DOMAIN_CAPABILITIES = _make(
conn_domain_capabilities = _make(
function="virConnect.getDomainCapabilities",
run_args=(None, None, None, None))
SUPPORT_CONN_DOMAIN_RESET = _make(version="0.9.7", hv_version={"qemu": 0})
SUPPORT_CONN_VMPORT = _make(
conn_domain_reset = _make(version="0.9.7", hv_version={"qemu": 0})
conn_vmport = _make(
version="1.2.16", hv_version={"qemu": "2.2.0", "test": 0})
SUPPORT_CONN_MEM_STATS_PERIOD = _make(
conn_mem_stats_period = _make(
function="virDomain.setMemoryStatsPeriod",
version="1.1.1", hv_version={"qemu": 0})
# spice GL is actually enabled with libvirt 1.3.3, but 3.1.0 is the
# first version that sorts out the qemu:///system + cgroup issues
SUPPORT_CONN_SPICE_GL = _make(version="3.1.0",
conn_spice_gl = _make(version="3.1.0",
hv_version={"qemu": "2.6.0", "test": 0})
SUPPORT_CONN_SPICE_RENDERNODE = _make(version="3.1.0",
conn_spice_rendernode = _make(version="3.1.0",
hv_version={"qemu": "2.9.0", "test": 0})
SUPPORT_CONN_VIDEO_VIRTIO_ACCEL3D = _make(version="1.3.0",
conn_video_virtio_accel3d = _make(version="1.3.0",
hv_version={"qemu": "2.5.0", "test": 0})
SUPPORT_CONN_GRAPHICS_LISTEN_NONE = _make(version="2.0.0")
SUPPORT_CONN_RNG_URANDOM = _make(version="1.3.4")
SUPPORT_CONN_USB3_PORTS = _make(version="1.3.5")
SUPPORT_CONN_MACHVIRT_PCI_DEFAULT = _make(version="3.0.0")
SUPPORT_CONN_QEMU_XHCI = _make(version="3.3.0", hv_version={"qemu": "2.9.0"})
SUPPORT_CONN_VNC_NONE_AUTH = _make(hv_version={"qemu": "2.9.0"})
SUPPORT_CONN_DEVICE_BOOT_ORDER = _make(hv_version={"qemu": 0, "test": 0})
SUPPORT_CONN_RISCV_VIRT_PCI_DEFAULT = _make(version="5.3.0", hv_version={"qemu": "4.0.0"})
conn_graphics_listen_none = _make(version="2.0.0")
conn_rng_urandom = _make(version="1.3.4")
conn_usb3_ports = _make(version="1.3.5")
conn_machvirt_pci_default = _make(version="3.0.0")
conn_qemu_xhci = _make(version="3.3.0", hv_version={"qemu": "2.9.0"})
conn_vnc_none_auth = _make(hv_version={"qemu": "2.9.0"})
conn_device_boot_order = _make(hv_version={"qemu": 0, "test": 0})
conn_riscv_virt_pci_default = _make(version="5.3.0", hv_version={"qemu": "4.0.0"})
# We choose qemu 2.11.0 as the first version to target for q35 default.
# That's not really based on anything except reasonably modern at the
# time of these patches.
SUPPORT_QEMU_Q35_DEFAULT = _make(hv_version={"qemu": "2.11.0", "test": "0"})
qemu_q35_default = _make(hv_version={"qemu": "2.11.0", "test": "0"})
# This is for disk <driver name=qemu>. xen supports this, but it's
# limited to arbitrary new enough xen, since I know libxl can handle it
# but I don't think the old xend driver does.
SUPPORT_CONN_DISK_DRIVER_NAME_QEMU = _make(
conn_disk_driver_name_qemu = _make(
hv_version={"qemu": 0, "xen": "4.2.0"},
hv_libvirt_version={"qemu": 0, "xen": "1.1.0"})
# Domain checks
SUPPORT_DOMAIN_XML_INACTIVE = _make(function="virDomain.XMLDesc", run_args=(),
domain_xml_inactive = _make(function="virDomain.XMLDesc", run_args=(),
flag="VIR_DOMAIN_XML_INACTIVE")
SUPPORT_DOMAIN_XML_SECURE = _make(function="virDomain.XMLDesc", run_args=(),
domain_xml_secure = _make(function="virDomain.XMLDesc", run_args=(),
flag="VIR_DOMAIN_XML_SECURE")
SUPPORT_DOMAIN_MANAGED_SAVE = _make(
domain_managed_save = _make(
function="virDomain.hasManagedSaveImage",
run_args=(0,))
SUPPORT_DOMAIN_JOB_INFO = _make(function="virDomain.jobInfo", run_args=())
SUPPORT_DOMAIN_LIST_SNAPSHOTS = _make(
domain_job_info = _make(function="virDomain.jobInfo", run_args=())
domain_list_snapshots = _make(
function="virDomain.listAllSnapshots", run_args=())
SUPPORT_DOMAIN_MEMORY_STATS = _make(
domain_memory_stats = _make(
function="virDomain.memoryStats", run_args=())
SUPPORT_DOMAIN_STATE = _make(function="virDomain.state", run_args=())
SUPPORT_DOMAIN_OPEN_GRAPHICS = _make(function="virDomain.openGraphicsFD",
domain_state = _make(function="virDomain.state", run_args=())
domain_open_graphics = _make(function="virDomain.openGraphicsFD",
version="1.2.8", hv_version={"qemu": 0})
# Pool checks
SUPPORT_POOL_ISACTIVE = _make(function="virStoragePool.isActive", run_args=())
SUPPORT_POOL_LISTALLVOLUMES = _make(
pool_isactive = _make(function="virStoragePool.isActive", run_args=())
pool_listallvolumes = _make(
function="virStoragePool.listAllVolumes", run_args=())
SUPPORT_POOL_METADATA_PREALLOC = _make(
pool_metadata_prealloc = _make(
flag="VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA",
version="1.0.1")
# Network checks
SUPPORT_NET_ISACTIVE = _make(function="virNetwork.isActive", run_args=())
net_isactive = _make(function="virNetwork.isActive", run_args=())
def check_support(self, virtconn, feature, data=None):
"""
Attempt to determine if a specific libvirt feature is support given
the passed connection.
:param virtconn: Libvirt connection to check feature on
:param feature: Feature type to check support for
:type feature: One of the SUPPORT_* flags
:param data: Option libvirt object to use in feature checking
:type data: Could be virDomain, virNetwork, virStoragePool, hv name, etc
:returns: True if feature is supported, False otherwise
"""
if "VirtinstConnection" in repr(data):
data = data.get_conn_for_api_arg()
sobj = _SUPPORT_OBJS[feature - 1]
return sobj.check_support(virtconn, data)
def check_version(self, virtconn, version):
def _check_version(self, version):
"""
Check libvirt version. Useful for the test suite so we don't need
to keep adding new support checks.
"""
sobj = _SupportCheck(version=version)
return sobj.check_support(virtconn, None)
return sobj(self._virtconn, None)