1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Schedule.h"
6 #include "tools/rbd/Shell.h"
7 #include "tools/rbd/Utils.h"
8 #include "common/ceph_context.h"
9 #include "common/ceph_json.h"
10 #include "common/errno.h"
11 #include "common/Formatter.h"
12 #include "common/TextTable.h"
13 #include "global/global_context.h"
14 #include "include/stringify.h"
20 #include <boost/program_options.hpp>
22 #include "json_spirit/json_spirit.h"
26 namespace mirror_snapshot_schedule
{
28 namespace at
= argument_types
;
29 namespace po
= boost::program_options
;
33 class ScheduleStatus
{
38 int parse(const std::string
&status
) {
39 json_spirit::mValue json_root
;
40 if(!json_spirit::read(status
, json_root
)) {
41 std::cerr
<< "rbd: invalid schedule status JSON received" << std::endl
;
46 auto &s
= json_root
.get_obj();
48 if (s
["scheduled_images"].type() != json_spirit::array_type
) {
49 std::cerr
<< "rbd: unexpected schedule JSON received: "
50 << "scheduled_images is not array" << std::endl
;
54 for (auto &item_val
: s
["scheduled_images"].get_array()) {
55 if (item_val
.type() != json_spirit::obj_type
) {
56 std::cerr
<< "rbd: unexpected schedule status JSON received: "
57 << "schedule item is not object" << std::endl
;
61 auto &item
= item_val
.get_obj();
63 if (item
["schedule_time"].type() != json_spirit::str_type
) {
64 std::cerr
<< "rbd: unexpected schedule JSON received: "
65 << "schedule_time is not string" << std::endl
;
68 auto schedule_time
= item
["schedule_time"].get_str();
70 if (item
["image"].type() != json_spirit::str_type
) {
71 std::cerr
<< "rbd: unexpected schedule JSON received: "
72 << "image is not string" << std::endl
;
75 auto image
= item
["image"].get_str();
77 scheduled_images
.push_back({schedule_time
, image
});
80 } catch (std::runtime_error
&) {
81 std::cerr
<< "rbd: invalid schedule JSON received" << std::endl
;
88 void dump(Formatter
*f
) {
89 f
->open_array_section("scheduled_images");
90 for (auto &image
: scheduled_images
) {
91 f
->open_object_section("image");
92 f
->dump_string("schedule_time", image
.first
);
93 f
->dump_string("image", image
.second
);
94 f
->close_section(); // image
96 f
->close_section(); // scheduled_images
99 friend std::ostream
& operator<<(std::ostream
& os
, ScheduleStatus
&d
);
103 std::list
<std::pair
<std::string
, std::string
>> scheduled_images
;
106 std::ostream
& operator<<(std::ostream
& os
, ScheduleStatus
&s
) {
108 tbl
.define_column("SCHEDULE TIME", TextTable::LEFT
, TextTable::LEFT
);
109 tbl
.define_column("IMAGE", TextTable::LEFT
, TextTable::LEFT
);
111 for (auto &[schedule_time
, image
] : s
.scheduled_images
) {
112 tbl
<< schedule_time
<< image
<< TextTable::endrow
;
119 } // anonymous namespace
121 void get_arguments_add(po::options_description
*positional
,
122 po::options_description
*options
) {
123 add_level_spec_options(options
);
124 add_schedule_options(positional
, true);
127 int execute_add(const po::variables_map
&vm
,
128 const std::vector
<std::string
> &ceph_global_init_args
) {
129 std::map
<std::string
, std::string
> args
;
131 int r
= get_level_spec_args(vm
, &args
);
135 r
= get_schedule_args(vm
, true, &args
);
140 librados::Rados rados
;
141 r
= utils::init_rados(&rados
);
146 normalize_level_spec_args(&args
);
147 r
= utils::mgr_command(rados
, "rbd mirror snapshot schedule add", args
,
148 &std::cout
, &std::cerr
);
156 void get_arguments_remove(po::options_description
*positional
,
157 po::options_description
*options
) {
158 add_level_spec_options(options
);
159 add_schedule_options(positional
, false);
162 int execute_remove(const po::variables_map
&vm
,
163 const std::vector
<std::string
> &ceph_global_init_args
) {
164 std::map
<std::string
, std::string
> args
;
166 int r
= get_level_spec_args(vm
, &args
);
170 r
= get_schedule_args(vm
, false, &args
);
175 librados::Rados rados
;
176 r
= utils::init_rados(&rados
);
181 normalize_level_spec_args(&args
);
182 r
= utils::mgr_command(rados
, "rbd mirror snapshot schedule remove", args
,
183 &std::cout
, &std::cerr
);
191 void get_arguments_list(po::options_description
*positional
,
192 po::options_description
*options
) {
193 add_level_spec_options(options
);
194 options
->add_options()
195 ("recursive,R", po::bool_switch(), "list all schedules");
196 at::add_format_options(options
);
199 int execute_list(const po::variables_map
&vm
,
200 const std::vector
<std::string
> &ceph_global_init_args
) {
201 std::map
<std::string
, std::string
> args
;
203 int r
= get_level_spec_args(vm
, &args
);
208 at::Format::Formatter formatter
;
209 r
= utils::get_formatter(vm
, &formatter
);
214 librados::Rados rados
;
215 r
= utils::init_rados(&rados
);
220 normalize_level_spec_args(&args
);
221 std::stringstream out
;
222 r
= utils::mgr_command(rados
, "rbd mirror snapshot schedule list", args
, &out
,
228 ScheduleList schedule_list
;
229 r
= schedule_list
.parse(out
.str());
234 if (vm
["recursive"].as
<bool>()) {
235 if (formatter
.get()) {
236 schedule_list
.dump(formatter
.get());
237 formatter
->flush(std::cout
);
239 std::cout
<< schedule_list
;
242 auto schedule
= schedule_list
.find(args
["level_spec"]);
243 if (schedule
== nullptr) {
247 if (formatter
.get()) {
248 schedule
->dump(formatter
.get());
249 formatter
->flush(std::cout
);
251 std::cout
<< *schedule
<< std::endl
;
258 void get_arguments_status(po::options_description
*positional
,
259 po::options_description
*options
) {
260 add_level_spec_options(options
);
261 at::add_format_options(options
);
264 int execute_status(const po::variables_map
&vm
,
265 const std::vector
<std::string
> &ceph_global_init_args
) {
266 std::map
<std::string
, std::string
> args
;
268 int r
= get_level_spec_args(vm
, &args
);
273 at::Format::Formatter formatter
;
274 r
= utils::get_formatter(vm
, &formatter
);
279 librados::Rados rados
;
280 r
= utils::init_rados(&rados
);
285 normalize_level_spec_args(&args
);
286 std::stringstream out
;
287 r
= utils::mgr_command(rados
, "rbd mirror snapshot schedule status", args
,
289 ScheduleStatus schedule_status
;
290 r
= schedule_status
.parse(out
.str());
295 if (formatter
.get()) {
296 schedule_status
.dump(formatter
.get());
297 formatter
->flush(std::cout
);
299 std::cout
<< schedule_status
;
305 Shell::Action
add_action(
306 {"mirror", "snapshot", "schedule", "add"}, {},
307 "Add mirror snapshot schedule.", "", &get_arguments_add
, &execute_add
);
308 Shell::Action
remove_action(
309 {"mirror", "snapshot", "schedule", "remove"},
310 {"mirror", "snapshot", "schedule", "rm"}, "Remove mirror snapshot schedule.",
311 "", &get_arguments_remove
, &execute_remove
);
312 Shell::Action
list_action(
313 {"mirror", "snapshot", "schedule", "list"},
314 {"mirror", "snapshot", "schedule", "ls"}, "List mirror snapshot schedule.",
315 "", &get_arguments_list
, &execute_list
);
316 Shell::Action
status_action(
317 {"mirror", "snapshot", "schedule", "status"}, {},
318 "Show mirror snapshot schedule status.", "", &get_arguments_status
, &execute_status
);
320 } // namespace mirror_snapshot_schedule
321 } // namespace action