Introduce a basic StoragePoolCapabilities class to fetch the pool capabilities (if available) from a libvirt connection, and query for supported pool types. The poolcaps-fs.xml file was copied from the libvirt test suite. Signed-off-by: Pino Toscano <ptoscano@xxxxxxxxxx> --- tests/data/capabilities/poolcaps-fs.xml | 207 ++++++++++++++++++++++++ tests/test_capabilities.py | 25 +++ virtinst/__init__.py | 1 + virtinst/storagepoolcapabilities.py | 61 +++++++ 4 files changed, 294 insertions(+) create mode 100644 tests/data/capabilities/poolcaps-fs.xml create mode 100644 virtinst/storagepoolcapabilities.py diff --git a/tests/data/capabilities/poolcaps-fs.xml b/tests/data/capabilities/poolcaps-fs.xml new file mode 100644 index 00000000..eee75af7 --- /dev/null +++ b/tests/data/capabilities/poolcaps-fs.xml @@ -0,0 +1,207 @@ +<storagepoolCapabilities> + <pool type='dir' supported='no'> + <volOptions> + <defaultFormat type='raw'/> + <enum name='targetFormatType'> + <value>none</value> + <value>raw</value> + <value>dir</value> + <value>bochs</value> + <value>cloop</value> + <value>dmg</value> + <value>iso</value> + <value>vpc</value> + <value>vdi</value> + <value>fat</value> + <value>vhd</value> + <value>ploop</value> + <value>cow</value> + <value>qcow</value> + <value>qcow2</value> + <value>qed</value> + <value>vmdk</value> + </enum> + </volOptions> + </pool> + <pool type='fs' supported='yes'> + <poolOptions> + <defaultFormat type='auto'/> + <enum name='sourceFormatType'> + <value>auto</value> + <value>ext2</value> + <value>ext3</value> + <value>ext4</value> + <value>ufs</value> + <value>iso9660</value> + <value>udf</value> + <value>gfs</value> + <value>gfs2</value> + <value>vfat</value> + <value>hfs+</value> + <value>xfs</value> + <value>ocfs2</value> + <value>vmfs</value> + </enum> + </poolOptions> + <volOptions> + <defaultFormat type='raw'/> + <enum name='targetFormatType'> + <value>none</value> + <value>raw</value> + <value>dir</value> + <value>bochs</value> + <value>cloop</value> + <value>dmg</value> + <value>iso</value> + <value>vpc</value> + <value>vdi</value> + <value>fat</value> + <value>vhd</value> + <value>ploop</value> + <value>cow</value> + <value>qcow</value> + <value>qcow2</value> + <value>qed</value> + <value>vmdk</value> + </enum> + </volOptions> + </pool> + <pool type='netfs' supported='no'> + <poolOptions> + <defaultFormat type='auto'/> + <enum name='sourceFormatType'> + <value>auto</value> + <value>nfs</value> + <value>glusterfs</value> + <value>cifs</value> + </enum> + </poolOptions> + <volOptions> + <defaultFormat type='raw'/> + <enum name='targetFormatType'> + <value>none</value> + <value>raw</value> + <value>dir</value> + <value>bochs</value> + <value>cloop</value> + <value>dmg</value> + <value>iso</value> + <value>vpc</value> + <value>vdi</value> + <value>fat</value> + <value>vhd</value> + <value>ploop</value> + <value>cow</value> + <value>qcow</value> + <value>qcow2</value> + <value>qed</value> + <value>vmdk</value> + </enum> + </volOptions> + </pool> + <pool type='logical' supported='no'> + <poolOptions> + <defaultFormat type='lvm2'/> + <enum name='sourceFormatType'> + <value>unknown</value> + <value>lvm2</value> + </enum> + </poolOptions> + </pool> + <pool type='disk' supported='no'> + <poolOptions> + <defaultFormat type='unknown'/> + <enum name='sourceFormatType'> + <value>unknown</value> + <value>dos</value> + <value>dvh</value> + <value>gpt</value> + <value>mac</value> + <value>bsd</value> + <value>pc98</value> + <value>sun</value> + <value>lvm2</value> + </enum> + </poolOptions> + <volOptions> + <defaultFormat type='none'/> + <enum name='targetFormatType'> + <value>none</value> + <value>linux</value> + <value>fat16</value> + <value>fat32</value> + <value>linux-swap</value> + <value>linux-lvm</value> + <value>linux-raid</value> + <value>extended</value> + </enum> + </volOptions> + </pool> + <pool type='iscsi' supported='no'> + </pool> + <pool type='iscsi-direct' supported='no'> + </pool> + <pool type='scsi' supported='no'> + </pool> + <pool type='mpath' supported='no'> + </pool> + <pool type='rbd' supported='no'> + <volOptions> + <defaultFormat type='raw'/> + <enum name='targetFormatType'> + </enum> + </volOptions> + </pool> + <pool type='sheepdog' supported='no'> + </pool> + <pool type='gluster' supported='no'> + <volOptions> + <defaultFormat type='raw'/> + <enum name='targetFormatType'> + <value>none</value> + <value>raw</value> + <value>dir</value> + <value>bochs</value> + <value>cloop</value> + <value>dmg</value> + <value>iso</value> + <value>vpc</value> + <value>vdi</value> + <value>fat</value> + <value>vhd</value> + <value>ploop</value> + <value>cow</value> + <value>qcow</value> + <value>qcow2</value> + <value>qed</value> + <value>vmdk</value> + </enum> + </volOptions> + </pool> + <pool type='zfs' supported='no'> + </pool> + <pool type='vstorage' supported='no'> + <volOptions> + <defaultFormat type='raw'/> + <enum name='targetFormatType'> + <value>none</value> + <value>raw</value> + <value>dir</value> + <value>bochs</value> + <value>cloop</value> + <value>dmg</value> + <value>iso</value> + <value>vpc</value> + <value>vdi</value> + <value>fat</value> + <value>vhd</value> + <value>ploop</value> + <value>cow</value> + <value>qcow</value> + <value>qcow2</value> + <value>qed</value> + <value>vmdk</value> + </enum> + </volOptions> + </pool> +</storagepoolCapabilities> diff --git a/tests/test_capabilities.py b/tests/test_capabilities.py index 0182e20f..84cb6bdb 100644 --- a/tests/test_capabilities.py +++ b/tests/test_capabilities.py @@ -11,6 +11,8 @@ from tests import utils from virtinst import Capabilities from virtinst import DomainCapabilities +from virtinst import StoragePool +from virtinst import StoragePoolCapabilities DATADIR = utils.DATADIR + "/capabilities" @@ -112,3 +114,26 @@ def testDomainCapabilitiesAArch64(): caps = DomainCapabilities(utils.URIs.open_testdriver_cached(), xml) assert "None" in caps.label_for_firmware_path(None) + + +###################################### +# storagepoolcapabilities.py testing # +###################################### + + +def testStoragePoolCapabilities(): + xml = open(DATADIR + "/poolcaps-fs.xml").read() + caps = StoragePoolCapabilities(utils.URIs.open_testdriver_cached(), xml) + + assert len(caps.pools) == 14 + assert caps.supports_type(StoragePool.TYPE_DIR) is False + assert caps.supports_type(StoragePool.TYPE_FS) is True + assert caps.supports_type("unknownstoragepooltype") is False + + +def testStoragePoolCapabilitiesNone(): + caps = StoragePoolCapabilities(utils.URIs.open_testdriver_cached()) + + assert len(caps.pools) == 0 + assert caps.supports_type(StoragePool.TYPE_DIR) is True + assert caps.supports_type("unknownstoragepooltype") is True diff --git a/virtinst/__init__.py b/virtinst/__init__.py index 02e852c1..f7e9d5ae 100644 --- a/virtinst/__init__.py +++ b/virtinst/__init__.py @@ -51,6 +51,7 @@ from virtinst.domain import * # pylint: disable=wildcard-import from virtinst.capabilities import Capabilities from virtinst.domcapabilities import DomainCapabilities +from virtinst.storagepoolcapabilities import StoragePoolCapabilities from virtinst.network import Network from virtinst.nodedev import NodeDevice from virtinst.storage import StoragePool, StorageVolume diff --git a/virtinst/storagepoolcapabilities.py b/virtinst/storagepoolcapabilities.py new file mode 100644 index 00000000..83627d59 --- /dev/null +++ b/virtinst/storagepoolcapabilities.py @@ -0,0 +1,61 @@ +# +# Support for parsing libvirt's storagepoolcapabilities XML +# +# Copyright 2020 Red Hat, Inc. +# +# This work is licensed under the GNU GPLv2 or later. +# See the COPYING file in the top-level directory. + +from .logger import log +from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty + + +########################## +# Toplevel <pool> parser # +########################## + +class _Pool(XMLBuilder): + XML_NAME = "pool" + pool_type = XMLProperty("./@type") + supported = XMLProperty("./@supported", is_yesno=True) + + +###################################### +# StoragePoolCapabilities main class # +###################################### + +class StoragePoolCapabilities(XMLBuilder): + @staticmethod + def build_from_params(conn, flags=0): + xml = None + if conn.support.conn_storage_pool_capabilities(): + try: + xml = conn.get_backend().getStoragePoolCapabilities(flags) + except Exception: # pragma: no cover + log.debug("Error fetching storagepoolcapabilities XML", + exc_info=True) + + if not xml: + # If not supported, just use a stub object + return StoragePoolCapabilities(conn) + return StoragePoolCapabilities(conn, parsexml=xml) + + def __init__(self, *args, **kwargs): + XMLBuilder.__init__(self, *args, **kwargs) + self._supported = kwargs.get('parsexml') is not None or len(args) >= 2 + + def supports_type(self, pool_type): + """ + Returns True if either libvirt supports the passed pool type + or if libvirt does not have the getStoragePoolCapabilities API + (and thus there is no way to know). + """ + if not self._supported: + return True + for pool in self.pools: + if pool.pool_type == pool_type: + return pool.supported + return False + + XML_NAME = "storagepoolCapabilities" + pools = XMLChildProperty(_Pool) -- 2.28.0