]>
Commit | Line | Data |
---|---|---|
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); | |
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); | |
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 |