]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: support clone_by_snap_id flag in clone API for group snapshots 69883/head
authorImran Imtiaz <imran.imtiaz@uk.ibm.com>
Wed, 1 Jul 2026 15:31:52 +0000 (16:31 +0100)
committerImran Imtiaz <imran.imtiaz@uk.ibm.com>
Thu, 2 Jul 2026 15:25:35 +0000 (16:25 +0100)
The clone API endpoint POST /api/block/image/{image_spec}/snap/{snapshot_name}/clone
only accepted a snapshot name, which uses rbd_clone3 (clone by name). This only works
for snapshots in the user namespace.

Group snapshots (with .group prefix, in RBD_SNAP_NAMESPACE_TYPE_GROUP namespace)
require rbd_clone4 (clone by snap ID). The rbd Python binding already supports this:
passing an int for p_snapshot triggers rbd_clone4.

Add an optional clone_by_snap_id boolean flag to the clone endpoint. When set, the
path parameter is treated as a numeric snap ID and passed directly as an int to
rbd.RBD().clone(). Clone format 2 is enforced because this flag is intended for
non-user namespace snapshots which cannot be protected (a prerequisite for clone
format 1).

Usage:
  POST /api/block/image/{image_spec}/snap/{snap_id}/clone
  {"clone_by_snap_id": true, ...}

Fixes: https://tracker.ceph.com/issues/77875
Signed-off-by: Imran Imtiaz <imran.imtiaz@uk.ibm.com>
Assisted-by: IBM Bob
src/pybind/mgr/dashboard/controllers/rbd.py
src/pybind/mgr/dashboard/openapi.yaml

index 54ec2f75de481986db22b5e285bb9127766c95b4..1496d57865b9991f6c7a41276a1d0ae6af4a6483 100644 (file)
@@ -317,7 +317,7 @@ class RbdSnapshot(RESTController):
     def clone(self, image_spec, snapshot_name, child_pool_name,
               child_image_name, child_namespace=None, obj_size=None, features=None,
               stripe_unit=None, stripe_count=None, data_pool=None,
-              configuration=None, metadata=None):
+              configuration=None, metadata=None, clone_by_snap_id=False):
         """
         Clones a snapshot to an image
         """
@@ -334,10 +334,25 @@ class RbdSnapshot(RESTController):
                 # Set features
                 feature_bitmask = format_features(features)
 
+                # When clone_by_snap_id is set, treat snapshot_name as a
+                # numeric snap ID and clone by ID. This is required for
+                # non-user namespace snapshots (e.g. group snapshots) which
+                # cannot be cloned by name. Passing an int to rbd.RBD().clone()
+                # triggers rbd_clone4 (by snap ID) instead of rbd_clone3.
+                # Clone format 2 is enforced here because this flag is intended
+                # for non-user namespace snapshots which cannot be protected
+                # (a prerequisite for clone format 1).
+                snap_ref = snapshot_name
+                clone_format = None
+                if clone_by_snap_id:
+                    snap_ref = int(snapshot_name)
+                    clone_format = 2
+
                 rbd_inst = rbd.RBD()
-                rbd_inst.clone(p_ioctx, image_name, snapshot_name, ioctx,
+                rbd_inst.clone(p_ioctx, image_name, snap_ref, ioctx,
                                child_image_name, feature_bitmask, l_order,
-                               stripe_unit, stripe_count, data_pool)
+                               stripe_unit, stripe_count, data_pool,
+                               clone_format=clone_format)
 
                 RbdConfiguration(pool_ioctx=ioctx, image_name=child_image_name).set_configuration(
                     configuration)
index 83f0ca149111e66cdb63a68bc436cb9ceda53148..b72f8e2893c5948db5bbd1bd76a24ff33363e461 100644 (file)
@@ -1198,6 +1198,9 @@ paths:
                   type: string
                 child_pool_name:
                   type: string
+                clone_by_snap_id:
+                  default: false
+                  type: boolean
                 configuration:
                   type: string
                 data_pool: