mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-25 18:55:27 -06:00
VirtualConnection: cache version lookups
This commit is contained in:
parent
c0deb97dba
commit
c406a6433c
@ -18,7 +18,6 @@ import unittest
|
||||
import os
|
||||
import logging
|
||||
|
||||
import libvirt
|
||||
import urlgrabber.progress as progress
|
||||
|
||||
import virtinst
|
||||
@ -454,13 +453,9 @@ class TestXMLConfig(unittest.TestCase):
|
||||
g = build_guest()
|
||||
self._compare(g, "install-f11-ac97", False)
|
||||
|
||||
oldver = libvirt.getVersion
|
||||
try:
|
||||
utils.set_conn(utils.open_plainkvm(libver=5000))
|
||||
g = build_guest()
|
||||
self._compare(g, "install-f11-noac97", False)
|
||||
finally:
|
||||
libvirt.getVersion = oldver
|
||||
utils.set_conn(utils.open_plainkvm(libver=5000))
|
||||
g = build_guest()
|
||||
self._compare(g, "install-f11-noac97", False)
|
||||
|
||||
utils.set_conn(utils.open_plainkvm(connver=10000))
|
||||
g = build_guest()
|
||||
|
@ -32,6 +32,7 @@ from gi.repository import GObject
|
||||
from gi.repository import LibvirtGLib
|
||||
# pylint: enable=E0611
|
||||
|
||||
from virtinst import util as virtinstutil
|
||||
from virtinst import cli as virtinstcli
|
||||
from virtcli import cliutils, cliconfig
|
||||
|
||||
@ -245,7 +246,8 @@ def main():
|
||||
os.path.join(cliconfig.asset_dir, "ui"),
|
||||
options.testfirstrun)
|
||||
|
||||
if not config.support_threading:
|
||||
if not virtinstutil.local_libvirt_version() >= 6000:
|
||||
# We need this version for threaded virConnect access
|
||||
_show_startup_error(
|
||||
_("virt-manager requires libvirt 0.6.0 or later."), "")
|
||||
return
|
||||
|
@ -123,8 +123,7 @@ def _simple_async(callback, args, title, text, parent, errorintro,
|
||||
docb = tmpcb
|
||||
|
||||
asyncjob = vmmAsyncJob(docb, args, title, text, parent.topwin,
|
||||
show_progress=show_progress,
|
||||
async=parent.config.support_threading)
|
||||
show_progress=show_progress)
|
||||
error, details = asyncjob.run()
|
||||
if error is None:
|
||||
return
|
||||
|
@ -26,8 +26,6 @@ from gi.repository import GLib
|
||||
from gi.repository import Gtk
|
||||
# pylint: enable=E0611
|
||||
|
||||
import virtinst
|
||||
|
||||
from virtManager.keyring import vmmKeyring, vmmSecret
|
||||
|
||||
|
||||
@ -171,17 +169,12 @@ class vmmConfig(object):
|
||||
|
||||
self._objects = []
|
||||
|
||||
self.support_threading = virtinst.support.support_threading()
|
||||
|
||||
self.support_inspection = self.check_inspection(self.support_threading)
|
||||
self.support_inspection = self.check_inspection()
|
||||
|
||||
self._spice_error = None
|
||||
|
||||
|
||||
def check_inspection(self, support_threading):
|
||||
if not support_threading:
|
||||
return False
|
||||
|
||||
def check_inspection(self):
|
||||
try:
|
||||
# Check we can open the Python guestfs module.
|
||||
from guestfs import GuestFS # pylint: disable=F0401
|
||||
|
@ -105,8 +105,6 @@ class vmmEngine(vmmGObject):
|
||||
|
||||
self._tick_thread = None
|
||||
self._tick_thread_slow = False
|
||||
if not self.config.support_threading:
|
||||
logging.debug("Libvirt doesn't support threading, skipping.")
|
||||
|
||||
self.inspection = None
|
||||
self._create_inspection_thread()
|
||||
@ -276,9 +274,6 @@ class vmmEngine(vmmGObject):
|
||||
self.timer = self.timeout_add(interval, self.tick)
|
||||
|
||||
def tick(self):
|
||||
if not self.config.support_threading:
|
||||
return self._tick()
|
||||
|
||||
if self._tick_thread and self._tick_thread.isAlive():
|
||||
if not self._tick_thread_slow:
|
||||
logging.debug("Tick is slow, not running at requested rate.")
|
||||
|
@ -23,9 +23,9 @@ import re
|
||||
import libvirt
|
||||
|
||||
from virtinst import support
|
||||
from virtinst import util
|
||||
from virtinst import CapabilitiesParser
|
||||
from virtinst.cli import parse_optstr
|
||||
from virtinst.util import uri_split
|
||||
|
||||
_virtinst_uri_magic = "__virtinst_test__"
|
||||
|
||||
@ -53,7 +53,12 @@ class VirtualConnection(object):
|
||||
self._test_opts = {}
|
||||
|
||||
self._libvirtconn = None
|
||||
self._urisplits = uri_split(self._uri)
|
||||
self._urisplits = util.uri_split(self._uri)
|
||||
|
||||
self._fake_libvirt_version = None
|
||||
self._fake_conn_version = None
|
||||
self._daemon_version = None
|
||||
self._conn_version = None
|
||||
|
||||
self._caps = None
|
||||
|
||||
@ -114,6 +119,41 @@ class VirtualConnection(object):
|
||||
self._libvirtconn = conn
|
||||
|
||||
|
||||
#########################
|
||||
# Public version checks #
|
||||
#########################
|
||||
|
||||
def local_libvirt_version(self):
|
||||
if self._fake_libvirt_version is not None:
|
||||
return self._fake_libvirt_version
|
||||
# This handles caching for us
|
||||
return util.local_libvirt_version()
|
||||
|
||||
def daemon_version(self):
|
||||
if self._fake_libvirt_version is not None:
|
||||
return self._fake_libvirt_version
|
||||
if not self.is_remote():
|
||||
return self.local_libvirt_version()
|
||||
|
||||
if not self._daemon_version:
|
||||
if not self.check_conn_support(support.SUPPORT_CONN_LIBVERSION):
|
||||
self._daemon_version = 0
|
||||
else:
|
||||
self._daemon_version = self.libvirtconn.getLibVersion()
|
||||
return self._daemon_version
|
||||
|
||||
def conn_version(self):
|
||||
if self._fake_conn_version is not None:
|
||||
return self._fake_conn_version
|
||||
|
||||
if not self._conn_version:
|
||||
if not self.check_conn_support(support.SUPPORT_CONN_GETVERSION):
|
||||
self._conn_version = 0
|
||||
else:
|
||||
self._conn_version = self.libvirtconn.getVersion()
|
||||
return self._conn_version
|
||||
|
||||
|
||||
###################
|
||||
# Public URI bits #
|
||||
###################
|
||||
@ -259,7 +299,7 @@ class VirtualConnection(object):
|
||||
opts.pop("xen", None)
|
||||
opts.pop("lxc", None)
|
||||
|
||||
conn.getVersion = lambda: 10000000000
|
||||
self._fake_conn_version = 10000000000
|
||||
conn.getURI = self._virtinst_uri_make_fake
|
||||
|
||||
origcreate = conn.createLinux
|
||||
@ -273,22 +313,12 @@ class VirtualConnection(object):
|
||||
conn.createLinux = newcreate
|
||||
conn.defineXML = newdefine
|
||||
|
||||
|
||||
# These need to come after the HV setter, since that sets a default
|
||||
# conn version
|
||||
if "connver" in opts:
|
||||
ver = int(opts.pop("connver"))
|
||||
def newconnversion():
|
||||
return ver
|
||||
conn.getVersion = newconnversion
|
||||
|
||||
self._fake_conn_version = int(opts.pop("connver"))
|
||||
if "libver" in opts:
|
||||
ver = int(opts.pop("libver"))
|
||||
def newlibversion(drv=None):
|
||||
if drv:
|
||||
return (ver, ver)
|
||||
return ver
|
||||
libvirt.getVersion = newlibversion
|
||||
self._fake_libvirt_version = int(opts.pop("libver"))
|
||||
|
||||
if opts:
|
||||
raise RuntimeError("Unhandled virtinst test uri options %s" % opts)
|
||||
|
@ -33,7 +33,9 @@ from virtinst import util
|
||||
SUPPORT_CONN_NETWORK,
|
||||
SUPPORT_CONN_INTERFACE,
|
||||
SUPPORT_CONN_MAXVCPUS_XML,
|
||||
SUPPORT_CONN_STREAM) = range(10)
|
||||
SUPPORT_CONN_STREAM,
|
||||
SUPPORT_CONN_GETVERSION,
|
||||
SUPPORT_CONN_LIBVERSION) = range(12)
|
||||
|
||||
# Flags for check_domain_support
|
||||
(SUPPORT_DOMAIN_GETVCPUS,
|
||||
@ -79,7 +81,7 @@ from virtinst import util
|
||||
# "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 a fairly new API call getLibVersion. So for things like
|
||||
# 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
|
||||
@ -112,158 +114,184 @@ _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": (),
|
||||
},
|
||||
|
||||
|
||||
# Domain checks
|
||||
#################
|
||||
# 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 : {
|
||||
SUPPORT_DOMAIN_CPU_HOST_MODEL : {
|
||||
"version" : 9010,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
# Pool checks
|
||||
###############
|
||||
# Pool checks #
|
||||
###############
|
||||
|
||||
# This can't ever require a pool object for back compat reasons
|
||||
SUPPORT_STORAGE_CREATEVOLFROM : {
|
||||
"function" : "virStoragePool.createXMLFrom",
|
||||
"version" : 6004,
|
||||
},
|
||||
},
|
||||
|
||||
##################
|
||||
# Nodedev checks #
|
||||
##################
|
||||
|
||||
# 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 #
|
||||
####################
|
||||
|
||||
# Interface checks
|
||||
SUPPORT_INTERFACE_XML_INACTIVE : {
|
||||
"function" : "virInterface.XMLDesc",
|
||||
"args" : (),
|
||||
"flag" : "VIR_INTERFACE_XML_INACTIVE",
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
##################
|
||||
# Conn HV checks #
|
||||
##################
|
||||
|
||||
# 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),
|
||||
@ -273,14 +301,14 @@ _support_dict = {
|
||||
("lxc", 0),
|
||||
("openvz", 0),
|
||||
("test", 0)],
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# RHEL6 has lots of feature backports, and since libvirt doesn't
|
||||
@ -330,72 +358,19 @@ def _get_flag(flag_name):
|
||||
def _try_command(func, args, check_all_error=False):
|
||||
try:
|
||||
func(*args)
|
||||
|
||||
except libvirt.libvirtError, e:
|
||||
if util.is_error_nosupport(e):
|
||||
return False
|
||||
|
||||
if check_all_error:
|
||||
return False
|
||||
|
||||
except Exception:
|
||||
# Other python exceptions likely mean the bindings are horked
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Version of the local libvirt library
|
||||
def _local_lib_ver():
|
||||
return libvirt.getVersion()
|
||||
|
||||
|
||||
# Version of libvirt library/daemon on the connection (could be remote)
|
||||
def _daemon_lib_ver(conn, is_remote, force_version, minimum_libvirt_version):
|
||||
# Always force the required version if it's after the version which
|
||||
# has getLibVersion
|
||||
if force_version or minimum_libvirt_version >= 7004:
|
||||
default_ret = 0
|
||||
else:
|
||||
default_ret = 100000000000
|
||||
|
||||
if not is_remote:
|
||||
return _local_lib_ver()
|
||||
|
||||
if not _has_command("getLibVersion", obj=conn):
|
||||
return default_ret
|
||||
|
||||
if not _try_command(getattr(conn, "getLibVersion"), ()):
|
||||
return default_ret
|
||||
|
||||
return conn.getLibVersion()
|
||||
|
||||
|
||||
# Return the hypervisor version
|
||||
def _hv_ver(conn, drv_type):
|
||||
args = ()
|
||||
|
||||
cmd = _get_command("getVersion", obj=conn)
|
||||
if not cmd:
|
||||
cmd = _get_command("getVersion")
|
||||
args = (drv_type,)
|
||||
|
||||
if not cmd:
|
||||
return 0
|
||||
|
||||
if not _try_command(cmd, args):
|
||||
return 0
|
||||
|
||||
try:
|
||||
ret = cmd(*args)
|
||||
if type(ret) == tuple:
|
||||
ret = ret[1]
|
||||
except libvirt.libvirtError:
|
||||
ret = 0
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _split_function_name(function):
|
||||
if not function:
|
||||
return (None, None)
|
||||
@ -407,7 +382,7 @@ def _split_function_name(function):
|
||||
return (output[0], output[1])
|
||||
|
||||
|
||||
def check_support(conn, feature, data=None):
|
||||
def check_support(virtconn, feature, data=None):
|
||||
"""
|
||||
Attempt to determine if a specific libvirt feature is support given
|
||||
the passed connection.
|
||||
@ -421,9 +396,6 @@ def check_support(conn, feature, data=None):
|
||||
|
||||
@returns: True if feature is supported, False otherwise
|
||||
"""
|
||||
is_remote = conn.is_remote()
|
||||
drv_type = conn.get_uri_driver()
|
||||
conn = conn.libvirtconn
|
||||
if "VirtualConnection" in repr(data):
|
||||
data = data.libvirtconn
|
||||
|
||||
@ -455,11 +427,6 @@ def check_support(conn, feature, data=None):
|
||||
args = get_value("args")
|
||||
flag = get_value("flag")
|
||||
|
||||
actual_lib_ver = _local_lib_ver()
|
||||
actual_daemon_ver = _daemon_lib_ver(conn, is_remote, force_version,
|
||||
minimum_libvirt_version)
|
||||
actual_drv_ver = _hv_ver(conn, drv_type)
|
||||
|
||||
# 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:
|
||||
@ -498,6 +465,16 @@ def check_support(conn, feature, data=None):
|
||||
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
|
||||
@ -564,7 +541,3 @@ def check_support(conn, feature, data=None):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def support_threading():
|
||||
return bool(_local_lib_ver() >= 6000)
|
||||
|
@ -578,3 +578,14 @@ def is_error_nosupport(err):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def local_libvirt_version():
|
||||
"""
|
||||
Lookup the local libvirt library version, but cache the value since
|
||||
it never changes.
|
||||
"""
|
||||
key = "__virtinst_cached_getVersion"
|
||||
if not hasattr(libvirt, key):
|
||||
setattr(libvirt, key, libvirt.getVersion())
|
||||
return getattr(libvirt, key)
|
||||
|
Loading…
Reference in New Issue
Block a user