]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/MirrorSnapshotSchedule.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / tools / rbd / action / MirrorSnapshotSchedule.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
15
16 #include <iostream>
17 #include <list>
18 #include <map>
19 #include <string>
20 #include <boost/program_options.hpp>
21
22 #include "json_spirit/json_spirit.h"
23
24 namespace rbd {
25 namespace action {
26 namespace mirror_snapshot_schedule {
27
28 namespace at = argument_types;
29 namespace po = boost::program_options;
30
31 namespace {
32
33 class ScheduleStatus {
34 public:
35 ScheduleStatus() {
36 }
37
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;
42 return -EBADMSG;
43 }
44
45 try {
46 auto &s = json_root.get_obj();
47
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;
51 return -EBADMSG;
52 }
53
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;
58 return -EBADMSG;
59 }
60
61 auto &item = item_val.get_obj();
62
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;
66 return -EBADMSG;
67 }
68 auto schedule_time = item["schedule_time"].get_str();
69
70 if (item["image"].type() != json_spirit::str_type) {
71 std::cerr << "rbd: unexpected schedule JSON received: "
72 << "image is not string" << std::endl;
73 return -EBADMSG;
74 }
75 auto image = item["image"].get_str();
76
77 scheduled_images.push_back({schedule_time, image});
78 }
79
80 } catch (std::runtime_error &) {
81 std::cerr << "rbd: invalid schedule JSON received" << std::endl;
82 return -EBADMSG;
83 }
84
85 return 0;
86 }
87
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
95 }
96 f->close_section(); // scheduled_images
97 }
98
99 friend std::ostream& operator<<(std::ostream& os, ScheduleStatus &d);
100
101 private:
102
103 std::list<std::pair<std::string, std::string>> scheduled_images;
104 };
105
106 std::ostream& operator<<(std::ostream& os, ScheduleStatus &s) {
107 TextTable tbl;
108 tbl.define_column("SCHEDULE TIME", TextTable::LEFT, TextTable::LEFT);
109 tbl.define_column("IMAGE", TextTable::LEFT, TextTable::LEFT);
110
111 for (auto &[schedule_time, image] : s.scheduled_images) {
112 tbl << schedule_time << image << TextTable::endrow;
113 }
114
115 os << tbl;
116 return os;
117 }
118
119 } // anonymous namespace
120
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);
125 }
126
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;
130
131 int r = get_level_spec_args(vm, &args);
132 if (r < 0) {
133 return r;
134 }
135 r = get_schedule_args(vm, true, &args);
136 if (r < 0) {
137 return r;
138 }
139
140 librados::Rados rados;
141 r = utils::init_rados(&rados);
142 if (r < 0) {
143 return r;
144 }
145
146 normalize_level_spec_args(&args);
147 r = utils::mgr_command(rados, "rbd mirror snapshot schedule add", args,
148 &std::cout, &std::cerr);
149 if (r < 0) {
150 return r;
151 }
152
153 return 0;
154 }
155
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);
160 }
161
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;
165
166 int r = get_level_spec_args(vm, &args);
167 if (r < 0) {
168 return r;
169 }
170 r = get_schedule_args(vm, false, &args);
171 if (r < 0) {
172 return r;
173 }
174
175 librados::Rados rados;
176 r = utils::init_rados(&rados);
177 if (r < 0) {
178 return r;
179 }
180
181 normalize_level_spec_args(&args);
182 r = utils::mgr_command(rados, "rbd mirror snapshot schedule remove", args,
183 &std::cout, &std::cerr);
184 if (r < 0) {
185 return r;
186 }
187
188 return 0;
189 }
190
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);
197 }
198
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;
202
203 int r = get_level_spec_args(vm, &args);
204 if (r < 0) {
205 return r;
206 }
207
208 at::Format::Formatter formatter;
209 r = utils::get_formatter(vm, &formatter);
210 if (r < 0) {
211 return r;
212 }
213
214 librados::Rados rados;
215 r = utils::init_rados(&rados);
216 if (r < 0) {
217 return r;
218 }
219
220 normalize_level_spec_args(&args);
221 std::stringstream out;
222 r = utils::mgr_command(rados, "rbd mirror snapshot schedule list", args, &out,
223 &std::cerr);
224 if (r < 0) {
225 return r;
226 }
227
228 ScheduleList schedule_list;
229 r = schedule_list.parse(out.str());
230 if (r < 0) {
231 return r;
232 }
233
234 if (vm["recursive"].as<bool>()) {
235 if (formatter.get()) {
236 schedule_list.dump(formatter.get());
237 formatter->flush(std::cout);
238 } else {
239 std::cout << schedule_list;
240 }
241 } else {
242 auto schedule = schedule_list.find(args["level_spec"]);
243 if (schedule == nullptr) {
244 return -ENOENT;
245 }
246
247 if (formatter.get()) {
248 schedule->dump(formatter.get());
249 formatter->flush(std::cout);
250 } else {
251 std::cout << *schedule << std::endl;
252 }
253 }
254
255 return 0;
256 }
257
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);
262 }
263
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;
267
268 int r = get_level_spec_args(vm, &args);
269 if (r < 0) {
270 return r;
271 }
272
273 at::Format::Formatter formatter;
274 r = utils::get_formatter(vm, &formatter);
275 if (r < 0) {
276 return r;
277 }
278
279 librados::Rados rados;
280 r = utils::init_rados(&rados);
281 if (r < 0) {
282 return r;
283 }
284
285 normalize_level_spec_args(&args);
286 std::stringstream out;
287 r = utils::mgr_command(rados, "rbd mirror snapshot schedule status", args,
288 &out, &std::cerr);
289 ScheduleStatus schedule_status;
290 r = schedule_status.parse(out.str());
291 if (r < 0) {
292 return r;
293 }
294
295 if (formatter.get()) {
296 schedule_status.dump(formatter.get());
297 formatter->flush(std::cout);
298 } else {
299 std::cout << schedule_status;
300 }
301
302 return 0;
303 }
304
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);
319
320 } // namespace mirror_snapshot_schedule
321 } // namespace action
322 } // namespace rbd