From eb53985dd7720ec0c9be6e6c9ef54b74dda90ff2 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Tue, 18 Feb 2020 15:35:16 +0000 Subject: [PATCH] rbd: add `trash purge schedule` commands Signed-off-by: Mykola Golub --- doc/man/8/rbd.rst | 12 + src/test/cli/rbd/help.t | 63 ++++ src/tools/rbd/CMakeLists.txt | 1 + src/tools/rbd/action/TrashPurgeSchedule.cc | 349 +++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 src/tools/rbd/action/TrashPurgeSchedule.cc diff --git a/doc/man/8/rbd.rst b/doc/man/8/rbd.rst index ad188909f0fbe..b5a373584a213 100644 --- a/doc/man/8/rbd.rst +++ b/doc/man/8/rbd.rst @@ -651,6 +651,18 @@ Commands you can not removed it unless use force. But an actively in-use by clones or has snapshots can not be removed. +:command:`trash purge schedule add` [-p | --pool *pool*] [--namespace *namespace*] *interval* [*start-time*] + Add trash purge schedule. + +:command:`trash purge schedule list` [-R | --recursive] [--format *format*] [--pretty-format] [-p | --pool *pool*] [--namespace *namespace*] + List trash purge schedule. + +:command:`trash purge schedule remove` [-p | --pool *pool*] [--namespace *namespace*] *interval* [*start-time*] + Remove trash purge schedule. + +:command:`trash purge schedule status` [-p | --pool *pool*] [--format *format*] [--pretty-format] [--namespace *namespace*] + Show trash purge schedule status. + :command:`watch` *image-spec* Watch events on image. diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index bf08a14107969..fe3d4dc3efb1b 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -140,6 +140,12 @@ trash list (trash ls) List trash images. trash move (trash mv) Move an image to the trash. trash purge Remove all expired images from trash. + trash purge schedule add Add trash purge schedule. + trash purge schedule list (... ls) + List trash purge schedule. + trash purge schedule remove (... rm) + Remove trash purge schedule. + trash purge schedule status Show trash purge schedule status. trash remove (trash rm) Remove an image from trash. trash restore Restore an image from trash. watch Watch events on image. @@ -2389,6 +2395,63 @@ --threshold arg purges images until the current pool data usage is reduced to X%, value range: 0.0-1.0 + rbd help trash purge schedule add + usage: rbd trash purge schedule add [--pool ] [--namespace ] + + + Add trash purge schedule. + + Positional arguments + schedule interval + schedule start time + + Optional arguments + -p [ --pool ] arg pool name + --namespace arg namespace name + + rbd help trash purge schedule list + usage: rbd trash purge schedule list [--pool ] [--namespace ] + [--recursive] [--format ] + [--pretty-format] + + List trash purge schedule. + + Optional arguments + -p [ --pool ] arg pool name + --namespace arg namespace name + -R [ --recursive ] list all schedules + --format arg output format (plain, json, or xml) [default: plain] + --pretty-format pretty formatting (json and xml) + + rbd help trash purge schedule remove + usage: rbd trash purge schedule remove + [--pool ] [--namespace ] + + + Remove trash purge schedule. + + Positional arguments + schedule interval + schedule start time + + Optional arguments + -p [ --pool ] arg pool name + --namespace arg namespace name + + rbd help trash purge schedule status + usage: rbd trash purge schedule status + [--pool ] + [--namespace ] + [--format ] [--pretty-format] + + Show trash purge schedule status. + + Optional arguments + -p [ --pool ] arg pool name + --namespace arg namespace name + --format arg output format (plain, json, or xml) [default: plain] + --pretty-format pretty formatting (json and xml) + rbd help trash remove usage: rbd trash remove [--pool ] [--namespace ] [--image-id ] [--no-progress] [--force] diff --git a/src/tools/rbd/CMakeLists.txt b/src/tools/rbd/CMakeLists.txt index 2abf9341363ea..2a185f05204dd 100644 --- a/src/tools/rbd/CMakeLists.txt +++ b/src/tools/rbd/CMakeLists.txt @@ -47,6 +47,7 @@ set(rbd_srcs action/Snap.cc action/Sparsify.cc action/Status.cc + action/TrashPurgeSchedule.cc action/Trash.cc action/Watch.cc) diff --git a/src/tools/rbd/action/TrashPurgeSchedule.cc b/src/tools/rbd/action/TrashPurgeSchedule.cc new file mode 100644 index 0000000000000..b6282f91e063c --- /dev/null +++ b/src/tools/rbd/action/TrashPurgeSchedule.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 "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/Formatter.h" +#include "common/TextTable.h" +#include "global/global_context.h" +#include "include/stringify.h" + +#include +#include +#include +#include +#include +#include + +#include "json_spirit/json_spirit.h" + +namespace rbd { +namespace action { +namespace trash_purge_schedule { + +namespace at = argument_types; +namespace po = boost::program_options; + +namespace { + +class ScheduleStatus { +public: + ScheduleStatus() { + } + + int parse(const std::string &status) { + json_spirit::mValue json_root; + if(!json_spirit::read(status, json_root)) { + std::cerr << "rbd: invalid schedule status JSON received" << std::endl; + return -EBADMSG; + } + + try { + auto &s = json_root.get_obj(); + + if (s["scheduled"].type() != json_spirit::array_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "scheduled is not array" << std::endl; + return -EBADMSG; + } + + for (auto &item_val : s["scheduled"].get_array()) { + if (item_val.type() != json_spirit::obj_type) { + std::cerr << "rbd: unexpected schedule status JSON received: " + << "schedule item is not object" << std::endl; + return -EBADMSG; + } + + auto &item = item_val.get_obj(); + + if (item["pool_name"].type() != json_spirit::str_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "pool_name is not string" << std::endl; + return -EBADMSG; + } + auto pool_name = item["pool_name"].get_str(); + + if (item["namespace"].type() != json_spirit::str_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "namespace is not string" << std::endl; + return -EBADMSG; + } + auto namespace_name = item["namespace"].get_str(); + + if (item["schedule_time"].type() != json_spirit::str_type) { + std::cerr << "rbd: unexpected schedule JSON received: " + << "schedule_time is not string" << std::endl; + return -EBADMSG; + } + auto schedule_time = item["schedule_time"].get_str(); + + scheduled.insert({pool_name, namespace_name, schedule_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("scheduled"); + for (auto &item : scheduled) { + f->open_object_section("item"); + f->dump_string("pool", item.pool_name); + f->dump_string("namespce", item.namespace_name); + f->dump_string("schedule_time", item.schedule_time); + f->close_section(); // item + } + f->close_section(); // scheduled + } + + friend std::ostream& operator<<(std::ostream& os, ScheduleStatus &d); + +private: + + struct Item { + std::string pool_name; + std::string namespace_name; + std::string schedule_time; + + Item(const std::string &pool_name, const std::string &namespace_name, + const std::string &schedule_time) + : pool_name(pool_name), namespace_name(namespace_name), + schedule_time(schedule_time) { + } + + bool operator<(const Item &rhs) const { + if (pool_name != rhs.pool_name) { + return pool_name < rhs.pool_name; + } + return namespace_name < rhs.namespace_name; + } + }; + + std::set scheduled; +}; + +std::ostream& operator<<(std::ostream& os, ScheduleStatus &s) { + TextTable tbl; + tbl.define_column("POOL", TextTable::LEFT, TextTable::LEFT); + tbl.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT); + tbl.define_column("SCHEDULE TIME", TextTable::LEFT, TextTable::LEFT); + + for (auto &item : s.scheduled) { + tbl << item.pool_name << item.namespace_name << item.schedule_time + << TextTable::endrow; + } + + os << tbl; + return os; +} + +} // anonymous namespace + +void get_arguments_add(po::options_description *positional, + po::options_description *options) { + add_level_spec_options(options, false); + add_schedule_options(positional); +} + +int execute_add(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::map args; + + int r = get_level_spec_args(vm, &args); + if (r < 0) { + return r; + } + r = get_schedule_args(vm, true, &args); + if (r < 0) { + return r; + } + + librados::Rados rados; + r = utils::init_rados(&rados); + if (r < 0) { + return r; + } + + r = utils::mgr_command(rados, "rbd trash purge schedule add", args, + &std::cout, &std::cerr); + if (r < 0) { + return r; + } + + return 0; +} + +void get_arguments_remove(po::options_description *positional, + po::options_description *options) { + add_level_spec_options(options, false); + add_schedule_options(positional); +} + +int execute_remove(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::map args; + + int r = get_level_spec_args(vm, &args); + if (r < 0) { + return r; + } + r = get_schedule_args(vm, false, &args); + if (r < 0) { + return r; + } + + librados::Rados rados; + r = utils::init_rados(&rados); + if (r < 0) { + return r; + } + + r = utils::mgr_command(rados, "rbd trash purge schedule remove", args, + &std::cout, &std::cerr); + if (r < 0) { + return r; + } + + return 0; +} + +void get_arguments_list(po::options_description *positional, + po::options_description *options) { + add_level_spec_options(options, false); + options->add_options() + ("recursive,R", po::bool_switch(), "list all schedules"); + at::add_format_options(options); +} + +int execute_list(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::map args; + + int r = get_level_spec_args(vm, &args); + if (r < 0) { + return r; + } + + at::Format::Formatter formatter; + r = utils::get_formatter(vm, &formatter); + if (r < 0) { + return r; + } + + librados::Rados rados; + r = utils::init_rados(&rados); + if (r < 0) { + return r; + } + + std::stringstream out; + r = utils::mgr_command(rados, "rbd trash purge schedule list", args, &out, + &std::cerr); + if (r < 0) { + return r; + } + + ScheduleList schedule_list(false); + r = schedule_list.parse(out.str()); + if (r < 0) { + return r; + } + + if (vm["recursive"].as()) { + if (formatter.get()) { + schedule_list.dump(formatter.get()); + formatter->flush(std::cout); + } else { + std::cout << schedule_list; + } + } else { + auto schedule = schedule_list.find(args["level_spec"]); + if (schedule == nullptr) { + return -ENOENT; + } + + if (formatter.get()) { + schedule->dump(formatter.get()); + formatter->flush(std::cout); + } else { + std::cout << *schedule << std::endl; + } + } + + return 0; +} + +void get_arguments_status(po::options_description *positional, + po::options_description *options) { + add_level_spec_options(options, false); + at::add_format_options(options); +} + +int execute_status(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::map args; + + int r = get_level_spec_args(vm, &args); + if (r < 0) { + return r; + } + + at::Format::Formatter formatter; + r = utils::get_formatter(vm, &formatter); + if (r < 0) { + return r; + } + + librados::Rados rados; + r = utils::init_rados(&rados); + if (r < 0) { + return r; + } + + std::stringstream out; + r = utils::mgr_command(rados, "rbd trash purge schedule status", args, &out, + &std::cerr); + ScheduleStatus schedule_status; + r = schedule_status.parse(out.str()); + if (r < 0) { + return r; + } + + if (formatter.get()) { + schedule_status.dump(formatter.get()); + formatter->flush(std::cout); + } else { + std::cout << schedule_status; + } + + return 0; +} + +Shell::Action add_action( + {"trash", "purge", "schedule", "add"}, {}, "Add trash purge schedule.", "", + &get_arguments_add, &execute_add); +Shell::Action remove_action( + {"trash", "purge", "schedule", "remove"}, + {"trash", "purge", "schedule", "rm"}, "Remove trash purge schedule.", + "", &get_arguments_remove, &execute_remove); +Shell::Action list_action( + {"trash", "purge", "schedule", "list"}, + {"trash", "purge", "schedule", "ls"}, "List trash purge schedule.", + "", &get_arguments_list, &execute_list); +Shell::Action status_action( + {"trash", "purge", "schedule", "status"}, {}, + "Show trash purge schedule status.", "", &get_arguments_status, + &execute_status); + +} // namespace trash_purge_schedule +} // namespace action +} // namespace rbd -- 2.39.5