]>
git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/Schedule.cc
596408199ee23543a4fc0d52c7120397f9c6ff8c
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/Formatter.h"
5 #include "common/TextTable.h"
6 #include "common/ceph_json.h"
7 #include "tools/rbd/ArgumentTypes.h"
8 #include "tools/rbd/Schedule.h"
9 #include "tools/rbd/Utils.h"
16 namespace at
= argument_types
;
17 namespace po
= boost::program_options
;
21 int parse_schedule_name(const std::string
&name
, bool allow_images
,
22 std::string
*pool_name
, std::string
*namespace_name
,
23 std::string
*image_name
) {
25 // '', 'rbd/', 'rbd/ns/', 'rbd/image', 'rbd/ns/image'
26 std::regex
pattern("^(?:([^/]+)/(?:(?:([^/]+)/|)(?:([^/@]+))?)?)?$");
28 if (!std::regex_match(name
, match
, pattern
)) {
32 if (match
[1].matched
) {
33 *pool_name
= match
[1];
38 if (match
[2].matched
) {
39 *namespace_name
= match
[2];
40 } else if (match
[3].matched
) {
43 *namespace_name
= "-";
46 if (match
[3].matched
) {
50 *image_name
= match
[3];
58 } // anonymous namespace
60 void add_level_spec_options(po::options_description
*options
,
62 at::add_pool_option(options
, at::ARGUMENT_MODIFIER_NONE
);
63 at::add_namespace_option(options
, at::ARGUMENT_MODIFIER_NONE
);
65 at::add_image_option(options
, at::ARGUMENT_MODIFIER_NONE
);
69 int get_level_spec_args(const po::variables_map
&vm
,
70 std::map
<std::string
, std::string
> *args
) {
71 if (vm
.count(at::IMAGE_NAME
)) {
72 std::string pool_name
;
73 std::string namespace_name
;
74 std::string image_name
;
76 int r
= utils::extract_spec(vm
[at::IMAGE_NAME
].as
<std::string
>(),
77 &pool_name
, &namespace_name
, &image_name
,
78 nullptr, utils::SPEC_VALIDATION_FULL
);
83 if (!pool_name
.empty()) {
84 if (vm
.count(at::POOL_NAME
)) {
85 std::cerr
<< "rbd: pool is specified both via pool and image options"
89 if (vm
.count(at::NAMESPACE_NAME
)) {
90 std::cerr
<< "rbd: namespace is specified both via namespace and image"
91 << " options" << std::endl
;
96 if (vm
.count(at::POOL_NAME
)) {
97 pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
98 } else if (pool_name
.empty()) {
99 pool_name
= utils::get_default_pool_name();
102 if (vm
.count(at::NAMESPACE_NAME
)) {
103 namespace_name
= vm
[at::NAMESPACE_NAME
].as
<std::string
>();
106 if (namespace_name
.empty()) {
107 (*args
)["level_spec"] = pool_name
+ "/" + image_name
;
109 (*args
)["level_spec"] = pool_name
+ "/" + namespace_name
+ "/" +
115 if (vm
.count(at::NAMESPACE_NAME
)) {
116 std::string pool_name
;
117 std::string namespace_name
;
119 if (vm
.count(at::POOL_NAME
)) {
120 pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
122 pool_name
= utils::get_default_pool_name();
125 namespace_name
= vm
[at::NAMESPACE_NAME
].as
<std::string
>();
127 (*args
)["level_spec"] = pool_name
+ "/" + namespace_name
+ "/";
132 if (vm
.count(at::POOL_NAME
)) {
133 std::string pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
135 (*args
)["level_spec"] = pool_name
+ "/";
140 (*args
)["level_spec"] = "";
145 void add_schedule_options(po::options_description
*positional
) {
146 positional
->add_options()
147 ("interval", "schedule interval");
148 positional
->add_options()
149 ("start-time", "schedule start time");
152 int get_schedule_args(const po::variables_map
&vm
, bool mandatory
,
153 std::map
<std::string
, std::string
> *args
) {
154 size_t arg_index
= 0;
156 std::string interval
= utils::get_positional_argument(vm
, arg_index
++);
157 if (interval
.empty()) {
159 std::cerr
<< "rbd: missing 'interval' argument" << std::endl
;
164 (*args
)["interval"] = interval
;
166 std::string start_time
= utils::get_positional_argument(vm
, arg_index
++);
167 if (!start_time
.empty()) {
168 (*args
)["start_time"] = start_time
;
174 int Schedule::parse(json_spirit::mValue
&schedule_val
) {
175 if (schedule_val
.type() != json_spirit::array_type
) {
176 std::cerr
<< "rbd: unexpected schedule JSON received: "
177 << "schedule is not array" << std::endl
;
182 for (auto &item_val
: schedule_val
.get_array()) {
183 if (item_val
.type() != json_spirit::obj_type
) {
184 std::cerr
<< "rbd: unexpected schedule JSON received: "
185 << "schedule item is not object" << std::endl
;
189 auto &item
= item_val
.get_obj();
191 if (item
["interval"].type() != json_spirit::str_type
) {
192 std::cerr
<< "rbd: unexpected schedule JSON received: "
193 << "interval is not string" << std::endl
;
196 auto interval
= item
["interval"].get_str();
198 std::string start_time
;
199 if (item
["start_time"].type() == json_spirit::str_type
) {
200 start_time
= item
["start_time"].get_str();
203 items
.push_back({interval
, start_time
});
206 } catch (std::runtime_error
&) {
207 std::cerr
<< "rbd: invalid schedule JSON received" << std::endl
;
214 void Schedule::dump(ceph::Formatter
*f
) {
215 f
->open_array_section("items");
216 for (auto &item
: items
) {
217 f
->open_object_section("item");
218 f
->dump_string("interval", item
.first
);
219 f
->dump_string("start_time", item
.second
);
220 f
->close_section(); // item
222 f
->close_section(); // items
225 std::ostream
& operator<<(std::ostream
& os
, Schedule
&s
) {
226 std::string delimiter
;
227 for (auto &item
: s
.items
) {
228 os
<< delimiter
<< "every " << item
.first
;
229 if (!item
.second
.empty()) {
230 os
<< " starting at " << item
.second
;
237 int ScheduleList::parse(const std::string
&list
) {
238 json_spirit::mValue json_root
;
239 if (!json_spirit::read(list
, json_root
)) {
240 std::cerr
<< "rbd: invalid schedule list JSON received" << std::endl
;
245 for (auto &[id
, schedule_val
] : json_root
.get_obj()) {
246 if (schedule_val
.type() != json_spirit::obj_type
) {
247 std::cerr
<< "rbd: unexpected schedule list JSON received: "
248 << "schedule_val is not object" << std::endl
;
251 auto &schedule
= schedule_val
.get_obj();
252 if (schedule
["name"].type() != json_spirit::str_type
) {
253 std::cerr
<< "rbd: unexpected schedule list JSON received: "
254 << "schedule name is not string" << std::endl
;
257 auto name
= schedule
["name"].get_str();
259 if (schedule
["schedule"].type() != json_spirit::array_type
) {
260 std::cerr
<< "rbd: unexpected schedule list JSON received: "
261 << "schedule is not array" << std::endl
;
266 int r
= s
.parse(schedule
["schedule"]);
272 } catch (std::runtime_error
&) {
273 std::cerr
<< "rbd: invalid schedule list JSON received" << std::endl
;
280 Schedule
*ScheduleList::find(const std::string
&name
) {
281 auto it
= schedules
.find(name
);
282 if (it
== schedules
.end()) {
289 void ScheduleList::dump(ceph::Formatter
*f
) {
290 f
->open_array_section("schedules");
291 for (auto &[name
, s
] : schedules
) {
292 std::string pool_name
;
293 std::string namespace_name
;
294 std::string image_name
;
296 int r
= parse_schedule_name(name
, allow_images
, &pool_name
, &namespace_name
,
302 f
->open_object_section("schedule");
303 f
->dump_string("pool", pool_name
);
304 f
->dump_string("namespace", namespace_name
);
306 f
->dump_string("image", image_name
);
314 std::ostream
& operator<<(std::ostream
& os
, ScheduleList
&l
) {
316 tbl
.define_column("POOL", TextTable::LEFT
, TextTable::LEFT
);
317 tbl
.define_column("NAMESPACE", TextTable::LEFT
, TextTable::LEFT
);
318 if (l
.allow_images
) {
319 tbl
.define_column("IMAGE", TextTable::LEFT
, TextTable::LEFT
);
321 tbl
.define_column("SCHEDULE", TextTable::LEFT
, TextTable::LEFT
);
323 for (auto &[name
, s
] : l
.schedules
) {
324 std::string pool_name
;
325 std::string namespace_name
;
326 std::string image_name
;
328 int r
= parse_schedule_name(name
, l
.allow_images
, &pool_name
,
329 &namespace_name
, &image_name
);
334 std::stringstream ss
;
337 tbl
<< pool_name
<< namespace_name
;
338 if (l
.allow_images
) {
341 tbl
<< ss
.str() << TextTable::endrow
;