]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/TrashPurgeSchedule.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / tools / rbd / action / TrashPurgeSchedule.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 <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("namespce", 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);
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 r = utils::mgr_command(rados, "rbd trash purge schedule add", args,
177 &std::cout, &std::cerr);
178 if (r < 0) {
179 return r;
180 }
181
182 return 0;
183 }
184
185 void get_arguments_remove(po::options_description *positional,
186 po::options_description *options) {
187 add_level_spec_options(options, false);
188 add_schedule_options(positional);
189 }
190
191 int execute_remove(const po::variables_map &vm,
192 const std::vector<std::string> &ceph_global_init_args) {
193 std::map<std::string, std::string> args;
194
195 int r = get_level_spec_args(vm, &args);
196 if (r < 0) {
197 return r;
198 }
199 r = get_schedule_args(vm, false, &args);
200 if (r < 0) {
201 return r;
202 }
203
204 librados::Rados rados;
205 r = utils::init_rados(&rados);
206 if (r < 0) {
207 return r;
208 }
209
210 r = utils::mgr_command(rados, "rbd trash purge schedule remove", args,
211 &std::cout, &std::cerr);
212 if (r < 0) {
213 return r;
214 }
215
216 return 0;
217 }
218
219 void get_arguments_list(po::options_description *positional,
220 po::options_description *options) {
221 add_level_spec_options(options, false);
222 options->add_options()
223 ("recursive,R", po::bool_switch(), "list all schedules");
224 at::add_format_options(options);
225 }
226
227 int execute_list(const po::variables_map &vm,
228 const std::vector<std::string> &ceph_global_init_args) {
229 std::map<std::string, std::string> args;
230
231 int r = get_level_spec_args(vm, &args);
232 if (r < 0) {
233 return r;
234 }
235
236 at::Format::Formatter formatter;
237 r = utils::get_formatter(vm, &formatter);
238 if (r < 0) {
239 return r;
240 }
241
242 librados::Rados rados;
243 r = utils::init_rados(&rados);
244 if (r < 0) {
245 return r;
246 }
247
248 std::stringstream out;
249 r = utils::mgr_command(rados, "rbd trash purge schedule list", args, &out,
250 &std::cerr);
251 if (r < 0) {
252 return r;
253 }
254
255 ScheduleList schedule_list(false);
256 r = schedule_list.parse(out.str());
257 if (r < 0) {
258 return r;
259 }
260
261 if (vm["recursive"].as<bool>()) {
262 if (formatter.get()) {
263 schedule_list.dump(formatter.get());
264 formatter->flush(std::cout);
265 } else {
266 std::cout << schedule_list;
267 }
268 } else {
269 auto schedule = schedule_list.find(args["level_spec"]);
270 if (schedule == nullptr) {
271 return -ENOENT;
272 }
273
274 if (formatter.get()) {
275 schedule->dump(formatter.get());
276 formatter->flush(std::cout);
277 } else {
278 std::cout << *schedule << std::endl;
279 }
280 }
281
282 return 0;
283 }
284
285 void get_arguments_status(po::options_description *positional,
286 po::options_description *options) {
287 add_level_spec_options(options, false);
288 at::add_format_options(options);
289 }
290
291 int execute_status(const po::variables_map &vm,
292 const std::vector<std::string> &ceph_global_init_args) {
293 std::map<std::string, std::string> args;
294
295 int r = get_level_spec_args(vm, &args);
296 if (r < 0) {
297 return r;
298 }
299
300 at::Format::Formatter formatter;
301 r = utils::get_formatter(vm, &formatter);
302 if (r < 0) {
303 return r;
304 }
305
306 librados::Rados rados;
307 r = utils::init_rados(&rados);
308 if (r < 0) {
309 return r;
310 }
311
312 std::stringstream out;
313 r = utils::mgr_command(rados, "rbd trash purge schedule status", args, &out,
314 &std::cerr);
315 ScheduleStatus schedule_status;
316 r = schedule_status.parse(out.str());
317 if (r < 0) {
318 return r;
319 }
320
321 if (formatter.get()) {
322 schedule_status.dump(formatter.get());
323 formatter->flush(std::cout);
324 } else {
325 std::cout << schedule_status;
326 }
327
328 return 0;
329 }
330
331 Shell::Action add_action(
332 {"trash", "purge", "schedule", "add"}, {}, "Add trash purge schedule.", "",
333 &get_arguments_add, &execute_add);
334 Shell::Action remove_action(
335 {"trash", "purge", "schedule", "remove"},
336 {"trash", "purge", "schedule", "rm"}, "Remove trash purge schedule.",
337 "", &get_arguments_remove, &execute_remove);
338 Shell::Action list_action(
339 {"trash", "purge", "schedule", "list"},
340 {"trash", "purge", "schedule", "ls"}, "List trash purge schedule.",
341 "", &get_arguments_list, &execute_list);
342 Shell::Action status_action(
343 {"trash", "purge", "schedule", "status"}, {},
344 "Show trash purge schedule status.", "", &get_arguments_status,
345 &execute_status);
346
347 } // namespace trash_purge_schedule
348 } // namespace action
349 } // namespace rbd