From: Ilya Dryomov Date: Thu, 30 May 2024 09:38:53 +0000 (+0200) Subject: rbd: add --snap-id option to "rbd clone" X-Git-Tag: v20.0.0~1745^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=06c0dd2b33d0a632c1d4bbe815e729028c58aeff;p=ceph.git rbd: add --snap-id option to "rbd clone" Enable cloning from non-user snapshots via the CLI. Signed-off-by: Ilya Dryomov --- diff --git a/PendingReleaseNotes b/PendingReleaseNotes index e07d02f334fe..a9259aee5c0b 100644 --- a/PendingReleaseNotes +++ b/PendingReleaseNotes @@ -226,6 +226,10 @@ CephFS: Disallow delegating preallocated inode ranges to clients. Config Copies, and list metrics. * RBD: `Image::access_timestamp` and `Image::modify_timestamp` Python APIs now return timestamps in UTC. +* 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 diff --git a/qa/workunits/rbd/cli_generic.sh b/qa/workunits/rbd/cli_generic.sh index 15c47074db5f..42c15fc28e8a 100755 --- a/qa/workunits/rbd/cli_generic.sh +++ b/qa/workunits/rbd/cli_generic.sh @@ -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 diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 69060b0af12f..c981996ea9a5 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -222,9 +222,10 @@ rbd help clone usage: rbd clone [--pool ] [--namespace ] [--image ] - [--snap ] [--dest-pool ] - [--dest-namespace ] [--dest ] - [--order ] [--object-size ] + [--snap ] [--snap-id ] + [--dest-pool ] [--dest-namespace ] + [--dest ] [--order ] + [--object-size ] [--image-feature ] [--image-shared] [--stripe-unit ] [--stripe-count ] [--data-pool ] @@ -249,6 +250,7 @@ --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 diff --git a/src/tools/rbd/action/Clone.cc b/src/tools/rbd/action/Clone.cc index 6406c957e498..874024f482bd 100644 --- a/src/tools/rbd/action/Clone.cc +++ b/src/tools/rbd/action/Clone.cc @@ -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 #include @@ -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(); + } + 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;