]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: add --snap-id option to "rbd clone"
authorIlya Dryomov <idryomov@gmail.com>
Thu, 30 May 2024 09:38:53 +0000 (11:38 +0200)
committerIlya Dryomov <idryomov@gmail.com>
Fri, 14 Jun 2024 07:26:10 +0000 (09:26 +0200)
Enable cloning from non-user snapshots via the CLI.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
(cherry picked from commit 06c0dd2b33d0a632c1d4bbe815e729028c58aeff)

PendingReleaseNotes
qa/workunits/rbd/cli_generic.sh
src/test/cli/rbd/help.t
src/tools/rbd/action/Clone.cc

index ef43007e8e9c361d3cab444ca871aaa45b97c95a..16e26192486af62d6fef38155b7dcbcbe3b14d68 100644 (file)
@@ -205,6 +205,10 @@ CephFS: Disallow delegating preallocated inode ranges to clients. Config
 * Monitoring: RGW S3 Analytics: A new Grafana dashboard is now available, enabling you to
   visualize per bucket and user analytics data, including total GETs, PUTs, Deletes,
   Copies, and list metrics.
+* RBD: Support for cloning from non-user type snapshots is added.  This is
+  intended primarily as a building block for cloning new groups from group
+  snapshots created with `rbd group snap create` command, but has also been
+  exposed via the new `--snap-id` option for `rbd clone` command.
 
 >=18.0.0
 
