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