VirtualConnection: Allow using virt-manager object caches

So when we call into virtinst it doesn't do a whole round of object
lookup and XML fetching.
This commit is contained in:
Cole Robinson 2013-07-07 18:54:08 -04:00
parent 9f3e17d270
commit 7a2caee6e1
6 changed files with 65 additions and 41 deletions

View File

@ -42,6 +42,7 @@ load-plugins=
# I0011: Warn about locally disabled pylint msgs
# R0201: Method could be a function
#
# W0108: Lambda may not be necessary
# W0142: Used * or ** magic*
# W0603: Using the global statement
# W0702: No exception type specified for 'catch'
@ -53,7 +54,7 @@ load-plugins=
# W1001: Use of 'property' on old style class,
# pylint can't detect our Gtk subclasses are new style
# W0511: FIXME and XXX: messages
disable=Design,Similarities,C0103,C0111,C0301,C0302,I0011,R0201,W0142,W0603,W0702,W0703,W1401,W1001,W0511
disable=Design,Similarities,C0103,C0111,C0301,C0302,I0011,R0201,W0108,W0142,W0603,W0702,W0703,W1401,W1001,W0511
[REPORTS]

View File

@ -127,11 +127,17 @@ class vmmConnection(vmmGObject):
self.mediadev_error = ""
self.mediadev_use_libvirt = False
self._init_virtconn()
#################
# Init routines #
#################
def _init_virtconn(self):
self._backend.cb_fetch_all_guests = lambda: self.vms.values()
self._backend.cb_fetch_all_pools = lambda: self.pools.values()
def _init_netdev(self):
"""
Determine how we will be polling for net devices (HAL or libvirt)

View File

@ -469,8 +469,6 @@ class VirtualDisk(VirtualDevice):
vms = conn.fetch_all_guests()
def count_cb(ctx):
c = 0
template = "count(/domain/devices/disk["
if check_conflict:
template += "not(shareable) and "
@ -478,16 +476,15 @@ class VirtualDisk(VirtualDevice):
for dtype in VirtualDisk._target_props:
xpath = template % (dtype, util.xml_escape(path))
c += ctx.xpathEval(xpath)
return c
if ctx.xpathEval(xpath):
return True
return False
names = []
for vm in vms:
xml = vm.XMLDesc(0)
tmpcount = util.get_xml_path(xml, func=count_cb)
if tmpcount:
names.append(vm.name())
xml = vm.get_xml(refresh_if_nec=False)
if util.get_xml_path(xml, func=count_cb):
names.append(vm.get_backend().name())
return names

View File

@ -46,26 +46,6 @@ def _compareMAC(p, q):
return 0
def _countMACaddr(vms, searchmac):
if not searchmac:
return
def count_cb(ctx):
c = 0
for mac in ctx.xpathEval("/domain/devices/interface/mac"):
macaddr = mac.xpathEval("attribute::address")[0].content
if macaddr and _compareMAC(searchmac, macaddr) == 0:
c += 1
return c
count = 0
for vm in vms:
xml = vm.XMLDesc(0)
count += util.get_xml_path(xml, func=count_cb)
return count
class VirtualPort(XMLBuilderDomain.XMLBuilderDomain):
def __init__(self, conn, parsexml=None, parsexmlnode=None):
@ -332,16 +312,22 @@ class VirtualNetworkInterface(VirtualDevice):
Non fatal collisions (mac addr collides with inactive guest) will
return (False, "description of collision")
"""
mac = mac or self.macaddr
if mac is None:
searchmac = mac or self.macaddr
if searchmac is None:
return (False, None)
vms = self.conn.fetch_all_guests()
if _countMACaddr(vms, mac) > 0:
return (True, _("The MAC address '%s' is in use "
"by another virtual machine.") % mac)
def count_cb(ctx):
for mac in ctx.xpathEval("/domain/devices/interface/mac"):
macaddr = mac.xpathEval("attribute::address")[0].content
if macaddr and _compareMAC(searchmac, macaddr) == 0:
return True
return False
for vm in self.conn.fetch_all_guests():
xml = vm.get_xml(refresh_if_nec=False)
if util.get_xml_path(xml, func=count_cb):
return (True, _("The MAC address '%s' is in use "
"by another virtual machine.") % searchmac)
return (False, None)
def setup(self, meter=None):

View File

@ -31,6 +31,24 @@ from virtinst.cli import parse_optstr
_virtinst_uri_magic = "__virtinst_test__"
class _FetchObjWrapper(object):
"""
Wrapper to make virDomain etc. objects have a similar XML API as
virt-manager objects, so fetch_all* callers get similar results
"""
def __init__(self, backend):
self._backend = backend
self._xml = None
def get_xml(self, refresh_if_nec=True):
if self._xml is None or refresh_if_nec:
self._xml = self._backend.XMLDesc(0)
return self._xml
def get_backend(self):
return self._backend
class VirtualConnection(object):
"""
Wrapper for libvirt connection that provides various bits like
@ -70,6 +88,11 @@ class VirtualConnection(object):
# isn't hammering the connection over and over
self.cache_object_fetch = False
# These let virt-manager register a callback which provides its
# own cached object lists, rather than doing fresh calls
self.cb_fetch_all_guests = None
self.cb_fetch_all_pools = None
##############
# Properties #
@ -127,25 +150,35 @@ class VirtualConnection(object):
self._libvirtconn = conn
def fetch_all_guests(self):
# pylint: disable=E1102
if self.cb_fetch_all_guests:
return self.cb_fetch_all_guests()
# pylint: enable=E1102
key = "vms"
if key in self._fetch_cache:
return self._fetch_cache[key]
ignore, ignore, ret = pollhelpers.fetch_vms(self, {},
lambda obj, ignore: obj)
ret = ret.values()
ret = [_FetchObjWrapper(obj) for obj in ret.values()]
if self.cache_object_fetch:
self._fetch_cache[key] = ret
return ret
def fetch_all_pools(self):
# pylint: disable=E1102
if self.cb_fetch_all_pools:
return self.cb_fetch_all_pools()
# pylint: enable=E1102
key = "pools"
if key in self._fetch_cache:
return self._fetch_cache[key]
ignore, ignore, ret = pollhelpers.fetch_pools(self, {},
lambda obj, ignore: obj)
ret = ret.values()
ret = [_FetchObjWrapper(obj) for obj in ret.values()]
if self.cache_object_fetch:
self._fetch_cache[key] = ret
return ret

View File

@ -465,14 +465,15 @@ def lookup_pool_by_path(conn, path):
return None
def check_pool(pool, path):
xml_path = get_xml_path(pool.XMLDesc(0), "/pool/target/path")
xml_path = get_xml_path(pool.get_xml(refresh_if_nec=False),
"/pool/target/path")
if xml_path is not None and os.path.abspath(xml_path) == path:
return pool
for pool in conn.fetch_all_pools():
p = check_pool(pool, path)
if p:
return p
return p.get_backend()
return None