]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/ArgumentTypes.cc
update sources to v12.2.1
[ceph.git] / ceph / src / tools / rbd / ArgumentTypes.cc
CommitLineData
7c673cae
FG
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/Shell.h"
6#include "tools/rbd/Utils.h"
7#include "include/rbd/features.h"
8#include "common/config.h"
9#include "common/strtol.h"
10#include "common/Formatter.h"
11#include "global/global_context.h"
12#include <iostream>
13#include <boost/tokenizer.hpp>
14
15namespace rbd {
16namespace argument_types {
17
18namespace po = boost::program_options;
19
20const std::map<uint64_t, std::string> ImageFeatures::FEATURE_MAPPING = {
21 {RBD_FEATURE_LAYERING, RBD_FEATURE_NAME_LAYERING},
22 {RBD_FEATURE_STRIPINGV2, RBD_FEATURE_NAME_STRIPINGV2},
23 {RBD_FEATURE_EXCLUSIVE_LOCK, RBD_FEATURE_NAME_EXCLUSIVE_LOCK},
24 {RBD_FEATURE_OBJECT_MAP, RBD_FEATURE_NAME_OBJECT_MAP},
25 {RBD_FEATURE_FAST_DIFF, RBD_FEATURE_NAME_FAST_DIFF},
26 {RBD_FEATURE_DEEP_FLATTEN, RBD_FEATURE_NAME_DEEP_FLATTEN},
27 {RBD_FEATURE_JOURNALING, RBD_FEATURE_NAME_JOURNALING},
28 {RBD_FEATURE_DATA_POOL, RBD_FEATURE_NAME_DATA_POOL},
29};
30
31Format::Formatter Format::create_formatter(bool pretty) const {
32 if (value == "json") {
33 return Formatter(new JSONFormatter(pretty));
34 } else if (value == "xml") {
35 return Formatter(new XMLFormatter(pretty));
36 }
37 return Formatter();
38}
39
40std::string get_name_prefix(ArgumentModifier modifier) {
41 switch (modifier) {
42 case ARGUMENT_MODIFIER_SOURCE:
43 return SOURCE_PREFIX;
44 case ARGUMENT_MODIFIER_DEST:
45 return DEST_PREFIX;
46 default:
47 return "";
48 }
49}
50
51std::string get_description_prefix(ArgumentModifier modifier) {
52 switch (modifier) {
53 case ARGUMENT_MODIFIER_SOURCE:
54 return "source ";
55 case ARGUMENT_MODIFIER_DEST:
56 return "destination ";
57 default:
58 return "";
59 }
60}
61
62void add_special_pool_option(po::options_description *opt,
63 std::string prefix) {
64 std::string name = prefix + "-" + POOL_NAME;
65 std::string description = prefix + " pool name";
66
67 opt->add_options()
68 (name.c_str(), po::value<std::string>(), description.c_str());
69}
70
71void add_pool_option(po::options_description *opt,
72 ArgumentModifier modifier,
73 const std::string &desc_suffix) {
74 std::string name = POOL_NAME + ",p";
75 std::string description = "pool name";
76 switch (modifier) {
77 case ARGUMENT_MODIFIER_NONE:
78 break;
79 case ARGUMENT_MODIFIER_SOURCE:
80 description = "source " + description;
81 break;
82 case ARGUMENT_MODIFIER_DEST:
83 name = DEST_POOL_NAME;
84 description = "destination " + description;
85 break;
86 }
87 description += desc_suffix;
88
89 // TODO add validator
90 opt->add_options()
91 (name.c_str(), po::value<std::string>(), description.c_str());
92}
93
94void add_image_option(po::options_description *opt,
95 ArgumentModifier modifier,
96 const std::string &desc_suffix) {
97 std::string name = IMAGE_NAME;
98 std::string description = "image name";
99 switch (modifier) {
100 case ARGUMENT_MODIFIER_NONE:
101 break;
102 case ARGUMENT_MODIFIER_SOURCE:
103 description = "source " + description;
104 break;
105 case ARGUMENT_MODIFIER_DEST:
106 name = DEST_IMAGE_NAME;
107 description = "destination " + description;
108 break;
109 }
110 description += desc_suffix;
111
112 // TODO add validator
113 opt->add_options()
114 (name.c_str(), po::value<std::string>(), description.c_str());
115}
116
117void add_image_id_option(po::options_description *opt,
118 const std::string &desc_suffix) {
119 std::string name = IMAGE_ID;
120 std::string description = "image id";
121 description += desc_suffix;
122
123 // TODO add validator
124 opt->add_options()
125 (name.c_str(), po::value<std::string>(), description.c_str());
126}
127
128void add_group_option(po::options_description *opt,
129 ArgumentModifier modifier,
130 const std::string &desc_suffix) {
131 std::string name = GROUP_NAME;
132 std::string description = "group name";
133 switch (modifier) {
134 case ARGUMENT_MODIFIER_NONE:
135 break;
136 case ARGUMENT_MODIFIER_SOURCE:
137 description = "source " + description;
138 break;
139 case ARGUMENT_MODIFIER_DEST:
140 name = DEST_GROUP_NAME;
141 description = "destination " + description;
142 break;
143 }
144 description += desc_suffix;
145
146 // TODO add validator
147 opt->add_options()
148 (name.c_str(), po::value<std::string>(), description.c_str());
149}
150
151void add_snap_option(po::options_description *opt,
152 ArgumentModifier modifier) {
153
154 std::string name = SNAPSHOT_NAME;
155 std::string description = "snapshot name";
156 switch (modifier) {
157 case ARGUMENT_MODIFIER_NONE:
158 break;
159 case ARGUMENT_MODIFIER_DEST:
160 name = DEST_SNAPSHOT_NAME;
161 description = "destination " + description;
162 break;
163 case ARGUMENT_MODIFIER_SOURCE:
164 description = "source " + description;
165 break;
166 }
167
168 // TODO add validator
169 opt->add_options()
170 (name.c_str(), po::value<std::string>(), description.c_str());
171}
172
173void add_journal_option(po::options_description *opt,
174 ArgumentModifier modifier,
175 const std::string &desc_suffix) {
176 std::string name = JOURNAL_NAME;
177 std::string description = "journal name";
178 switch (modifier) {
179 case ARGUMENT_MODIFIER_NONE:
180 break;
181 case ARGUMENT_MODIFIER_SOURCE:
182 description = "source " + description;
183 break;
184 case ARGUMENT_MODIFIER_DEST:
185 name = DEST_JOURNAL_NAME;
186 description = "destination " + description;
187 break;
188 }
189 description += desc_suffix;
190
191 // TODO add validator
192 opt->add_options()
193 (name.c_str(), po::value<std::string>(), description.c_str());
194}
195
196void add_pool_options(boost::program_options::options_description *pos,
197 boost::program_options::options_description *opt) {
198 pos->add_options()
199 ("pool-name", "pool name");
200 opt->add_options()
201 ((POOL_NAME + ",p").c_str(), po::value<std::string>(), "pool name");
202}
203
204void add_image_spec_options(po::options_description *pos,
205 po::options_description *opt,
206 ArgumentModifier modifier) {
207 pos->add_options()
208 ((get_name_prefix(modifier) + IMAGE_SPEC).c_str(),
209 (get_description_prefix(modifier) + "image specification\n" +
210 "(example: [<pool-name>/]<image-name>)").c_str());
211 add_pool_option(opt, modifier);
212 add_image_option(opt, modifier);
213}
214
215void add_group_spec_options(po::options_description *pos,
216 po::options_description *opt,
217 ArgumentModifier modifier) {
218 pos->add_options()
219 ((get_name_prefix(modifier) + GROUP_SPEC).c_str(),
220 (get_description_prefix(modifier) + "group specification\n" +
221 "(example: [<pool-name>/]<group-name>)").c_str());
222 add_pool_option(opt, modifier);
223 add_group_option(opt, modifier);
224}
225
226void add_snap_spec_options(po::options_description *pos,
227 po::options_description *opt,
228 ArgumentModifier modifier) {
229 pos->add_options()
230 ((get_name_prefix(modifier) + SNAPSHOT_SPEC).c_str(),
231 (get_description_prefix(modifier) + "snapshot specification\n" +
232 "(example: [<pool-name>/]<image-name>@<snapshot-name>)").c_str());
233 add_pool_option(opt, modifier);
234 add_image_option(opt, modifier);
235 add_snap_option(opt, modifier);
236}
237
238void add_image_or_snap_spec_options(po::options_description *pos,
239 po::options_description *opt,
240 ArgumentModifier modifier) {
241 pos->add_options()
242 ((get_name_prefix(modifier) + IMAGE_OR_SNAPSHOT_SPEC).c_str(),
243 (get_description_prefix(modifier) + "image or snapshot specification\n" +
244 "(example: [<pool-name>/]<image-name>[@<snap-name>])").c_str());
245 add_pool_option(opt, modifier);
246 add_image_option(opt, modifier);
247 add_snap_option(opt, modifier);
248}
249
250void add_journal_spec_options(po::options_description *pos,
251 po::options_description *opt,
252 ArgumentModifier modifier) {
253
254 pos->add_options()
255 ((get_name_prefix(modifier) + JOURNAL_SPEC).c_str(),
256 (get_description_prefix(modifier) + "journal specification\n" +
257 "(example: [<pool-name>/]<journal-name>)").c_str());
258 add_pool_option(opt, modifier);
259 add_image_option(opt, modifier);
260 add_journal_option(opt, modifier);
261}
262
263void add_create_image_options(po::options_description *opt,
264 bool include_format) {
265 // TODO get default image format from conf
266 if (include_format) {
267 opt->add_options()
268 (IMAGE_FORMAT.c_str(), po::value<ImageFormat>(),
269 "image format [1 (deprecated) or 2]")
270 (IMAGE_NEW_FORMAT.c_str(),
271 po::value<ImageNewFormat>()->zero_tokens(),
272 "use image format 2\n(deprecated)");
273 }
274
275 opt->add_options()
276 (IMAGE_ORDER.c_str(), po::value<ImageOrder>(),
277 "object order [12 <= order <= 25]")
278 (IMAGE_OBJECT_SIZE.c_str(), po::value<ImageObjectSize>(),
279 "object size in B/K/M [4K <= object size <= 32M]")
280 (IMAGE_FEATURES.c_str(), po::value<ImageFeatures>()->composing(),
281 ("image features\n" + get_short_features_help(true)).c_str())
282 (IMAGE_SHARED.c_str(), po::bool_switch(), "shared image")
283 (IMAGE_STRIPE_UNIT.c_str(), po::value<ImageObjectSize>(), "stripe unit in B/K/M")
284 (IMAGE_STRIPE_COUNT.c_str(), po::value<uint64_t>(), "stripe count")
285 (IMAGE_DATA_POOL.c_str(), po::value<std::string>(), "data pool");
286
287 add_create_journal_options(opt);
288}
289
290void add_create_journal_options(po::options_description *opt) {
291 opt->add_options()
292 (JOURNAL_SPLAY_WIDTH.c_str(), po::value<uint64_t>(),
293 "number of active journal objects")
294 (JOURNAL_OBJECT_SIZE.c_str(), po::value<JournalObjectSize>(),
295 "size of journal objects")
296 (JOURNAL_POOL.c_str(), po::value<std::string>(),
297 "pool for journal objects");
298}
299
300void add_size_option(boost::program_options::options_description *opt) {
301 opt->add_options()
302 ((IMAGE_SIZE + ",s").c_str(), po::value<ImageSize>()->required(),
31f18b77 303 "image size (in M/G/T) [default: M]");
7c673cae
FG
304}
305
306void add_sparse_size_option(boost::program_options::options_description *opt) {
307 opt->add_options()
308 (IMAGE_SPARSE_SIZE.c_str(), po::value<ImageObjectSize>(),
309 "sparse size in B/K/M [default: 4K]");
310}
311
312void add_path_options(boost::program_options::options_description *pos,
313 boost::program_options::options_description *opt,
314 const std::string &description) {
315 pos->add_options()
316 (PATH_NAME.c_str(), po::value<std::string>(), description.c_str());
317 opt->add_options()
318 (PATH.c_str(), po::value<std::string>(), description.c_str());
319}
320
321void add_limit_option(po::options_description *opt) {
322 std::string description = "maximum allowed snapshot count";
323
324 opt->add_options()
325 (LIMIT.c_str(), po::value<uint64_t>(), description.c_str());
326}
327
328void add_no_progress_option(boost::program_options::options_description *opt) {
329 opt->add_options()
330 (NO_PROGRESS.c_str(), po::bool_switch(), "disable progress output");
331}
332
333void add_format_options(boost::program_options::options_description *opt) {
334 opt->add_options()
181888fb 335 (FORMAT.c_str(), po::value<Format>(), "output format (plain, json, or xml) [default: plain]")
7c673cae
FG
336 (PRETTY_FORMAT.c_str(), po::bool_switch(),
337 "pretty formatting (json and xml)");
338}
339
340void add_verbose_option(boost::program_options::options_description *opt) {
341 opt->add_options()
342 (VERBOSE.c_str(), po::bool_switch(), "be verbose");
343}
344
345void add_no_error_option(boost::program_options::options_description *opt) {
346 opt->add_options()
347 (NO_ERROR.c_str(), po::bool_switch(), "continue after error");
348}
349
350void add_export_format_option(boost::program_options::options_description *opt) {
351 opt->add_options()
352 ("export-format", po::value<ExportFormat>(), "format of image file");
353}
354
355std::string get_short_features_help(bool append_suffix) {
356 std::ostringstream oss;
357 bool first_feature = true;
358 oss << "[";
359 for (auto &pair : ImageFeatures::FEATURE_MAPPING) {
360 if (!first_feature) {
361 oss << ", ";
362 }
363 first_feature = false;
364
365 std::string suffix;
366 if (append_suffix) {
367 if ((pair.first & rbd::utils::get_rbd_default_features(g_ceph_context)) != 0) {
368 suffix += "+";
369 }
370 if ((pair.first & RBD_FEATURES_MUTABLE) != 0) {
371 suffix += "*";
372 } else if ((pair.first & RBD_FEATURES_DISABLE_ONLY) != 0) {
373 suffix += "-";
374 }
375 if (!suffix.empty()) {
376 suffix = "(" + suffix + ")";
377 }
378 }
379 oss << pair.second << suffix;
380 }
381 oss << "]";
382 return oss.str();
383}
384
385std::string get_long_features_help() {
386 std::ostringstream oss;
387 oss << "Image Features:" << std::endl
388 << " (*) supports enabling/disabling on existing images" << std::endl
389 << " (-) supports disabling-only on existing images" << std::endl
390 << " (+) enabled by default for new images if features not specified"
391 << std::endl;
392 return oss.str();
393}
394
395void validate(boost::any& v, const std::vector<std::string>& values,
396 ImageSize *target_type, int) {
397 po::validators::check_first_occurrence(v);
398 const std::string &s = po::validators::get_single_string(values);
399
400 std::string parse_error;
401 uint64_t size = strict_sistrtoll(s.c_str(), &parse_error);
402 if (!parse_error.empty()) {
403 throw po::validation_error(po::validation_error::invalid_option_value);
404 }
405
406 //NOTE: We can remove below given three lines of code once all applications,
407 //which use this CLI will adopt B/K/M/G/T/P/E with size value
408 if (isdigit(*s.rbegin())) {
409 size = size << 20; // Default MB to Bytes
410 }
411 v = boost::any(size);
412}
413
414void validate(boost::any& v, const std::vector<std::string>& values,
415 ImageOrder *target_type, int dummy) {
416 po::validators::check_first_occurrence(v);
417 const std::string &s = po::validators::get_single_string(values);
418 try {
419 uint64_t order = boost::lexical_cast<uint64_t>(s);
420 if (order >= 12 && order <= 25) {
421 v = boost::any(order);
422 return;
423 }
424 } catch (const boost::bad_lexical_cast &) {
425 }
426 throw po::validation_error(po::validation_error::invalid_option_value);
427}
428
429void validate(boost::any& v, const std::vector<std::string>& values,
430 ImageObjectSize *target_type, int dummy) {
431 po::validators::check_first_occurrence(v);
432 const std::string &s = po::validators::get_single_string(values);
433
434 std::string parse_error;
435 uint64_t objectsize = strict_sistrtoll(s.c_str(), &parse_error);
436 if (!parse_error.empty()) {
437 throw po::validation_error(po::validation_error::invalid_option_value);
438 }
439 v = boost::any(objectsize);
440}
441
442void validate(boost::any& v, const std::vector<std::string>& values,
443 ImageFormat *target_type, int dummy) {
444 po::validators::check_first_occurrence(v);
445 const std::string &s = po::validators::get_single_string(values);
446 try {
447 uint32_t format = boost::lexical_cast<uint32_t>(s);
448 if (format == 1 || format == 2) {
449 v = boost::any(format);
450 return;
451 }
452 } catch (const boost::bad_lexical_cast &) {
453 }
454 throw po::validation_error(po::validation_error::invalid_option_value);
455}
456
457void validate(boost::any& v, const std::vector<std::string>& values,
458 ImageNewFormat *target_type, int dummy) {
459 std::cout << "rbd: --new-format is deprecated, use --image-format"
460 << std::endl;
461 v = boost::any(true);
462}
463
464void validate(boost::any& v, const std::vector<std::string>& values,
465 ImageFeatures *target_type, int) {
466 if (v.empty()) {
467 v = boost::any(static_cast<uint64_t>(0));
468 }
469
470 uint64_t &features = boost::any_cast<uint64_t &>(v);
471 for (auto &value : values) {
472 boost::char_separator<char> sep(",");
473 boost::tokenizer<boost::char_separator<char> > tok(value, sep);
474 for (auto &token : tok) {
475 bool matched = false;
476 for (auto &it : ImageFeatures::FEATURE_MAPPING) {
477 if (token == it.second) {
478 features |= it.first;
479 matched = true;
480 break;
481 }
482 }
483
484 if (!matched) {
485 throw po::validation_error(po::validation_error::invalid_option_value);
486 }
487 }
488 }
489}
490
491void validate(boost::any& v, const std::vector<std::string>& values,
492 Format *target_type, int) {
493 po::validators::check_first_occurrence(v);
494 const std::string &s = po::validators::get_single_string(values);
495 if (s == "plain" || s == "json" || s == "xml") {
496 v = boost::any(Format(s));
497 } else {
498 throw po::validation_error(po::validation_error::invalid_option_value);
499 }
500}
501
502void validate(boost::any& v, const std::vector<std::string>& values,
503 JournalObjectSize *target_type, int) {
504 po::validators::check_first_occurrence(v);
505 const std::string &s = po::validators::get_single_string(values);
506
507 std::string parse_error;
508 uint64_t size = strict_sistrtoll(s.c_str(), &parse_error);
509 if (parse_error.empty() && (size >= (1 << 12))) {
510 v = boost::any(size);
511 return;
512 }
513 throw po::validation_error(po::validation_error::invalid_option_value);
514}
515
516void validate(boost::any& v, const std::vector<std::string>& values,
517 ExportFormat *target_type, int) {
518 po::validators::check_first_occurrence(v);
519 const std::string &s = po::validators::get_single_string(values);
520
521 std::string parse_error;
522 uint64_t format = strict_sistrtoll(s.c_str(), &parse_error);
523 if (!parse_error.empty() || (format != 1 && format != 2)) {
524 throw po::validation_error(po::validation_error::invalid_option_value);
525 }
526
527 v = boost::any(format);
528}
529
530void validate(boost::any& v, const std::vector<std::string>& values,
531 Secret *target_type, int) {
532 std::cerr << "rbd: --secret is deprecated, use --keyfile" << std::endl;
533
534 po::validators::check_first_occurrence(v);
535 const std::string &s = po::validators::get_single_string(values);
536 g_conf->set_val_or_die("keyfile", s.c_str());
537 v = boost::any(s);
538}
539
540} // namespace argument_types
541} // namespace rbd