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