]>
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 <set> | |
20 | #include <string> | |
21 | #include <boost/program_options.hpp> | |
22 | ||
23 | #include "json_spirit/json_spirit.h" | |
24 | ||
25 | namespace rbd { | |
26 | namespace action { | |
27 | namespace trash_purge_schedule { | |
28 | ||
29 | namespace at = argument_types; | |
30 | namespace po = boost::program_options; | |
31 | ||
32 | namespace { | |
33 | ||
34 | class ScheduleStatus { | |
35 | public: | |
36 | ScheduleStatus() { | |
37 | } | |
38 | ||
39 | int parse(const std::string &status) { | |
40 | json_spirit::mValue json_root; | |
41 | if(!json_spirit::read(status, json_root)) { | |
42 | std::cerr << "rbd: invalid schedule status JSON received" << std::endl; | |
43 | return -EBADMSG; | |
44 | } | |
45 | ||
46 | try { | |
47 | auto &s = json_root.get_obj(); | |
48 | ||
49 | if (s["scheduled"].type() != json_spirit::array_type) { | |
50 | std::cerr << "rbd: unexpected schedule JSON received: " | |
51 | << "scheduled is not array" << std::endl; | |
52 | return -EBADMSG; | |
53 | } | |
54 | ||
55 | for (auto &item_val : s["scheduled"].get_array()) { | |
56 | if (item_val.type() != json_spirit::obj_type) { | |
57 | std::cerr << "rbd: unexpected schedule status JSON received: " | |
58 | << "schedule item is not object" << std::endl; | |
59 | return -EBADMSG; | |
60 | } | |
61 | ||
62 | auto &item = item_val.get_obj(); | |
63 | ||
64 | if (item["pool_name"].type() != json_spirit::str_type) { | |
65 | std::cerr << "rbd: unexpected schedule JSON received: " | |
66 | << "pool_name is not string" << std::endl; | |
67 | return -EBADMSG; | |
68 | } | |
69 | auto pool_name = item["pool_name"].get_str(); | |
70 | ||
71 | if (item["namespace"].type() != json_spirit::str_type) { | |
72 | std::cerr << "rbd: unexpected schedule JSON received: " | |
73 | << "namespace is not string" << std::endl; | |
74 | return -EBADMSG; | |
75 | } | |
76 | auto namespace_name = item["namespace"].get_str(); | |
77 | ||
78 | if (item["schedule_time"].type() != json_spirit::str_type) { | |
79 | std::cerr << "rbd: unexpected schedule JSON received: " | |
80 | << "schedule_time is not string" << std::endl; | |
81 | return -EBADMSG; | |
82 | } | |
83 | auto schedule_time = item["schedule_time"].get_str(); | |
84 | ||
85 | scheduled.insert({pool_name, namespace_name, schedule_time}); | |
86 | } | |
87 | ||
88 | } catch (std::runtime_error &) { | |
89 | std::cerr << "rbd: invalid schedule JSON received" << std::endl; | |
90 | return -EBADMSG; | |
91 | } | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
96 | void dump(Formatter *f) { | |
97 | f->open_array_section("scheduled"); | |
98 | for (auto &item : scheduled) { | |
99 | f->open_object_section("item"); | |
100 | f->dump_string("pool", item.pool_name); | |
101 | f->dump_string("namespace", item.namespace_name); | |
102 | f->dump_string("schedule_time", item.schedule_time); | |
103 | f->close_section(); // item | |
104 | } | |
105 | f->close_section(); // scheduled | |
106 | } | |
107 | ||
108 | friend std::ostream& operator<<(std::ostream& os, ScheduleStatus &d); | |
109 | ||
110 | private: | |
111 | ||
112 | struct Item { | |
113 | std::string pool_name; | |
114 | std::string namespace_name; | |
115 | std::string schedule_time; | |
116 | ||
117 | Item(const std::string &pool_name, const std::string &namespace_name, | |
118 | const std::string &schedule_time) | |
119 | : pool_name(pool_name), namespace_name(namespace_name), | |
120 | schedule_time(schedule_time) { | |
121 | } | |
122 | ||
123 | bool operator<(const Item &rhs) const { | |
124 | if (pool_name != rhs.pool_name) { | |
125 | return pool_name < rhs.pool_name; | |
126 | } | |
127 | return namespace_name < rhs.namespace_name; | |
128 | } | |
129 | }; | |
130 | ||
131 | std::set<Item> scheduled; | |
132 | }; | |
133 | ||
134 | std::ostream& operator<<(std::ostream& os, ScheduleStatus &s) { | |
135 | TextTable tbl; | |
136 | tbl.define_column("POOL", TextTable::LEFT, TextTable::LEFT); | |
137 | tbl.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT); | |
138 | tbl.define_column("SCHEDULE TIME", TextTable::LEFT, TextTable::LEFT); | |
139 | ||
140 | for (auto &item : s.scheduled) { | |
141 | tbl << item.pool_name << item.namespace_name << item.schedule_time | |
142 | << TextTable::endrow; | |
143 | } | |
144 | ||
145 | os << tbl; | |
146 | return os; | |
147 | } | |
148 | ||
149 | } // anonymous namespace | |
150 | ||
151 | void get_arguments_add(po::options_description *positional, | |
152 | po::options_description *options) { | |
153 | add_level_spec_options(options, false); | |
154 | add_schedule_options(positional, true); | |
155 | } | |
156 | ||
157 | int execute_add(const po::variables_map &vm, | |
158 | const std::vector<std::string> &ceph_global_init_args) { | |
159 | std::map<std::string, std::string> args; | |
160 | ||
161 | int r = get_level_spec_args(vm, &args); | |
162 | if (r < 0) { | |
163 | return r; | |
164 | } | |
165 | r = get_schedule_args(vm, true, &args); | |
166 | if (r < 0) { | |
167 | return r; | |
168 | } | |
169 | ||
170 | librados::Rados rados; | |
171 | r = utils::init_rados(&rados); | |
172 | if (r < 0) { | |
173 | return r; | |
174 | } | |
175 | ||
176 | normalize_level_spec_args(&args); | |
177 | r = utils::mgr_command(rados, "rbd trash purge schedule add", args, | |
178 | &std::cout, &std::cerr); | |
179 | if (r < 0) { | |
180 | return r; | |
181 | } | |
182 | ||
183 | return 0; | |
184 | } | |
185 | ||
186 | void get_arguments_remove(po::options_description *positional, | |
187 | po::options_description *options) { | |
188 | add_level_spec_options(options, false); | |
189 | add_schedule_options(positional, false); | |
190 | } | |
191 | ||
192 | int execute_remove(const po::variables_map &vm, | |
193 | const std::vector<std::string> &ceph_global_init_args) { | |
194 | std::map<std::string, std::string> args; | |
195 | ||
196 | int r = get_level_spec_args(vm, &args); | |
197 | if (r < 0) { | |
198 | return r; | |
199 | } | |
200 | r = get_schedule_args(vm, false, &args); | |
201 | if (r < 0) { | |
202 | return r; | |
203 | } | |
204 | ||
205 | librados::Rados rados; | |
206 | r = utils::init_rados(&rados); | |
207 | if (r < 0) { | |
208 | return r; | |
209 | } | |
210 | ||
211 | normalize_level_spec_args(&args); | |
212 | r = utils::mgr_command(rados, "rbd trash purge schedule remove", args, | |
213 | &std::cout, &std::cerr); | |
214 | if (r < 0) { | |
215 | return r; | |
216 | } | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | void get_arguments_list(po::options_description *positional, | |
222 | po::options_description *options) { | |
223 | add_level_spec_options(options, false); | |
224 | options->add_options() | |
225 | ("recursive,R", po::bool_switch(), "list all schedules"); | |
226 | at::add_format_options(options); | |
227 | } | |
228 | ||
229 | int execute_list(const po::variables_map &vm, | |
230 | const std::vector<std::string> &ceph_global_init_args) { | |
231 | std::map<std::string, std::string> args; | |
232 | ||
233 | int r = get_level_spec_args(vm, &args); | |
234 | if (r < 0) { | |
235 | return r; | |
236 | } | |
237 | ||
238 | at::Format::Formatter formatter; | |
239 | r = utils::get_formatter(vm, &formatter); | |
240 | if (r < 0) { | |
241 | return r; | |
242 | } | |
243 | ||
244 | librados::Rados rados; | |
245 | r = utils::init_rados(&rados); | |
246 | if (r < 0) { | |
247 | return r; | |
248 | } | |
249 | ||
250 | normalize_level_spec_args(&args); | |
251 | std::stringstream out; | |
252 | r = utils::mgr_command(rados, "rbd trash purge schedule list", args, &out, | |
253 | &std::cerr); | |
254 | if (r < 0) { | |
255 | return r; | |
256 | } | |
257 | ||
258 | ScheduleList schedule_list(false); | |
259 | r = schedule_list.parse(out.str()); | |
260 | if (r < 0) { | |
261 | return r; | |
262 | } | |
263 | ||
264 | if (vm["recursive"].as<bool>()) { | |
265 | if (formatter.get()) { | |
266 | schedule_list.dump(formatter.get()); | |
267 | formatter->flush(std::cout); | |
268 | } else { | |
269 | std::cout << schedule_list; | |
270 | } | |
271 | } else { | |
272 | auto schedule = schedule_list.find(args["level_spec"]); | |
273 | if (schedule == nullptr) { | |
274 | return -ENOENT; | |
275 | } | |
276 | ||
277 | if (formatter.get()) { | |
278 | schedule->dump(formatter.get()); | |
279 | formatter->flush(std::cout); | |
280 | } else { | |
281 | std::cout << *schedule << std::endl; | |
282 | } | |
283 | } | |
284 | ||
285 | return 0; | |
286 | } | |
287 | ||
288 | void get_arguments_status(po::options_description *positional, | |
289 | po::options_description *options) { | |
290 | add_level_spec_options(options, false); | |
291 | at::add_format_options(options); | |
292 | } | |
293 | ||
294 | int execute_status(const po::variables_map &vm, | |
295 | const std::vector<std::string> &ceph_global_init_args) { | |
296 | std::map<std::string, std::string> args; | |
297 | ||
298 | int r = get_level_spec_args(vm, &args); | |
299 | if (r < 0) { | |
300 | return r; | |
301 | } | |
302 | ||
303 | at::Format::Formatter formatter; | |
304 | r = utils::get_formatter(vm, &formatter); | |
305 | if (r < 0) { | |
306 | return r; | |
307 | } | |
308 | ||
309 | librados::Rados rados; | |
310 | r = utils::init_rados(&rados); | |
311 | if (r < 0) { | |
312 | return r; | |
313 | } | |
314 | ||
315 | normalize_level_spec_args(&args); | |
316 | std::stringstream out; | |
317 | r = utils::mgr_command(rados, "rbd trash purge schedule status", args, &out, | |
318 | &std::cerr); | |
319 | ScheduleStatus schedule_status; | |
320 | r = schedule_status.parse(out.str()); | |
321 | if (r < 0) { | |
322 | return r; | |
323 | } | |
324 | ||
325 | if (formatter.get()) { | |
326 | schedule_status.dump(formatter.get()); | |
327 | formatter->flush(std::cout); | |
328 | } else { | |
329 | std::cout << schedule_status; | |
330 | } | |
331 | ||
332 | return 0; | |
333 | } | |
334 | ||
335 | Shell::SwitchArguments switched_arguments({"recursive", "R"}); | |
336 | ||
337 | Shell::Action add_action( | |
338 | {"trash", "purge", "schedule", "add"}, {}, "Add trash purge schedule.", "", | |
339 | &get_arguments_add, &execute_add); | |
340 | Shell::Action remove_action( | |
341 | {"trash", "purge", "schedule", "remove"}, | |
342 | {"trash", "purge", "schedule", "rm"}, "Remove trash purge schedule.", | |
343 | "", &get_arguments_remove, &execute_remove); | |
344 | Shell::Action list_action( | |
345 | {"trash", "purge", "schedule", "list"}, | |
346 | {"trash", "purge", "schedule", "ls"}, "List trash purge schedule.", | |
347 | "", &get_arguments_list, &execute_list); | |
348 | Shell::Action status_action( | |
349 | {"trash", "purge", "schedule", "status"}, {}, | |
350 | "Show trash purge schedule status.", "", &get_arguments_status, | |
351 | &execute_status); | |
352 | ||
353 | } // namespace trash_purge_schedule | |
354 | } // namespace action | |
355 | } // namespace rbd |