index 15c47074db5f9131b68307d038ad839e156e857f..42c15fc28e8a5d7c134ed491a10fd75cc77a4103 100755 (executable)
@@ -394,10 +394,26 @@ test_clone() {
     rbd ls -l | grep clone2 | grep rbd2/clone@s1
     rbd -p rbd2 ls | grep -v clone2
 
+    rbd clone rbd2/clone clone3 |& grep 'snapshot name was not specified'
+    rbd clone rbd2/clone@invalid clone3 |& grep 'failed to open parent image'
+    rbd clone rbd2/clone --snap-id 0 clone3 |& grep 'failed to open parent image'
+    rbd clone rbd2/clone@invalid --snap-id 0 clone3 |&
+        grep 'trying to access snapshot using both name and id'
+    SNAP_ID=$(rbd snap ls rbd2/clone --format json |
+        jq '.[] | select(.name == "s1") | .id')
+    rbd clone --snap-id $SNAP_ID rbd2/clone clone3
+    rbd ls | grep clone3
+    rbd ls -l | grep clone3 | grep rbd2/clone@s1
+    test "$(rbd -p rbd2 ls)" = 'clone'
+    test "$(rbd ls -l | grep -c rbd2/clone@s1)" = '2'
+    rbd flatten clone3
+    test "$(rbd ls -l | grep -c rbd2/clone@s1)" = '1'
+
     rbd rm clone2
     rbd snap unprotect rbd2/clone@s1
     rbd snap rm rbd2/clone@s1
     rbd rm rbd2/clone
+    rbd rm clone3
     rbd snap unprotect test1@s1
     rbd snap rm test1@s1
     rbd rm test1
@@ -752,7 +768,9 @@ test_clone_v2() {
     rbd snap create test1@1
     rbd clone --rbd-default-clone-format=1 test1@1 test2 && exit 1 || true
     rbd clone --rbd-default-clone-format=2 test1@1 test2
-    rbd clone --rbd-default-clone-format=2 test1@1 test3
+    SNAP_ID=$(rbd snap ls test1 --format json |
+        jq '.[] | select(.name == "1") | .id')
+    rbd clone --rbd-default-clone-format=2 --snap-id $SNAP_ID test1 test3
 
     rbd snap protect test1@1
     rbd clone --rbd-default-clone-format=1 test1@1 test4
index 866bd8f11c85fd538c82a224475ea67603ef2523..5a51199d32c49b9a5a4e35a811101c0d9d6d3adb 100644 (file)
   
   rbd help clone
   usage: rbd clone [--pool <pool>] [--namespace <namespace>] [--image <image>] 
-                   [--snap <snap>] [--dest-pool <dest-pool>] 
-                   [--dest-namespace <dest-namespace>] [--dest <dest>] 
-                   [--order <order>] [--object-size <object-size>] 
+                   [--snap <snap>] [--snap-id <snap-id>] 
+                   [--dest-pool <dest-pool>] [--dest-namespace <dest-namespace>] 
+                   [--dest <dest>] [--order <order>] 
+                   [--object-size <object-size>] 
                    [--image-feature <image-feature>] [--image-shared] 
                    [--stripe-unit <stripe-unit>] [--stripe-count <stripe-count>] 
                    [--data-pool <data-pool>] 
     --namespace arg           source namespace name
     --image arg               source image name
     --snap arg                source snapshot name
+    --snap-id arg             source snapshot id
     --dest-pool arg           destination pool name
     --dest-namespace arg      destination namespace name
     --dest arg                destination image name
index 6406c957e49804398a7051c165f9e83571ca6b41..874024f482bd2c1c0919924f927496753d5310b9 100644 (file)
@@ -4,6 +4,7 @@
 #include "tools/rbd/ArgumentTypes.h"
 #include "tools/rbd/Shell.h"
 #include "tools/rbd/Utils.h"
+#include "include/types.h"
 #include "common/errno.h"
 #include <iostream>
 #include <boost/program_options.hpp>
@@ -15,16 +16,10 @@ namespace clone {
 namespace at = argument_types;
 namespace po = boost::program_options;
 
-int do_clone(librbd::RBD &rbd, librados::IoCtx &p_ioctx,
-             const char *p_name, const char *p_snapname,
-             librados::IoCtx &c_ioctx, const char *c_name,
-             librbd::ImageOptions& opts) {
-  return rbd.clone3(p_ioctx, p_name, p_snapname, c_ioctx, c_name, opts);
-}
-
 void get_arguments(po::options_description *positional,
                    po::options_description *options) {
   at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_SOURCE);
+  at::add_snap_id_option(options, at::ARGUMENT_MODIFIER_SOURCE);
   at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST);
   at::add_create_image_options(options, false);
 }
@@ -36,14 +31,28 @@ int execute(const po::variables_map &vm,
   std::string namespace_name;
   std::string image_name;
   std::string snap_name;
+  uint64_t snap_id = CEPH_NOSNAP;
+
+  if (vm.count(at::SNAPSHOT_ID)) {
+    snap_id = vm[at::SNAPSHOT_ID].as<uint64_t>();
+  }
+
   int r = utils::get_pool_image_snapshot_names(
     vm, at::ARGUMENT_MODIFIER_SOURCE, &arg_index, &pool_name, &namespace_name,
-    &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
+    &image_name, &snap_name, true,
+    (snap_id == CEPH_NOSNAP ? utils::SNAPSHOT_PRESENCE_REQUIRED :
+                              utils::SNAPSHOT_PRESENCE_PERMITTED),
     utils::SPEC_VALIDATION_NONE);
   if (r < 0) {
     return r;
   }
 
+  if (!snap_name.empty() && snap_id != CEPH_NOSNAP) {
+    std::cerr << "rbd: trying to access snapshot using both name and id."
+              << std::endl;
+    return -EINVAL;
+  }
+
   std::string dst_pool_name;
   std::string dst_namespace_name;
   std::string dst_image_name;
@@ -77,8 +86,13 @@ int execute(const po::variables_map &vm,
   }
 
   librbd::RBD rbd;
-  r = do_clone(rbd, io_ctx, image_name.c_str(), snap_name.c_str(), dst_io_ctx,
-               dst_image_name.c_str(), opts);
+  if (!snap_name.empty()) {
+    r = rbd.clone3(io_ctx, image_name.c_str(), snap_name.c_str(), dst_io_ctx,
+                   dst_image_name.c_str(), opts);
+  } else {
+    r = rbd.clone4(io_ctx, image_name.c_str(), snap_id, dst_io_ctx,
+                   dst_image_name.c_str(), opts);
+  }
   if (r == -EXDEV) {
     std::cerr << "rbd: clone v2 required for cross-namespace clones."
               << std::endl;