From: Mykola Golub Date: Sun, 23 Feb 2020 16:49:38 +0000 (+0000) Subject: rbd: generalize schedule reusable code X-Git-Tag: v15.1.1~214^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e24ba188a72f79f1335e334903e12daa5a61f96c;p=ceph.git rbd: generalize schedule reusable code Signed-off-by: Mykola Golub --- diff --git a/src/tools/rbd/CMakeLists.txt b/src/tools/rbd/CMakeLists.txt index bcf3cff1db3b..2abf9341363e 100644 --- a/src/tools/rbd/CMakeLists.txt +++ b/src/tools/rbd/CMakeLists.txt @@ -7,6 +7,7 @@ set(rbd_srcs IndentStream.cc MirrorDaemonServiceInfo.cc OptionPrinter.cc + Schedule.cc Shell.cc Utils.cc action/Bench.cc diff --git a/src/tools/rbd/Schedule.cc b/src/tools/rbd/Schedule.cc new file mode 100644 index 000000000000..596408199ee2 --- /dev/null +++ b/src/tools/rbd/Schedule.cc @@ -0,0 +1,349 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/Formatter.h" +#include "common/TextTable.h" +#include "common/ceph_json.h" +#include "tools/rbd/ArgumentTypes.h" +#include "tools/rbd/Schedule.h" +#include "tools/rbd/Utils.h" + +#include +#include + +namespace rbd { + +namespace at = argument_types; +namespace po = boost::program_options; + +namespace { + +int parse_schedule_name(const std::string &name, bool allow_images, + std::string *pool_name, std::string *namespace_name, + std::string *image_name) { + // parse names like: + // '', 'rbd/', 'rbd/ns/', 'rbd/image', 'rbd/ns/image' + std::regex pattern("^(?:([^/]+)/(?:(?:([^/]+)/|)(?:([^/@]+))?)?)?$"); + std::smatch match; + if (!std::regex_match(name, match, pattern)) { + return -EINVAL; + } + + if (match[1].matched) { + *pool_name = match[1]; + } else { + *pool_name = "-"; + } + + if (match[2].matched) { + *namespace_name = match[2]; + } else if (match[3].matched) { + *namespace_name = ""; + } else { + *namespace_name = "-"; + } + + if (match[3].matched) { + if (!allow_images) { + return -EINVAL; + } + *image_name = match[3]; + } else { + *image_name = "-"; + } + + return 0; +} + +} // anonymous namespace + +void add_level_spec_options(po::options_description *options, + bool allow_image) { + at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); + at::add_namespace_option(options, at::ARGUMENT_MODIFIER_NONE); + if (allow_image) { + at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); + } +} + +int get_level_spec_args(const po::variables_map &vm, + std::map *args) { + if (vm.count(at::IMAGE_NAME)) { + std::string pool_name; + std::string namespace_name; + std::string image_name; + + int r = utils::extract_spec(vm[at::IMAGE_NAME].as(), + &pool_name, &namespace_name, &image_name, + nullptr, utils::SPEC_VALIDATION_FULL); + if (r < 0) { + return r; + } + + if (!pool_name.empty()) { + if (vm.count(at::POOL_NAME)) { + std::cerr << "rbd: pool is specified both via pool and image options" + << std::endl; + return -EINVAL; + } + if (vm.count(at::NAMESPACE_NAME)) { + std::cerr << "rbd: namespace is specified both via namespace and image" + << " options" << std::endl; + return -EINVAL; + } + } + + if (vm.count(at::POOL_NAME)) { + pool_name = vm[at::POOL_NAME].as(); + } else if (pool_name.empty()) { + pool_name = utils::get_default_pool_name(); + } + + if (vm.count(at::NAMESPACE_NAME)) { + namespace_name = vm[at::NAMESPACE_NAME].as(); + } + + if (namespace_name.empty()) { + (*args)["level_spec"] = pool_name + "/" + image_name; + } else { + (*args)["level_spec"] = pool_name + "/" + namespace_name + "/" + + image_name; + } + return 0; + } + + if (vm.count(at::NAMESPACE_NAME)) { + std::string pool_name; + std::string namespace_name; + + if (vm.count(at::POOL_NAME)) { + pool_name = vm[at::POOL_NAME].as(); + } else { + pool_name = utils::get_default_pool_name(); + } + + namespace_name = vm[at::NAMESPACE_NAME].as(); + + (*args)["level_spec"] = pool_name + "/" + namespace_name + "/"; + + return 0; + } + + if (vm.count(at::POOL_NAME)) { + std::string pool_name = vm[at::POOL_NAME].as(); + + (*args)["level_spec"] = pool_name + "/"; + + return 0; + } + + (*args)["level_spec"] = ""; + + return 0; +} + +void add_schedule_options(po::options_description *positional) { + positional->add_options() + ("interval", "schedule interval"); + positional->add_options() + ("start-time", "schedule start time"); +} + +int get_schedule_args(const po::variables_map &vm, bool mandatory, + std::map *args) { + size_t arg_index = 0; + + std::string interval = utils::get_positional_argument(vm, arg_index++); + if (interval.empty()) { + if (mandatory) { + std::cerr << "rbd: missing 'interval' argument" << std::endl; + return -EINVAL; + } + return 0; + } + (*args)["interval"] = interval; + + std::string start_time = utils::get_positional_argument(vm, arg_index++); + if (!start_time.empty()) { + (*args)["start_time"] = start_time; + } + + return 0; +} + +int Schedule::parse(json_spirit::mValue &schedule_val) { + if (schedule_val.type() != json_spirit::array_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "schedule is not array" << std::endl; + return -EBADMSG; + } + + try { + for (auto &item_val : schedule_val.get_array()) { + if (item_val.type() != json_spirit::obj_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "schedule item is not object" << std::endl; + return -EBADMSG; + } + + auto &item = item_val.get_obj(); + + if (item["interval"].type() != json_spirit::str_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "interval is not string" << std::endl; + return -EBADMSG; + } + auto interval = item["interval"].get_str(); + + std::string start_time; + if (item["start_time"].type() == json_spirit::str_type) { + start_time = item["start_time"].get_str(); + } + + items.push_back({interval, start_time}); + } + + } catch (std::runtime_error &) { + std::cerr << "rbd: invalid schedule JSON received" << std::endl; + return -EBADMSG; + } + + return 0; +} + +void Schedule::dump(ceph::Formatter *f) { + f->open_array_section("items"); + for (auto &item : items) { + f->open_object_section("item"); + f->dump_string("interval", item.first); + f->dump_string("start_time", item.second); + f->close_section(); // item + } + f->close_section(); // items +} + +std::ostream& operator<<(std::ostream& os, Schedule &s) { + std::string delimiter; + for (auto &item : s.items) { + os << delimiter << "every " << item.first; + if (!item.second.empty()) { + os << " starting at " << item.second; + } + delimiter = ", "; + } + return os; +} + +int ScheduleList::parse(const std::string &list) { + json_spirit::mValue json_root; + if (!json_spirit::read(list, json_root)) { + std::cerr << "rbd: invalid schedule list JSON received" << std::endl; + return -EBADMSG; + } + + try { + for (auto &[id, schedule_val] : json_root.get_obj()) { + if (schedule_val.type() != json_spirit::obj_type) { + std::cerr << "rbd: unexpected schedule list JSON received: " + << "schedule_val is not object" << std::endl; + return -EBADMSG; + } + auto &schedule = schedule_val.get_obj(); + if (schedule["name"].type() != json_spirit::str_type) { + std::cerr << "rbd: unexpected schedule list JSON received: " + << "schedule name is not string" << std::endl; + return -EBADMSG; + } + auto name = schedule["name"].get_str(); + + if (schedule["schedule"].type() != json_spirit::array_type) { + std::cerr << "rbd: unexpected schedule list JSON received: " + << "schedule is not array" << std::endl; + return -EBADMSG; + } + + Schedule s; + int r = s.parse(schedule["schedule"]); + if (r < 0) { + return r; + } + schedules[name] = s; + } + } catch (std::runtime_error &) { + std::cerr << "rbd: invalid schedule list JSON received" << std::endl; + return -EBADMSG; + } + + return 0; +} + +Schedule *ScheduleList::find(const std::string &name) { + auto it = schedules.find(name); + if (it == schedules.end()) { + return nullptr; + } + + return &it->second; +} + +void ScheduleList::dump(ceph::Formatter *f) { + f->open_array_section("schedules"); + for (auto &[name, s] : schedules) { + std::string pool_name; + std::string namespace_name; + std::string image_name; + + int r = parse_schedule_name(name, allow_images, &pool_name, &namespace_name, + &image_name); + if (r < 0) { + continue; + } + + f->open_object_section("schedule"); + f->dump_string("pool", pool_name); + f->dump_string("namespace", namespace_name); + if (allow_images) { + f->dump_string("image", image_name); + } + s.dump(f); + f->close_section(); + } + f->close_section(); +} + +std::ostream& operator<<(std::ostream& os, ScheduleList &l) { + TextTable tbl; + tbl.define_column("POOL", TextTable::LEFT, TextTable::LEFT); + tbl.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT); + if (l.allow_images) { + tbl.define_column("IMAGE", TextTable::LEFT, TextTable::LEFT); + } + tbl.define_column("SCHEDULE", TextTable::LEFT, TextTable::LEFT); + + for (auto &[name, s] : l.schedules) { + std::string pool_name; + std::string namespace_name; + std::string image_name; + + int r = parse_schedule_name(name, l.allow_images, &pool_name, + &namespace_name, &image_name); + if (r < 0) { + continue; + } + + std::stringstream ss; + ss << s; + + tbl << pool_name << namespace_name; + if (l.allow_images) { + tbl << image_name; + } + tbl << ss.str() << TextTable::endrow; + } + + os << tbl; + return os; +} + +} // namespace rbd + diff --git a/src/tools/rbd/Schedule.h b/src/tools/rbd/Schedule.h new file mode 100644 index 000000000000..c92b9357a3d5 --- /dev/null +++ b/src/tools/rbd/Schedule.h @@ -0,0 +1,65 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_RBD_SCHEDULE_H +#define CEPH_RBD_SCHEDULE_H + +#include "json_spirit/json_spirit.h" + +#include +#include +#include +#include +#include + +namespace ceph { class Formatter; } + +namespace rbd { + +void add_level_spec_options( + boost::program_options::options_description *options, bool allow_image=true); +int get_level_spec_args(const boost::program_options::variables_map &vm, + std::map *args); +void add_schedule_options( + boost::program_options::options_description *positional); +int get_schedule_args(const boost::program_options::variables_map &vm, + bool mandatory, std::map *args); + +class Schedule { +public: + Schedule() { + } + + int parse(json_spirit::mValue &schedule_val); + void dump(ceph::Formatter *f); + + friend std::ostream& operator<<(std::ostream& os, Schedule &s); + +private: + std::string name; + std::list> items; +}; + +std::ostream& operator<<(std::ostream& os, Schedule &s); + +class ScheduleList { +public: + ScheduleList(bool allow_images=true) : allow_images(allow_images) { + } + + int parse(const std::string &list); + Schedule *find(const std::string &name); + void dump(ceph::Formatter *f); + + friend std::ostream& operator<<(std::ostream& os, ScheduleList &l); + +private: + bool allow_images; + std::map schedules; +}; + +std::ostream& operator<<(std::ostream& os, ScheduleList &l); + +} // namespace rbd + +#endif // CEPH_RBD_SCHEDULE_H diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index ea5ce46b8487..520b654714b8 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -10,6 +10,7 @@ #include "include/rbd/features.h" #include "common/config.h" #include "common/errno.h" +#include "common/escape.h" #include "common/safe_io.h" #include "global/global_context.h" #include @@ -23,6 +24,24 @@ namespace utils { namespace at = argument_types; namespace po = boost::program_options; +namespace { + +static std::string mgr_command_args_to_str( + const std::map &args) { + std::string out = ""; + + std::string delimiter; + for (auto &it : args) { + out += delimiter + "\"" + it.first + "\": \"" + + stringify(json_stream_escaper(it.second)) + "\""; + delimiter = ",\n"; + } + + return out; +} + +} // anonymous namespace + int ProgressContext::update_progress(uint64_t offset, uint64_t total) { if (progress) { int pc = total ? (offset * 100ull / total) : 0; @@ -1017,5 +1036,33 @@ void populate_unknown_mirror_image_site_statuses( std::swap(global_status->site_statuses, site_statuses); } +int mgr_command(librados::Rados& rados, const std::string& cmd, + const std::map &args, + std::ostream *out_os, std::ostream *err_os) { + std::string command = R"( + { + "prefix": ")" + cmd + R"(", )" + mgr_command_args_to_str(args) + R"( + })"; + + bufferlist in_bl; + bufferlist out_bl; + std::string outs; + int r = rados.mgr_command(command, in_bl, &out_bl, &outs); + if (r < 0) { + (*err_os) << "rbd: " << cmd << " failed: " << cpp_strerror(r); + if (!outs.empty()) { + (*err_os) << ": " << outs; + } + (*err_os) << std::endl; + return r; + } + + if (out_bl.length() != 0) { + (*out_os) << out_bl.c_str(); + } + + return 0; +} + } // namespace utils } // namespace rbd diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index bc9786b4ff21..14e46d5c4788 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -8,6 +8,7 @@ #include "include/rados/librados.hpp" #include "include/rbd/librbd.hpp" #include "tools/rbd/ArgumentTypes.h" +#include #include #include @@ -219,6 +220,10 @@ void populate_unknown_mirror_image_site_statuses( const std::vector& mirror_peers, librbd::mirror_image_global_status_t* global_status); +int mgr_command(librados::Rados& rados, const std::string& cmd, + const std::map &args, + std::ostream *out_os, std::ostream *err_os); + } // namespace utils } // namespace rbd diff --git a/src/tools/rbd/action/MirrorSnapshotSchedule.cc b/src/tools/rbd/action/MirrorSnapshotSchedule.cc index 79e77f906d4e..f8dbb5ec6b2d 100644 --- a/src/tools/rbd/action/MirrorSnapshotSchedule.cc +++ b/src/tools/rbd/action/MirrorSnapshotSchedule.cc @@ -2,12 +2,12 @@ // vim: ts=8 sw=2 smarttab #include "tools/rbd/ArgumentTypes.h" +#include "tools/rbd/Schedule.h" #include "tools/rbd/Shell.h" #include "tools/rbd/Utils.h" #include "common/ceph_context.h" #include "common/ceph_json.h" #include "common/errno.h" -#include "common/escape.h" #include "common/Formatter.h" #include "common/TextTable.h" #include "global/global_context.h" @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -31,252 +30,6 @@ namespace po = boost::program_options; namespace { -struct Args { - std::map args; - - Args() { - } - Args(const std::map &args) - : args(args) { - } - - std::string str() const { - std::string out = ""; - - std::string delimiter; - for (auto &it : args) { - out += delimiter + "\"" + it.first + "\": \"" + - stringify(json_stream_escaper(it.second)) + "\""; - delimiter = ",\n"; - } - - return out; - } -}; - -class Schedule { -public: - Schedule() { - } - - int parse(json_spirit::mValue &schedule_val) { - if (schedule_val.type() != json_spirit::array_type) { - std::cerr << "rbd: unexpected schedule JSON received: " - << "schedule is not array" << std::endl; - return -EBADMSG; - } - - try { - for (auto &item_val : schedule_val.get_array()) { - if (item_val.type() != json_spirit::obj_type) { - std::cerr << "rbd: unexpected schedule JSON received: " - << "schedule item is not object" << std::endl; - return -EBADMSG; - } - - auto &item = item_val.get_obj(); - - if (item["interval"].type() != json_spirit::str_type) { - std::cerr << "rbd: unexpected schedule JSON received: " - << "interval is not string" << std::endl; - return -EBADMSG; - } - auto interval = item["interval"].get_str(); - - std::string start_time; - if (item["start_time"].type() == json_spirit::str_type) { - start_time = item["start_time"].get_str(); - } - - items.push_back({interval, start_time}); - } - - } catch (std::runtime_error &) { - std::cerr << "rbd: invalid schedule JSON received" << std::endl; - return -EBADMSG; - } - - return 0; - } - - void dump(Formatter *f) { - f->open_array_section("items"); - for (auto &item : items) { - f->open_object_section("item"); - f->dump_string("interval", item.first); - f->dump_string("start_time", item.second); - f->close_section(); // item - } - f->close_section(); // items - } - - friend std::ostream& operator<<(std::ostream& os, Schedule &s); - -private: - std::string name; - std::list> items; -}; - -std::ostream& operator<<(std::ostream& os, Schedule &s) { - std::string delimiter; - for (auto &item : s.items) { - os << delimiter << "every " << item.first; - if (!item.second.empty()) { - os << " starting at " << item.second; - } - delimiter = ", "; - } - return os; -} - -int parse_schedule_name(const std::string &name, std::string *pool_name, - std::string *namespace_name, std::string *image_name) { - // parse names like: - // '', 'rbd/', 'rbd/ns/', 'rbd/image', 'rbd/ns/image' - std::regex pattern("^(?:([^/]+)/(?:(?:([^/]+)/|)(?:([^/@]+))?)?)?$"); - std::smatch match; - if (!std::regex_match(name, match, pattern)) { - return -EINVAL; - } - - if (match[1].matched) { - *pool_name = match[1]; - } else { - *pool_name = "-"; - } - - if (match[2].matched) { - *namespace_name = match[2]; - } else if (match[3].matched) { - *namespace_name = ""; - } else { - *namespace_name = "-"; - } - - if (match[3].matched) { - *image_name = match[3]; - } else { - *image_name = "-"; - } - - return 0; -} - -class ScheduleList { -public: - ScheduleList() { - } - - int parse(const std::string &list) { - json_spirit::mValue json_root; - if (!json_spirit::read(list, json_root)) { - std::cerr << "rbd: invalid schedule list JSON received" << std::endl; - return -EBADMSG; - } - - try { - for (auto &[id, schedule_val] : json_root.get_obj()) { - if (schedule_val.type() != json_spirit::obj_type) { - std::cerr << "rbd: unexpected schedule list JSON received: " - << "schedule_val is not object" << std::endl; - return -EBADMSG; - } - auto &schedule = schedule_val.get_obj(); - if (schedule["name"].type() != json_spirit::str_type) { - std::cerr << "rbd: unexpected schedule list JSON received: " - << "schedule name is not string" << std::endl; - return -EBADMSG; - } - auto name = schedule["name"].get_str(); - - if (schedule["schedule"].type() != json_spirit::array_type) { - std::cerr << "rbd: unexpected schedule list JSON received: " - << "schedule is not array" << std::endl; - return -EBADMSG; - } - - Schedule s; - int r = s.parse(schedule["schedule"]); - if (r < 0) { - return r; - } - schedules[name] = s; - } - } catch (std::runtime_error &) { - std::cerr << "rbd: invalid schedule list JSON received" << std::endl; - return -EBADMSG; - } - - return 0; - } - - Schedule *find(const std::string &name) { - auto it = schedules.find(name); - if (it == schedules.end()) { - return nullptr; - } - - return &it->second; - } - - void dump(Formatter *f) { - f->open_array_section("schedules"); - for (auto &[name, s] : schedules) { - std::string pool_name; - std::string namespace_name; - std::string image_name; - - int r = parse_schedule_name(name, &pool_name, &namespace_name, - &image_name); - if (r < 0) { - continue; - } - - f->open_object_section("schedule"); - f->dump_string("pool", pool_name); - f->dump_string("namespace", namespace_name); - f->dump_string("image", image_name); - s.dump(f); - f->close_section(); - } - f->close_section(); - } - - friend std::ostream& operator<<(std::ostream& os, ScheduleList &d); - -private: - std::map schedules; -}; - -std::ostream& operator<<(std::ostream& os, ScheduleList &l) { - TextTable tbl; - tbl.define_column("POOL", TextTable::LEFT, TextTable::LEFT); - tbl.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT); - tbl.define_column("IMAGE", TextTable::LEFT, TextTable::LEFT); - tbl.define_column("SCHEDULE", TextTable::LEFT, TextTable::LEFT); - - for (auto &[name, s] : l.schedules) { - std::string pool_name; - std::string namespace_name; - std::string image_name; - - int r = parse_schedule_name(name, &pool_name, &namespace_name, - &image_name); - if (r < 0) { - continue; - } - - std::stringstream ss; - ss << s; - - tbl << pool_name << namespace_name << image_name << ss.str() - << TextTable::endrow; - } - - os << tbl; - return os; -} - class ScheduleStatus { public: ScheduleStatus() { @@ -363,155 +116,25 @@ std::ostream& operator<<(std::ostream& os, ScheduleStatus &s) { return os; } -int ceph_rbd_mirror_snapshot_schedule(librados::Rados& rados, - const std::string& cmd, - const Args& args, - std::ostream *out_os, - std::ostream *err_os) { - std::string command = R"( - { - "prefix": "rbd mirror snapshot schedule )" + cmd + R"(", - )" + args.str() + R"( - })"; - - bufferlist in_bl; - bufferlist out_bl; - std::string outs; - int r = rados.mgr_command(command, in_bl, &out_bl, &outs); - if (r == -EOPNOTSUPP) { - (*err_os) << "rbd: 'rbd_support' mgr module is not enabled." - << std::endl << std::endl - << "Use 'ceph mgr module enable rbd_support' to enable." - << std::endl; - return r; - } else if (r < 0) { - (*err_os) << "rbd: " << cmd << " failed: " << cpp_strerror(r); - if (!outs.empty()) { - (*err_os) << ": " << outs; - } - (*err_os) << std::endl; - return r; - } - - if (out_bl.length() != 0) { - (*out_os) << out_bl.c_str(); - } - - return 0; -} - -void add_level_spec_options(po::options_description *options) { - at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); - at::add_namespace_option(options, at::ARGUMENT_MODIFIER_NONE); - at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); -} - -int get_level_spec_name(const po::variables_map &vm, - std::string *level_spec_name) { - if (vm.count(at::IMAGE_NAME)) { - std::string pool_name; - std::string namespace_name; - std::string image_name; - - int r = utils::extract_spec(vm[at::IMAGE_NAME].as(), - &pool_name, &namespace_name, &image_name, - nullptr, utils::SPEC_VALIDATION_FULL); - if (r < 0) { - return r; - } - - if (!pool_name.empty()) { - if (vm.count(at::POOL_NAME)) { - std::cerr << "rbd: pool is specified both via pool and image options" - << std::endl; - return -EINVAL; - } - if (vm.count(at::NAMESPACE_NAME)) { - std::cerr << "rbd: namespace is specified both via namespace and image" - << " options" << std::endl; - return -EINVAL; - } - } - - if (vm.count(at::POOL_NAME)) { - pool_name = vm[at::POOL_NAME].as(); - } else if (pool_name.empty()) { - pool_name = utils::get_default_pool_name(); - } - - if (vm.count(at::NAMESPACE_NAME)) { - namespace_name = vm[at::NAMESPACE_NAME].as(); - } - - if (namespace_name.empty()) { - *level_spec_name = pool_name + "/" + image_name; - } else { - *level_spec_name = pool_name + "/" + namespace_name + "/" + image_name; - } - return 0; - } - - if (vm.count(at::NAMESPACE_NAME)) { - std::string pool_name; - std::string namespace_name; - - if (vm.count(at::POOL_NAME)) { - pool_name = vm[at::POOL_NAME].as(); - } else { - pool_name = utils::get_default_pool_name(); - } - - namespace_name = vm[at::NAMESPACE_NAME].as(); - - *level_spec_name = pool_name + "/" + namespace_name + "/"; - - return 0; - } - - if (vm.count(at::POOL_NAME)) { - std::string pool_name = vm[at::POOL_NAME].as(); - - *level_spec_name = pool_name + "/"; - - return 0; - } - - *level_spec_name = ""; - - return 0; -} - } // anonymous namespace void get_arguments_add(po::options_description *positional, po::options_description *options) { add_level_spec_options(options); - positional->add_options() - ("interval", "schedule interval"); - positional->add_options() - ("start-time", "schedule start time"); + add_schedule_options(positional); } int execute_add(const po::variables_map &vm, const std::vector &ceph_global_init_args) { - std::string level_spec_name; - int r = get_level_spec_name(vm, &level_spec_name); + std::map args; + + int r = get_level_spec_args(vm, &args); if (r < 0) { return r; } - - size_t arg_index = 0; - std::string interval = utils::get_positional_argument(vm, arg_index++); - if (interval.empty()) { - std::cerr << "rbd: missing 'interval' argument" << std::endl; - return -EINVAL; - } - - Args args({{"level_spec", level_spec_name}, {"interval", interval}}); - - std::string start_time = utils::get_positional_argument(vm, arg_index++); - if (!start_time.empty()) { - args.args["start_time"] = start_time; + r = get_schedule_args(vm, true, &args); + if (r < 0) { + return r; } librados::Rados rados; @@ -520,8 +143,8 @@ int execute_add(const po::variables_map &vm, return r; } - r = ceph_rbd_mirror_snapshot_schedule(rados, "add", args, &std::cout, - &std::cerr); + r = utils::mgr_command(rados, "rbd mirror snapshot schedule add", args, + &std::cout, &std::cerr); if (r < 0) { return r; } @@ -532,31 +155,20 @@ int execute_add(const po::variables_map &vm, void get_arguments_remove(po::options_description *positional, po::options_description *options) { add_level_spec_options(options); - positional->add_options() - ("interval", "schedule interval"); - positional->add_options() - ("start-time", "schedule start time"); + add_schedule_options(positional); } int execute_remove(const po::variables_map &vm, const std::vector &ceph_global_init_args) { - std::string level_spec_name; - int r = get_level_spec_name(vm, &level_spec_name); + std::map args; + + int r = get_level_spec_args(vm, &args); if (r < 0) { return r; } - - Args args({{"level_spec", level_spec_name}}); - - size_t arg_index = 0; - std::string interval = utils::get_positional_argument(vm, arg_index++); - if (!interval.empty()) { - args.args["interval"] = interval; - } - - std::string start_time = utils::get_positional_argument(vm, arg_index++); - if (!start_time.empty()) { - args.args["start_time"] = start_time; + r = get_schedule_args(vm, false, &args); + if (r < 0) { + return r; } librados::Rados rados; @@ -565,8 +177,8 @@ int execute_remove(const po::variables_map &vm, return r; } - r = ceph_rbd_mirror_snapshot_schedule(rados, "remove", args, &std::cout, - &std::cerr); + r = utils::mgr_command(rados, "rbd mirror snapshot schedule remove", args, + &std::cout, &std::cerr); if (r < 0) { return r; } @@ -584,8 +196,9 @@ void get_arguments_list(po::options_description *positional, int execute_list(const po::variables_map &vm, const std::vector &ceph_global_init_args) { - std::string level_spec_name; - int r = get_level_spec_name(vm, &level_spec_name); + std::map args; + + int r = get_level_spec_args(vm, &args); if (r < 0) { return r; } @@ -602,9 +215,9 @@ int execute_list(const po::variables_map &vm, return r; } - Args args({{"level_spec", level_spec_name}}); std::stringstream out; - r = ceph_rbd_mirror_snapshot_schedule(rados, "list", args, &out, &std::cerr); + r = utils::mgr_command(rados, "rbd mirror snapshot schedule list", args, &out, + &std::cerr); if (r < 0) { return r; } @@ -623,7 +236,7 @@ int execute_list(const po::variables_map &vm, std::cout << schedule_list; } } else { - auto schedule = schedule_list.find(level_spec_name); + auto schedule = schedule_list.find(args["level_spec"]); if (schedule == nullptr) { return -ENOENT; } @@ -647,8 +260,9 @@ void get_arguments_status(po::options_description *positional, int execute_status(const po::variables_map &vm, const std::vector &ceph_global_init_args) { - std::string level_spec_name; - int r = get_level_spec_name(vm, &level_spec_name); + std::map args; + + int r = get_level_spec_args(vm, &args); if (r < 0) { return r; } @@ -665,11 +279,9 @@ int execute_status(const po::variables_map &vm, return r; } - Args args({{"level_spec", level_spec_name}}); - std::stringstream out; - r = ceph_rbd_mirror_snapshot_schedule(rados, "status", args, &out, - &std::cerr); + r = utils::mgr_command(rados, "rbd mirror snapshot schedule status", args, + &out, &std::cerr); ScheduleStatus schedule_status; r = schedule_status.parse(out.str()); if (r < 0) {