From: Han Han <h...@redhat.com> Since Nautilus ceph supports separate image namespaces within a pool for tenant isolation and QEMU adds it as a rbd blockdev options from 5.0.0. The source name with format "<pool>/<namespace>/<image>" could be used to access a rbd image with namespace.
Add unit tests for this attribute. https://bugzilla.redhat.com/show_bug.cgi?id=1816909 Closes: https://gitlab.com/libvirt/libvirt/-/issues/405 Signed-off-by: Han Han <h...@redhat.com> Signed-off-by: Peter Krempa <pkre...@redhat.com> --- docs/formatdomain.rst | 6 +++ src/conf/domain_conf.c | 3 +- src/conf/storage_source_conf.c | 47 ++++++++++++++----- src/conf/storage_source_conf.h | 1 + src/qemu/qemu_block.c | 6 ++- .../storage_file_backend_gluster.c | 2 +- .../storage_source_backingstore.c | 2 +- .../disk-network-rbd.x86_64-latest.args | 4 +- .../disk-network-rbd.x86_64-latest.xml | 4 +- tests/qemuxmlconfdata/disk-network-rbd.xml | 4 +- 10 files changed, 56 insertions(+), 23 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 9a2f065590..e8022e502d 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -2958,6 +2958,12 @@ paravirtualized driver is specified via the ``disk`` element. the optional attribute ``tlsHostname`` can be used to override the expected host name of the NBD server used for TLS certificate verification. + For "rbd", the ``name`` attribute could be two formats: the format of + ``pool_name/image_name`` includes the rbd pool name and image name with + default rbd pool namespace; for the customized namespace, the format is + ``pool_name/namespace/image_name`` ( :since:`Since 11.6.0 and QEMU 5.0` ). + The pool name, namespace and image are separated by slash. + For protocols ``http`` and ``https`` an optional attribute ``query`` specifies the query string. ( :since:`Since 6.2.0` ) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c7bad53ae6..7a8713771c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7381,7 +7381,8 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node, return -1; } - if (virStorageSourceNetworkProtocolPathSplit(src->path, src->protocol, NULL, NULL) < 0) + if (virStorageSourceNetworkProtocolPathSplit(src->path, src->protocol, + NULL, NULL, NULL) < 0) return -1; if (virXMLPropTristateBool(node, "tls", VIR_XML_PROP_NONE, diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c index 9014fa37e6..dd46ea695b 100644 --- a/src/conf/storage_source_conf.c +++ b/src/conf/storage_source_conf.c @@ -1449,6 +1449,7 @@ virStorageSourceFDTupleNew(void) * @path: path to split * @protocol: protocol * @pool: filled with pool name (may be NULL) + * @namespace: filed with namespace (may be NULL) * @image: filled with image name (may be NULL) * * Historically libvirt accepted the specification of Gluster's volume and @@ -1463,35 +1464,57 @@ int virStorageSourceNetworkProtocolPathSplit(const char *path, virStorageNetProtocol protocol, char **pool, + char **namespace, char **image) { - - g_autofree char *pathcopy = g_strdup(path); - char *tmp; + g_auto(GStrv) tokens = NULL; + int components_max = 2; + size_t ncomponents = 0; + size_t i; if (protocol != VIR_STORAGE_NET_PROTOCOL_GLUSTER && protocol != VIR_STORAGE_NET_PROTOCOL_RBD) { if (image) - *image = g_steal_pointer(&pathcopy); + *image = g_strdup(path); return 0; } - if (!(tmp = strchr(pathcopy, '/')) || tmp == pathcopy) { - virReportError(VIR_ERR_XML_ERROR, - _("can't split path '%1$s' into pool name and image name"), - pathcopy); - return -1; + if (protocol == VIR_STORAGE_NET_PROTOCOL_RBD) { + /* the name of rbd can be <pool>/<image> or <pool>/<namespace>/<image> */ + components_max = 3; } - tmp[0] = '\0'; + if ((tokens = g_strsplit(path, "/", components_max))) + ncomponents = g_strv_length(tokens); + + if (ncomponents < 2) + goto error; + + for (i = 0; i < ncomponents; i++) { + if (*tokens[i] == '\0') + goto error; + } if (pool) - *pool = g_steal_pointer(&pathcopy); + *pool = g_strdup(tokens[0]); + + if (namespace) { + if (ncomponents == 3) + *namespace = g_strdup(tokens[1]); + else + *namespace = NULL; + } if (image) - *image = g_strdup(tmp + 1); + *image = g_strdup(tokens[ncomponents - 1]); return 0; + + error: + virReportError(VIR_ERR_XML_ERROR, + _("failed to split path '%1$s' into 'pool/image' or 'pool/namespace/image' components"), + path); + return -1; } diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h index 798ca20ac4..aa4efda9ad 100644 --- a/src/conf/storage_source_conf.h +++ b/src/conf/storage_source_conf.h @@ -601,4 +601,5 @@ int virStorageSourceNetworkProtocolPathSplit(const char *path, virStorageNetProtocol protocol, char **pool, + char **namespace, char **image); diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 9b370d4c7c..daefeb2f45 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -405,7 +405,7 @@ qemuBlockStorageSourceGetGlusterProps(virStorageSource *src, if (virStorageSourceNetworkProtocolPathSplit(src->path, VIR_STORAGE_NET_PROTOCOL_GLUSTER, - &volume, &path) < 0) + &volume, NULL, &path) < 0) return NULL; /* { driver:"gluster", @@ -666,11 +666,12 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, g_autoptr(virJSONValue) authmodes = NULL; const char *keysecret = NULL; g_autofree char *pool = NULL; + g_autofree char *namespace = NULL; g_autofree char *image = NULL; if (virStorageSourceNetworkProtocolPathSplit(src->path, VIR_STORAGE_NET_PROTOCOL_RBD, - &pool, &image) < 0) + &pool, &namespace, &image) < 0) return NULL; if (src->nhosts > 0 && @@ -726,6 +727,7 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, if (virJSONValueObjectAdd(&ret, "s:pool", pool, + "S:namespace", namespace, "s:image", image, "S:snapshot", src->snapshot, "S:conf", src->configFile, diff --git a/src/storage_file/storage_file_backend_gluster.c b/src/storage_file/storage_file_backend_gluster.c index 8778995b6c..4682b85903 100644 --- a/src/storage_file/storage_file_backend_gluster.c +++ b/src/storage_file/storage_file_backend_gluster.c @@ -106,7 +106,7 @@ virStorageFileBackendGlusterInit(virStorageSource *src) if (virStorageSourceNetworkProtocolPathSplit(src->path, VIR_STORAGE_NET_PROTOCOL_GLUSTER, - &volume, &image) < 0) + &volume, NULL, &image) < 0) return -1; priv = g_new0(virStorageFileBackendGlusterPriv, 1); diff --git a/src/storage_file/storage_source_backingstore.c b/src/storage_file/storage_source_backingstore.c index 700a2f5dcb..821378883c 100644 --- a/src/storage_file/storage_source_backingstore.c +++ b/src/storage_file/storage_source_backingstore.c @@ -109,7 +109,7 @@ virStorageSourceParseBackingURI(virStorageSource *src, if (src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) { if (virStorageSourceNetworkProtocolPathSplit(src->path, src->protocol, - NULL, NULL) < 0) + NULL, NULL, NULL) < 0) return -1; } diff --git a/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.args b/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.args index f344b57371..a15263c884 100644 --- a/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.args +++ b/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.args @@ -36,9 +36,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \ -blockdev '{"driver":"rbd","pool":"pool","image":"image","snapshot":"foo","conf":"/blah/test.conf","node-name":"libvirt-3-storage","read-only":false}' \ -device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x5","drive":"libvirt-3-storage","id":"virtio-disk3"}' \ -object '{"qom-type":"secret","id":"libvirt-2-storage-auth-secret0","data":"9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1","keyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw==","format":"base64"}' \ --blockdev '{"driver":"rbd","pool":"pool","image":"image","server":[{"host":"mon1.example.org","port":"6321"},{"host":"mon2.example.org","port":"6322"},{"host":"mon3.example.org","port":"6322"}],"user":"myname","auth-client-required":["cephx","none"],"key-secret":"libvirt-2-storage-auth-secret0","node-name":"libvirt-2-storage","read-only":false}' \ +-blockdev '{"driver":"rbd","pool":"pool","namespace":"namespace","image":"image","server":[{"host":"mon1.example.org","port":"6321"},{"host":"mon2.example.org","port":"6322"},{"host":"mon3.example.org","port":"6322"}],"user":"myname","auth-client-required":["cephx","none"],"key-secret":"libvirt-2-storage-auth-secret0","node-name":"libvirt-2-storage","read-only":false}' \ -device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x6","drive":"libvirt-2-storage","id":"virtio-disk4"}' \ --blockdev '{"driver":"rbd","pool":"pool","image":"image","server":[{"host":"::1","port":"6321"},{"host":"example.org","port":"6789"},{"host":"ffff:1234:567:abc::0f","port":"6322"},{"host":"2001:db8::ff00:42:8329","port":"6322"}],"node-name":"libvirt-1-storage","read-only":false}' \ +-blockdev '{"driver":"rbd","pool":"pool","namespace":"namespace","image":"image","server":[{"host":"::1","port":"6321"},{"host":"example.org","port":"6789"},{"host":"ffff:1234:567:abc::0f","port":"6322"},{"host":"2001:db8::ff00:42:8329","port":"6322"}],"node-name":"libvirt-1-storage","read-only":false}' \ -device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x7","drive":"libvirt-1-storage","id":"virtio-disk5"}' \ -audiodev '{"id":"audio1","driver":"none"}' \ -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ diff --git a/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.xml b/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.xml index 6da7185d18..cfb10a701c 100644 --- a/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.xml +++ b/tests/qemuxmlconfdata/disk-network-rbd.x86_64-latest.xml @@ -60,7 +60,7 @@ <auth username='myname'> <secret type='ceph' usage='mycluster_myname'/> </auth> - <source protocol='rbd' name='pool/image'> + <source protocol='rbd' name='pool/namespace/image'> <host name='mon1.example.org' port='6321'/> <host name='mon2.example.org' port='6322'/> <host name='mon3.example.org' port='6322'/> @@ -70,7 +70,7 @@ </disk> <disk type='network' device='disk'> <driver name='qemu' type='raw'/> - <source protocol='rbd' name='pool/image'> + <source protocol='rbd' name='pool/namespace/image'> <host name='::1' port='6321'/> <host name='example.org' port='6789'/> <host name='ffff:1234:567:abc::0f' port='6322'/> diff --git a/tests/qemuxmlconfdata/disk-network-rbd.xml b/tests/qemuxmlconfdata/disk-network-rbd.xml index c427fbea83..0973f50ecc 100644 --- a/tests/qemuxmlconfdata/disk-network-rbd.xml +++ b/tests/qemuxmlconfdata/disk-network-rbd.xml @@ -53,7 +53,7 @@ <auth username='myname'> <secret type='ceph' usage='mycluster_myname'/> </auth> - <source protocol='rbd' name='pool/image'> + <source protocol='rbd' name='pool/namespace/image'> <host name='mon1.example.org' port='6321'/> <host name='mon2.example.org' port='6322'/> <host name='mon3.example.org' port='6322'/> @@ -62,7 +62,7 @@ </disk> <disk type='network' device='disk'> <driver name='qemu' type='raw'/> - <source protocol='rbd' name='pool/image'> + <source protocol='rbd' name='pool/namespace/image'> <host name='::1' port='6321'/> <host name='example.org' port='6789'/> <host name='ffff:1234:567:abc::0f' port='6322'/> -- 2.49.0