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

Reply via email to