From: Han Han <hhan(a)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 <hhan(a)redhat.com>
Signed-off-by: Peter Krempa <pkrempa(a)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