-#!/bin/sh -ex
+#!/usr/bin/env bash
+set -ex
+
+. $(dirname $0)/../../standalone/ceph-helpers.sh
export RBD_FORCE_ALLOW_V1=1
rbd namespace remove rbd test2
}
+get_migration_state() {
+ local image=$1
+
+ rbd --format xml status $image |
+ $XMLSTARLET sel -t -v '//status/migration/state'
+}
+
+test_migration() {
+ echo "testing migration..."
+ remove_images
+ rados mkpool rbd2
+ rbd pool init rbd2
+
+ # Convert to new format
+ rbd create --image-format 1 -s 128M test1
+ rbd info test1 | grep 'format: 1'
+ rbd migration prepare test1 --image-format 2
+ test "$(get_migration_state test1)" = prepared
+ rbd info test1 | grep 'format: 2'
+ rbd rm test1 && exit 1 || true
+ rbd migration execute test1
+ test "$(get_migration_state test1)" = executed
+ rbd migration commit test1
+ get_migration_state test1 && exit 1 || true
+
+ # Enable layering (and some other features)
+ rbd info test1 | grep 'features: .*layering' && exit 1 || true
+ rbd migration prepare test1 --image-feature \
+ layering,exclusive-lock,object-map,fast-diff,deep-flatten
+ rbd info test1 | grep 'features: .*layering'
+ rbd migration execute test1
+ rbd migration commit test1
+
+ # Migration to other pool
+ rbd migration prepare test1 rbd2/test1
+ test "$(get_migration_state rbd2/test1)" = prepared
+ rbd ls | wc -l | grep '^0$'
+ rbd -p rbd2 ls | grep test1
+ rbd migration execute test1
+ test "$(get_migration_state rbd2/test1)" = executed
+ rbd rm rbd2/test1 && exit 1 || true
+ rbd migration commit test1
+
+ # Enable data pool
+ rbd create -s 128M test1
+ rbd migration prepare test1 --data-pool rbd2
+ rbd info test1 | grep 'data_pool: rbd2'
+ rbd migration execute test1
+ rbd migration commit test1
+
+ for format in 1 2; do
+ # Abort migration after successful prepare
+ rbd create -s 128M --image-format ${format} test2
+ rbd migration prepare test2 --data-pool rbd2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd migration abort test2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd rm test2
+
+ # Abort migration after successful execute
+ rbd create -s 128M --image-format ${format} test2
+ rbd migration prepare test2 --data-pool rbd2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd migration execute test2
+ rbd migration abort test2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd rm test2
+
+ # Migration is automatically aborted if prepare failed
+ rbd create -s 128M --image-format ${format} test2
+ rbd migration prepare test2 --data-pool INVALID_DATA_POOL && exit 1 || true
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd rm test2
+
+ # Abort migration to other pool
+ rbd create -s 128M --image-format ${format} test2
+ rbd migration prepare test2 rbd2/test2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 rbd2/test2
+ rbd migration abort test2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd rm test2
+
+ # The same but abort using destination image
+ rbd create -s 128M --image-format ${format} test2
+ rbd migration prepare test2 rbd2/test2
+ rbd migration abort rbd2/test2
+ rbd bench --io-type write --io-size 1024 --io-total 1024 test2
+ rbd rm test2
+ done
+
+ remove_images
+ rados rmpool rbd2 rbd2 --yes-i-really-really-mean-it
+}
+
test_pool_image_args
test_rename
test_ls
test_remove
+test_migration
RBD_CREATE_ARGS=""
test_others
test_locking
lock list (lock ls) Show locks held on an image.
lock remove (lock rm) Release a lock on an image.
merge-diff Merge two diff exports together.
+ migration abort Cancel interrupted image migration.
+ migration commit Commit image migration.
+ migration execute Execute image migration.
+ migration prepare Prepare image migration.
mirror image demote Demote an image to non-primary for RBD
mirroring.
mirror image disable Disable RBD mirroring for an image.
--path arg path to merged diff (or '-' for stdout)
--no-progress disable progress output
+ rbd help migration abort
+ usage: rbd migration abort [--pool <pool>] [--namespace <namespace>]
+ [--image <image>] [--no-progress]
+ <image-spec>
+
+ Cancel interrupted image migration.
+
+ Positional arguments
+ <image-spec> image specification
+ (example: [<pool-name>/[<namespace-name>/]]<image-name>)
+
+ Optional arguments
+ -p [ --pool ] arg pool name
+ --namespace arg namespace name
+ --image arg image name
+ --no-progress disable progress output
+
+ rbd help migration commit
+ usage: rbd migration commit [--pool <pool>] [--namespace <namespace>]
+ [--image <image>] [--no-progress]
+ <image-spec>
+
+ Commit image migration.
+
+ Positional arguments
+ <image-spec> image specification
+ (example: [<pool-name>/[<namespace-name>/]]<image-name>)
+
+ Optional arguments
+ -p [ --pool ] arg pool name
+ --namespace arg namespace name
+ --image arg image name
+ --no-progress disable progress output
+
+ rbd help migration execute
+ usage: rbd migration execute [--pool <pool>] [--namespace <namespace>]
+ [--image <image>] [--no-progress]
+ <image-spec>
+
+ Execute image migration.
+
+ Positional arguments
+ <image-spec> image specification
+ (example: [<pool-name>/[<namespace-name>/]]<image-name>)
+
+ Optional arguments
+ -p [ --pool ] arg pool name
+ --namespace arg namespace name
+ --image arg image name
+ --no-progress disable progress output
+
+ rbd help migration prepare
+ usage: rbd migration prepare [--pool <pool>] [--namespace <namespace>]
+ [--image <image>] [--dest-pool <dest-pool>]
+ [--dest-namespace <dest-namespace>]
+ [--dest <dest>] [--image-format <image-format>]
+ [--new-format] [--order <order>]
+ [--object-size <object-size>]
+ [--image-feature <image-feature>]
+ [--image-shared] [--stripe-unit <stripe-unit>]
+ [--stripe-count <stripe-count>]
+ [--data-pool <data-pool>]
+ [--journal-splay-width <journal-splay-width>]
+ [--journal-object-size <journal-object-size>]
+ [--journal-pool <journal-pool>] [--flatten]
+ <source-image-spec> <dest-image-spec>
+
+ Prepare image migration.
+
+ Positional arguments
+ <source-image-spec> source image specification
+ (example:
+ [<pool-name>/[<namespace-name>/]]<image-name>)
+ <dest-image-spec> destination image specification
+ (example:
+ [<pool-name>/[<namespace-name>/]]<image-name>)
+
+ Optional arguments
+ -p [ --pool ] arg source pool name
+ --namespace arg source namespace name
+ --image arg source image name
+ --dest-pool arg destination pool name
+ --dest-namespace arg destination namespace name
+ --dest arg destination image name
+ --image-format arg image format [1 (deprecated) or 2]
+ --new-format use image format 2
+ (deprecated)
+ --order arg object order [12 <= order <= 25]
+ --object-size arg object size in B/K/M [4K <= object size <= 32M]
+ --image-feature arg image features
+ [layering(+), exclusive-lock(+*), object-map(+*),
+ deep-flatten(+-), journaling(*)]
+ --image-shared shared image
+ --stripe-unit arg stripe unit in B/K/M
+ --stripe-count arg stripe count
+ --data-pool arg data pool
+ --journal-splay-width arg number of active journal objects
+ --journal-object-size arg size of journal objects
+ --journal-pool arg pool for journal objects
+ --flatten fill clone with parent data (make it independent)
+
+ Image Features:
+ (*) supports enabling/disabling on existing images
+ (-) supports disabling-only on existing images
+ (+) enabled by default for new images if features not specified
+
rbd help mirror image demote
usage: rbd mirror image demote [--pool <pool>] [--namespace <namespace>]
[--image <image>]
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "common/errno.h"
+
+#include "tools/rbd/ArgumentTypes.h"
+#include "tools/rbd/Shell.h"
+#include "tools/rbd/Utils.h"
+
+#include <iostream>
+#include <boost/program_options.hpp>
+
+namespace rbd {
+namespace action {
+namespace migration {
+
+namespace at = argument_types;
+namespace po = boost::program_options;
+
+static int do_prepare(librados::IoCtx& io_ctx, const std::string &image_name,
+ librados::IoCtx& dest_io_ctx,
+ const std::string &dest_image_name,
+ librbd::ImageOptions& opts) {
+ int r = librbd::RBD().migration_prepare(io_ctx, image_name.c_str(),
+ dest_io_ctx, dest_image_name.c_str(),
+ opts);
+ if (r < 0) {
+ std::cerr << "rbd: preparing migration failed: " << cpp_strerror(r)
+ << std::endl;
+ return r;
+ }
+ return 0;
+}
+
+static int do_execute(librados::IoCtx& io_ctx, const std::string &image_name,
+ bool no_progress) {
+ utils::ProgressContext pc("Image migration", no_progress);
+ int r = librbd::RBD().migration_execute_with_progress(io_ctx,
+ image_name.c_str(), pc);
+ if (r < 0) {
+ pc.fail();
+ std::cerr << "rbd: migration failed: " << cpp_strerror(r) << std::endl;
+ return r;
+ }
+ pc.finish();
+ return 0;
+}
+
+static int do_abort(librados::IoCtx& io_ctx, const std::string &image_name,
+ bool no_progress) {
+ utils::ProgressContext pc("Abort image migration", no_progress);
+ int r = librbd::RBD().migration_abort_with_progress(io_ctx,
+ image_name.c_str(), pc);
+ if (r < 0) {
+ pc.fail();
+ std::cerr << "rbd: aborting migration failed: " << cpp_strerror(r)
+ << std::endl;
+ return r;
+ }
+ pc.finish();
+ return 0;
+}
+
+static int do_commit(librados::IoCtx& io_ctx, const std::string &image_name,
+ bool no_progress) {
+ utils::ProgressContext pc("Commit image migration", no_progress);
+ int r = librbd::RBD().migration_commit_with_progress(io_ctx,
+ image_name.c_str(), pc);
+ if (r < 0) {
+ pc.fail();
+ std::cerr << "rbd: committing migration failed: " << cpp_strerror(r)
+ << std::endl;
+ return r;
+ }
+ pc.finish();
+ return 0;
+}
+
+void get_prepare_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_SOURCE);
+ at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST);
+ at::add_create_image_options(options, true);
+ at::add_flatten_option(options);
+}
+
+int execute_prepare(const po::variables_map &vm,
+ const std::vector<std::string> &ceph_global_init_args) {
+ size_t arg_index = 0;
+ std::string pool_name;
+ std::string namespace_name;
+ std::string image_name;
+ int r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_SOURCE, &arg_index, &pool_name, &namespace_name,
+ &image_name, nullptr, true, utils::SNAPSHOT_PRESENCE_NONE,
+ utils::SPEC_VALIDATION_NONE);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::Rados rados;
+ librados::IoCtx io_ctx;
+ r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
+ if (r < 0) {
+ return r;
+ }
+ io_ctx.set_osdmap_full_try();
+
+ std::string dest_pool_name;
+ std::string dest_namespace_name;
+ std::string dest_image_name;
+ r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &dest_pool_name,
+ &dest_namespace_name, &dest_image_name, nullptr, false,
+ utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
+ if (r < 0) {
+ return r;
+ }
+
+ librbd::ImageOptions opts;
+ r = utils::get_image_options(vm, true, &opts);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::IoCtx dest_io_ctx;
+ if (!dest_pool_name.empty()) {
+ r = utils::init_io_ctx(rados, dest_pool_name, dest_namespace_name,
+ &dest_io_ctx);
+ if (r < 0) {
+ return r;
+ }
+ }
+
+ r = do_prepare(io_ctx, image_name, dest_pool_name.empty() ? io_ctx :
+ dest_io_ctx, dest_image_name, opts);
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
+
+void get_execute_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_no_progress_option(options);
+}
+
+int execute_execute(const po::variables_map &vm,
+ const std::vector<std::string> &ceph_global_init_args) {
+ size_t arg_index = 0;
+ std::string pool_name;
+ std::string namespace_name;
+ std::string image_name;
+ int r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+ &image_name, nullptr, true, utils::SNAPSHOT_PRESENCE_NONE,
+ utils::SPEC_VALIDATION_NONE);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::Rados rados;
+ librados::IoCtx io_ctx;
+ r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
+ if (r < 0) {
+ return r;
+ }
+ io_ctx.set_osdmap_full_try();
+
+ r = do_execute(io_ctx, image_name, vm[at::NO_PROGRESS].as<bool>());
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
+
+void get_abort_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_no_progress_option(options);
+}
+
+int execute_abort(const po::variables_map &vm,
+ const std::vector<std::string> &ceph_global_init_args) {
+ size_t arg_index = 0;
+ std::string pool_name;
+ std::string namespace_name;
+ std::string image_name;
+ int r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+ &image_name, nullptr, true, utils::SNAPSHOT_PRESENCE_NONE,
+ utils::SPEC_VALIDATION_NONE);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::Rados rados;
+ librados::IoCtx io_ctx;
+ r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
+ if (r < 0) {
+ return r;
+ }
+ io_ctx.set_osdmap_full_try();
+
+ r = do_abort(io_ctx, image_name, vm[at::NO_PROGRESS].as<bool>());
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
+
+void get_commit_arguments(po::options_description *positional,
+ po::options_description *options) {
+ at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
+ at::add_no_progress_option(options);
+}
+
+int execute_commit(const po::variables_map &vm,
+ const std::vector<std::string> &ceph_global_init_args) {
+ size_t arg_index = 0;
+ std::string pool_name;
+ std::string namespace_name;
+ std::string image_name;
+ int r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
+ &image_name, nullptr, true, utils::SNAPSHOT_PRESENCE_NONE,
+ utils::SPEC_VALIDATION_NONE);
+ if (r < 0) {
+ return r;
+ }
+
+ librados::Rados rados;
+ librados::IoCtx io_ctx;
+ r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
+ if (r < 0) {
+ return r;
+ }
+ io_ctx.set_osdmap_full_try();
+
+ r = do_commit(io_ctx, image_name, vm[at::NO_PROGRESS].as<bool>());
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
+
+Shell::Action action_prepare(
+ {"migration", "prepare"}, {}, "Prepare image migration.",
+ at::get_long_features_help(), &get_prepare_arguments, &execute_prepare);
+
+Shell::Action action_execute(
+ {"migration", "execute"}, {}, "Execute image migration.", "",
+ &get_execute_arguments, &execute_execute);
+
+Shell::Action action_abort(
+ {"migration", "abort"}, {}, "Cancel interrupted image migration.", "",
+ &get_abort_arguments, &execute_abort);
+
+Shell::Action action_commit(
+ {"migration", "commit"}, {}, "Commit image migration.", "",
+ &get_commit_arguments, &execute_commit);
+
+} // namespace migration
+} // namespace action
+} // namespace rbd