The attached patch adds some of the lower level plumbing for libvirt storage api awareness in virt-manager. Similar to the vmmNetwork and vmmDomain classes, I've added a vmmStoragePool and vmmStorageVol to wrap the underlying libvirt objects and provide convenience methods. The only other changes in this patch are to the connection object to poll for currently available pools and make this info accessable. I've been carrying this for a while so I think it's pretty stable. Thanks, Cole
# HG changeset patch # User "Cole Robinson <crobinso@xxxxxxxxxx>" # Date 1217535344 14400 # Node ID a3c5cd7b86ed627261054d1850c9b7646333553b # Parent 66bddd644b8297ec78e958f547991e358e7e84ec Add vmmStorage{Pool,Vol}, poll for these devices in connection tick function. diff -r 66bddd644b82 -r a3c5cd7b86ed src/virtManager/connection.py --- a/src/virtManager/connection.py Thu Jul 24 16:42:43 2008 -0400 +++ b/src/virtManager/connection.py Thu Jul 31 16:15:44 2008 -0400 @@ -36,6 +36,7 @@ from virtManager.domain import vmmDomain from virtManager.network import vmmNetwork from virtManager.netdev import vmmNetDevice +from virtManager.storagepool import vmmStoragePool LIBVIRT_POLICY_FILE = "/usr/share/PolicyKit/policy/libvirtd.policy" @@ -97,6 +98,14 @@ [str, str]), "net-stopped": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str, str]), + "pool-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + [str, str]), + "pool-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + [str, str]), + "pool-started": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + [str, str]), + "pool-stopped": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + [str, str]), "netdev-added": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str]), "netdev-removed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, @@ -134,6 +143,8 @@ self.state = self.STATE_DISCONNECTED self.vmm = None + # Connection Storage pools: UUID -> vmmStoragePool + self.pools = {} # Host network devices. name -> vmmNetDevice object self.netdevs = {} # Virtual networks UUUID -> vmmNetwork object @@ -339,6 +350,9 @@ def get_net_device(self, path): return self.netdevs[path] + def get_pool(self, uuid): + return self.pools[uuid] + def open(self): if self.state != self.STATE_DISCONNECTED: return @@ -513,6 +527,7 @@ #self.vmm.close() self.vmm = None self.nets = {} + self.pools = {} self.vms = {} self.activeUUIDs = [] self.record = [] @@ -527,6 +542,9 @@ def list_net_device_paths(self): return self.netdevs.keys() + + def list_pool_uuids(self): + return self.pools.keys() def get_host_info(self): return self.hostinfo @@ -661,6 +679,60 @@ logging.warn("Couldn't fetch inactive network name '%s'" % name) return (startNets, stopNets, newNets, origNets, currentNets) + + def _update_pools(self): + origPools = self.pools + currentPools = {} + startPools = [] + stopPools = [] + newPools = [] + newActivePoolNames = [] + newInactivePoolNames = [] + + try: + newActivePoolNames = self.vmm.listStoragePools() + except: + logging.warn("Unable to list active pools") + try: + newInactivePoolNames = self.vmm.listDefinedStoragePools() + except: + logging.warn("Unable to list inactive pools") + + for name in newActivePoolNames: + try: + pool = self.vmm.storagePoolLookupByName(name) + uuid = self.uuidstr(pool.UUID()) + if not origPools.has_key(uuid): + currentPools[uuid] = vmmStoragePool(self.config, self, + pool, uuid, True) + newPools.append(uuid) + startPools.append(uuid) + else: + currentPools[uuid] = origPools[uuid] + if not currentPools[uuid].is_active(): + currentPools[uuid].set_active(True) + startPools.append(uuid) + del origPools[uuid] + except libvirt.libvirtError: + logging.warn("Couldn't fetch active pool '%s'" % name) + + for name in newInactivePoolNames: + try: + pool = self.vmm.storagePoolLookupByName(name) + uuid = self.uuidstr(pool.UUID()) + if not origPools.has_key(uuid): + currentPools[uuid] = vmmStoragePool(self.config, self, + pool, uuid, False) + newPools.append(uuid) + else: + currentPools[uuid] = origPools[uuid] + if currentPools[uuid].is_active(): + currentPools[uuid].set_active(False) + stopPools.append(uuid) + del origPools[uuid] + except libvirt.libvirtError: + logging.warn("Couldn't fetch inactive pool '%s'" % name) + return (stopPools, startPools, origPools, newPools, currentPools) def _update_vms(self): """returns lists of changed VM states""" @@ -778,6 +850,10 @@ (startNets, stopNets, newNets, oldNets, self.nets) = self._update_nets() + # Update pools + (stopPools, startPools, oldPools, + newPools, self.pools) = self._update_pools() + # Poll for changed/new/removed VMs (startVMs, newVMs, oldVMs, self.vms, self.activeUUIDs) = self._update_vms() @@ -800,6 +876,15 @@ self.emit("net-started", self.uri, uuid) for uuid in stopNets: self.emit("net-stopped", self.uri, uuid) + + for uuid in oldPools: + self.emit("pool-removed", self.uri, uuid) + for uuid in newPools: + self.emit("pool-added", self.uri, uuid) + for uuid in startPools: + self.emit("pool-started", self.uri, uuid) + for uuid in stopPools: + self.emit("pool-stopped", self.uri, uuid) # Finally, we sample each domain now = time() diff -r 66bddd644b82 -r a3c5cd7b86ed src/virtManager/storagepool.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/virtManager/storagepool.py Thu Jul 31 16:15:44 2008 -0400 @@ -0,0 +1,163 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Copyright (C) 2008 Cole Robinson <crobinso@xxxxxxxxxx> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. +# + +import gobject +import libvirt +import libxml2 +import logging + +from virtManager.storagevol import vmmStorageVolume + +class vmmStoragePool(gobject.GObject): + __gsignals__ = { } + + def __init__(self, config, connection, pool, uuid, active): + self.__gobject_init__() + self.config = config + self.connection = connection + self.pool = pool # Libvirt pool object + self.uuid = uuid # String UUID + self.active = active # bool indicating if it is running + + self._volumes = {} # UUID->vmmStorageVolume mapping of the + # pools associated volumes + self._xml = None # xml cache + self._update_xml() + self.update_volumes() + + def set_active(self, state): + self.active = state + self._update_xml() + + def is_active(self): + return self.active + + def get_connection(self): + return self.connection + + def get_name(self): + return self.pool.name() + + def get_uuid(self): + return self.uuid + + def start(self): + self.pool.create(0) + self._update_xml() + + def stop(self): + self.pool.destroy() + self._update_xml() + + def delete(self): + self.pool.undefine() + del(self.pool) + + def _update_xml(self): + self._xml = self.pool.XMLDesc(0) + + def get_xml(self): + if self._xml is None: + self._update_xml() + return self._xml + + def set_autostart(self, value): + self.pool.setAutostart(value) + + def get_autostart(self): + return self.pool.autostart() + + def get_target_path(self): + return self._get_xml_path("/pool/target/path") + + def get_allocation(self): + return long(self._get_xml_path("/pool/allocation")) + def get_available(self): + return long(self._get_xml_path("/pool/available")) + def get_capacity(self): + return long(self._get_xml_path("/pool/capacity")) + + def get_pretty_allocation(self): + return self._prettyify(self.get_allocation()) + def get_pretty_available(self): + return self._prettyify(self.get_available()) + def get_pretty_capacity(self): + return self._prettyify(self.get_capacity()) + + def get_type(self): + return self._get_xml_path("/pool/@type") + + def get_volumes(self): + self.update_volumes() + return self._volumes + + def update_volumes(self): + if not self.is_active(): + self._volumes = {} + return + + self.pool.refresh(0) + vols = self.pool.listVolumes() + new_vol_list = {} + + for volname in vols: + if self._volumes.has_key(volname): + new_vol_list[volname] = self._volumes[volname] + else: + new_vol_list[volname] = vmmStorageVolume(self.config, + self.connection, + self.pool.storageVolLookupByName(volname), + volname) + self._volumes = new_vol_list + + def _get_xml_path(self, path): + doc = None + ctx = None + try: + xml = self.get_xml() + doc = libxml2.parseDoc(xml) + try: + ctx = doc.xpathNewContext() + + ret = ctx.xpathEval(path) + str = None + if ret != None: + if type(ret) == list: + if len(ret) == 1: + str = ret[0].content + else: + str = ret + ctx.xpathFreeContext() + return str + except: + if ctx: + ctx.xpathFreeContext() + return None + finally: + if doc is not None: + doc.freeDoc() + + def _prettyify(self, val): + if val > (1024*1024*1024): + return "%2.2f GB" % (val/(1024.0*1024.0*1024.0)) + else: + return "%2.2f MB" % (val/(1024.0*1024.0)) + +gobject.type_register(vmmStoragePool) diff -r 66bddd644b82 -r a3c5cd7b86ed src/virtManager/storagevol.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/virtManager/storagevol.py Thu Jul 31 16:15:44 2008 -0400 @@ -0,0 +1,111 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Copyright (C) 2008 Cole Robinson <crobinso@xxxxxxxxxx> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA. +# + +import gobject +import libvirt +import libxml2 +import logging + +class vmmStorageVolume(gobject.GObject): + __gsignals__ = { } + + def __init__(self, config, connection, vol, name): + self.__gobject_init__() + self.config = config + self.connection = connection + self.vol = vol # Libvirt storage volume object + self.name = name + self._xml = None # Cache xml rather than repeated lookups + self._update_xml() + + def get_connection(self): + return self.connection + + def get_name(self): + return self.name + + def get_path(self): + return self.vol.path() + + def delete(self): + self.vol.undefine() + del(self.vol) + + def get_xml(self): + if self._xml is None: + self._update_xml() + return self._xml + + def get_target_path(self): + return self._get_xml_path("/volume/target/path") + + def get_format(self): + return self._get_xml_path("/volume/target/format/@type") + + def get_allocation(self): + return long(self._get_xml_path("/volume/allocation")) + def get_capacity(self): + return long(self._get_xml_path("/volume/capacity")) + + def get_pretty_capacity(self): + return self._prettyify(self.get_capacity()) + def get_pretty_allocation(self): + return self._prettyify(self.get_allocation()) + + def get_type(self): + return self._get_xml_path("/volume/format/@type") + + def _update_xml(self): + self._xml = self.vol.XMLDesc(0) + + def _get_xml_path(self, path): + doc = None + ctx = None + try: + xml = self.get_xml() + doc = libxml2.parseDoc(xml) + try: + ctx = doc.xpathNewContext() + + ret = ctx.xpathEval(path) + str = None + if ret != None: + if type(ret) == list: + if len(ret) == 1: + str = ret[0].content + else: + str = ret + ctx.xpathFreeContext() + return str + except: + if ctx: + ctx.xpathFreeContext() + return None + finally: + if doc is not None: + doc.freeDoc() + + def _prettyify(self, val): + if val > (1024*1024*1024): + return "%2.2f GB" % (val/(1024.0*1024.0*1024.0)) + else: + return "%2.2f MB" % (val/(1024.0*1024.0)) + +gobject.type_register(vmmStorageVolume)
_______________________________________________ et-mgmt-tools mailing list et-mgmt-tools@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/et-mgmt-tools