From c18e15a6376e493ac3ce3df641698c22f07ec2c6 Mon Sep 17 00:00:00 2001 From: Jason Dillaman Date: Mon, 16 Sep 2019 13:21:40 -0400 Subject: [PATCH] rbd: new 'mirror pool peer bootstrap create/import' commands These two commands simplify the process of creating users and exchanging keys between two clusters. Fixes: https://tracker.ceph.com/issues/41653 Signed-off-by: Jason Dillaman --- src/test/cli/rbd/help.t | 40 +++++++ src/tools/rbd/action/MirrorPool.cc | 173 +++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index be724d49078..803a61d782a 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -96,6 +96,10 @@ mirror pool info Show information about the pool mirroring configuration. mirror pool peer add Add a mirroring peer to a pool. + mirror pool peer bootstrap create Create a peer bootstrap token to import + in a remote cluster + mirror pool peer bootstrap import Import a peer bootstrap token created + from a remote cluster mirror pool peer remove Remove a mirroring peer from a pool. mirror pool peer set Update mirroring peer settings. mirror pool promote Promote all non-primary images in the @@ -1686,6 +1690,42 @@ --remote-mon-host arg remote mon host(s) --remote-key-file arg path to file containing remote key + rbd help mirror pool peer bootstrap create + usage: rbd mirror pool peer bootstrap create + [--pool ] + [--site-name ] + + + Create a peer bootstrap token to import in a remote cluster + + Positional arguments + pool name + + Optional arguments + -p [ --pool ] arg pool name + --site-name arg local site name + + rbd help mirror pool peer bootstrap import + usage: rbd mirror pool peer bootstrap import + [--pool ] + [--site-name ] + [--token-path ] + [--direction ] + + + Import a peer bootstrap token created from a remote cluster + + Positional arguments + pool name + bootstrap token file (or '-' for stdin) + + Optional arguments + -p [ --pool ] arg pool name + --site-name arg local site name + --token-path arg bootstrap token file (or '-' for stdin) + --direction arg mirroring direction (rx-only, rx-tx) + [default: rx-tx] + rbd help mirror pool peer remove usage: rbd mirror pool peer remove [--pool ] diff --git a/src/tools/rbd/action/MirrorPool.cc b/src/tools/rbd/action/MirrorPool.cc index 45a510fd405..941d1e57572 100644 --- a/src/tools/rbd/action/MirrorPool.cc +++ b/src/tools/rbd/action/MirrorPool.cc @@ -63,6 +63,22 @@ int set_site_name(librados::Rados& rados, const std::string& site_name) { return 0; } +struct MirrorPeerDirection {}; + +void validate(boost::any& v, const std::vector& values, + MirrorPeerDirection *target_type, int) { + po::validators::check_first_occurrence(v); + const std::string &s = po::validators::get_single_string(values); + + if (s == "rx-only") { + v = boost::any(RBD_MIRROR_PEER_DIRECTION_RX); + } else if (s == "rx-tx") { + v = boost::any(RBD_MIRROR_PEER_DIRECTION_RX_TX); + } else { + throw po::validation_error(po::validation_error::invalid_option_value); + } +} + int validate_mirroring_enabled(librados::IoCtx& io_ctx) { librbd::RBD rbd; rbd_mirror_mode_t mirror_mode; @@ -674,6 +690,154 @@ private: } // anonymous namespace +void get_peer_bootstrap_create_arguments(po::options_description *positional, + po::options_description *options) { + at::add_pool_options(positional, options, false); + options->add_options() + (SITE_NAME.c_str(), po::value(), "local site name"); +} + +int execute_peer_bootstrap_create( + const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::string pool_name; + size_t arg_index = 0; + int r = utils::get_pool_and_namespace_names(vm, true, true, &pool_name, + nullptr, &arg_index); + if (r < 0) { + return r; + } + + librados::Rados rados; + librados::IoCtx io_ctx; + r = utils::init(pool_name, "", &rados, &io_ctx); + if (r < 0) { + return r; + } + + r = validate_mirroring_enabled(io_ctx); + if (r < 0) { + return r; + } + + if (vm.count(SITE_NAME)) { + r = set_site_name(rados, vm[SITE_NAME].as()); + if (r < 0) { + return r; + } + } + + librbd::RBD rbd; + std::string token; + r = rbd.mirror_peer_bootstrap_create(io_ctx, &token); + if (r == -EEXIST) { + std::cerr << "rbd: mismatch with pre-existing RBD mirroring peer user caps" + << std::endl; + } else if (r < 0) { + std::cerr << "rbd: failed to create mirroring bootstrap token: " + << cpp_strerror(r) << std::endl; + return r; + } + + std::cout << token << std::endl; + return 0; +} + +void get_peer_bootstrap_import_arguments(po::options_description *positional, + po::options_description *options) { + at::add_pool_options(positional, options, false); + options->add_options() + (SITE_NAME.c_str(), po::value(), "local site name"); + positional->add_options() + ("token-path", po::value(), + "bootstrap token file (or '-' for stdin)"); + options->add_options() + ("token-path", po::value(), + "bootstrap token file (or '-' for stdin)") + ("direction", po::value(), + "mirroring direction (rx-only, rx-tx)\n" + "[default: rx-tx]"); +} + +int execute_peer_bootstrap_import( + const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::string pool_name; + size_t arg_index = 0; + int r = utils::get_pool_and_namespace_names(vm, true, true, &pool_name, + nullptr, &arg_index); + if (r < 0) { + return r; + } + + std::string token_path; + if (vm.count("token-path")) { + token_path = vm["token-path"].as(); + } else { + token_path = utils::get_positional_argument(vm, arg_index++); + } + + if (token_path.empty()) { + std::cerr << "rbd: token path was not specified" << std::endl; + return -EINVAL; + } + + rbd_mirror_peer_direction_t mirror_peer_direction = + RBD_MIRROR_PEER_DIRECTION_RX_TX; + if (vm.count("direction")) { + mirror_peer_direction = vm["direction"].as(); + } + + int fd = STDIN_FILENO; + if (token_path != "-") { + fd = open(token_path.c_str(), O_RDONLY); + if (fd < 0) { + r = -errno; + std::cerr << "rbd: error opening " << token_path << std::endl; + return r; + } + } + + char token[1024]; + memset(token, 0, sizeof(token)); + r = safe_read(fd, token, sizeof(token) - 1); + if (fd != STDIN_FILENO) { + VOID_TEMP_FAILURE_RETRY(close(fd)); + } + + if (r < 0) { + std::cerr << "rbd: error reading token file: " << cpp_strerror(r) + << std::endl; + return r; + } + + librados::Rados rados; + librados::IoCtx io_ctx; + r = utils::init(pool_name, "", &rados, &io_ctx); + if (r < 0) { + return r; + } + + if (vm.count(SITE_NAME)) { + r = set_site_name(rados, vm[SITE_NAME].as()); + if (r < 0) { + return r; + } + } + + librbd::RBD rbd; + r = rbd.mirror_peer_bootstrap_import(io_ctx, mirror_peer_direction, token); + if (r == -ENOSYS) { + std::cerr << "rbd: mirroring is not enabled on remote peer" << std::endl; + return r; + } else if (r < 0) { + std::cerr << "rbd: failed to import peer bootstrap token" << std::endl; + return r; + } + + return 0; +} + void get_peer_add_arguments(po::options_description *positional, po::options_description *options) { at::add_pool_options(positional, options, false); @@ -1320,6 +1484,15 @@ int execute_demote(const po::variables_map &vm, return r; } +Shell::Action action_bootstrap_create( + {"mirror", "pool", "peer", "bootstrap", "create"}, {}, + "Create a peer bootstrap token to import in a remote cluster", "", + &get_peer_bootstrap_create_arguments, &execute_peer_bootstrap_create); +Shell::Action action_bootstreap_import( + {"mirror", "pool", "peer", "bootstrap", "import"}, {}, + "Import a peer bootstrap token created from a remote cluster", "", + &get_peer_bootstrap_import_arguments, &execute_peer_bootstrap_import); + Shell::Action action_add( {"mirror", "pool", "peer", "add"}, {}, "Add a mirroring peer to a pool.", "", -- 2.39.5