1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
13 #include <boost/tokenizer.hpp>
16 namespace argument_types
{
18 namespace po
= boost::program_options
;
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
},
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
));
44 std::string
get_name_prefix(ArgumentModifier modifier
) {
46 case ARGUMENT_MODIFIER_SOURCE
:
48 case ARGUMENT_MODIFIER_DEST
:
55 std::string
get_description_prefix(ArgumentModifier modifier
) {
57 case ARGUMENT_MODIFIER_SOURCE
:
59 case ARGUMENT_MODIFIER_DEST
:
60 return "destination ";
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";
72 case ARGUMENT_MODIFIER_NONE
:
74 case ARGUMENT_MODIFIER_SOURCE
:
75 description
= "source " + description
;
77 case ARGUMENT_MODIFIER_DEST
:
78 name
= DEST_POOL_NAME
;
79 description
= "destination " + description
;
82 description
+= desc_suffix
;
86 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
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";
94 case ARGUMENT_MODIFIER_NONE
:
96 case ARGUMENT_MODIFIER_SOURCE
:
97 description
= "source " + description
;
99 case ARGUMENT_MODIFIER_DEST
:
100 name
= DEST_NAMESPACE_NAME
;
101 description
= "destination " + description
;
105 // TODO add validator
107 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
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";
116 case ARGUMENT_MODIFIER_NONE
:
118 case ARGUMENT_MODIFIER_SOURCE
:
119 description
= "source " + description
;
121 case ARGUMENT_MODIFIER_DEST
:
122 name
= DEST_IMAGE_NAME
;
123 description
= "destination " + description
;
126 description
+= desc_suffix
;
128 // TODO add validator
130 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
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
;
139 // TODO add validator
141 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
144 void add_snap_option(po::options_description
*opt
,
145 ArgumentModifier modifier
) {
147 std::string name
= SNAPSHOT_NAME
;
148 std::string description
= "snapshot name";
150 case ARGUMENT_MODIFIER_NONE
:
152 case ARGUMENT_MODIFIER_DEST
:
153 name
= DEST_SNAPSHOT_NAME
;
154 description
= "destination " + description
;
156 case ARGUMENT_MODIFIER_SOURCE
:
157 description
= "source " + description
;
161 // TODO add validator
163 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
166 void add_snap_id_option(po::options_description
*opt
) {
168 (SNAPSHOT_ID
.c_str(), po::value
<uint64_t>(), "snapshot id");
171 void add_pool_options(boost::program_options::options_description
*pos
,
172 boost::program_options::options_description
*opt
,
173 bool namespaces_supported
) {
175 ((POOL_NAME
+ ",p").c_str(), po::value
<std::string
>(), "pool name");
176 if (namespaces_supported
) {
177 add_namespace_option(opt
, ARGUMENT_MODIFIER_NONE
);
179 ("pool-spec", "pool specification\n"
180 "(example: <pool-name>[/<namespace>]");
183 ("pool-name", "pool name");
187 void add_image_spec_options(po::options_description
*pos
,
188 po::options_description
*opt
,
189 ArgumentModifier modifier
) {
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
);
199 void add_snap_spec_options(po::options_description
*pos
,
200 po::options_description
*opt
,
201 ArgumentModifier modifier
) {
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
);
212 void add_image_or_snap_spec_options(po::options_description
*pos
,
213 po::options_description
*opt
,
214 ArgumentModifier modifier
) {
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
);
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
) {
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]");
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]");
251 add_create_journal_options(opt
);
254 void add_create_journal_options(po::options_description
*opt
) {
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");
264 void add_size_option(boost::program_options::options_description
*opt
) {
266 ((IMAGE_SIZE
+ ",s").c_str(), po::value
<ImageSize
>()->required(),
267 "image size (in M/G/T) [default: M]");
270 void add_sparse_size_option(boost::program_options::options_description
*opt
) {
272 (IMAGE_SPARSE_SIZE
.c_str(), po::value
<ImageObjectSize
>(),
273 "sparse size in B/K/M [default: 4K]");
276 void add_path_options(boost::program_options::options_description
*pos
,
277 boost::program_options::options_description
*opt
,
278 const std::string
&description
) {
280 (PATH_NAME
.c_str(), po::value
<std::string
>(), description
.c_str());
282 (PATH
.c_str(), po::value
<std::string
>(), description
.c_str());
285 void add_limit_option(po::options_description
*opt
) {
286 std::string description
= "maximum allowed snapshot count";
289 (LIMIT
.c_str(), po::value
<uint64_t>(), description
.c_str());
292 void add_no_progress_option(boost::program_options::options_description
*opt
) {
294 (NO_PROGRESS
.c_str(), po::bool_switch(), "disable progress output");
297 void add_format_options(boost::program_options::options_description
*opt
) {
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)");
304 void add_verbose_option(boost::program_options::options_description
*opt
) {
306 (VERBOSE
.c_str(), po::bool_switch(), "be verbose");
309 void add_no_error_option(boost::program_options::options_description
*opt
) {
311 (NO_ERR
.c_str(), po::bool_switch(), "continue after error");
314 void add_export_format_option(boost::program_options::options_description
*opt
) {
316 ("export-format", po::value
<ExportFormat
>(), "format of image file");
319 void add_flatten_option(boost::program_options::options_description
*opt
) {
321 (IMAGE_FLATTEN
.c_str(), po::bool_switch(),
322 "fill clone with parent data (make it independent)");
325 void add_snap_create_options(po::options_description
*opt
) {
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");
332 void add_encryption_options(boost::program_options::options_description
*opt
) {
334 (ENCRYPTION_FORMAT
.c_str(),
335 po::value
<std::vector
<EncryptionFormat
>>(),
336 "encryption format (luks, luks1, luks2) [default: luks]");
339 (ENCRYPTION_PASSPHRASE_FILE
.c_str(),
340 po::value
<std::vector
<std::string
>>(),
341 "path to file containing passphrase for unlocking the image");
344 std::string
get_short_features_help(bool append_suffix
) {
345 std::ostringstream oss
;
346 bool first_feature
= true;
348 for (auto &pair
: ImageFeatures::FEATURE_MAPPING
) {
349 if ((pair
.first
& RBD_FEATURES_IMPLICIT_ENABLE
) != 0ULL) {
350 // hide implicitly enabled features from list
352 } else if (!append_suffix
&& (pair
.first
& RBD_FEATURES_MUTABLE
) == 0ULL) {
353 // hide non-mutable features for the 'rbd feature XYZ' command
357 if (!first_feature
) {
360 first_feature
= false;
364 if ((pair
.first
& rbd::utils::get_rbd_default_features(g_ceph_context
)) != 0) {
367 if ((pair
.first
& RBD_FEATURES_MUTABLE
) != 0) {
369 } else if ((pair
.first
& RBD_FEATURES_DISABLE_ONLY
) != 0) {
372 if (!suffix
.empty()) {
373 suffix
= "(" + suffix
+ ")";
376 oss
<< pair
.second
<< suffix
;
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"
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
);
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
);
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
408 v
= boost::any(size
);
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
);
416 uint64_t order
= boost::lexical_cast
<uint64_t>(s
);
417 if (order
>= 12 && order
<= 25) {
418 v
= boost::any(order
);
421 } catch (const boost::bad_lexical_cast
&) {
423 throw po::validation_error(po::validation_error::invalid_option_value
);
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
);
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
);
436 v
= boost::any(objectsize
);
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
);
444 uint32_t format
= boost::lexical_cast
<uint32_t>(s
);
445 if (format
== 1 || format
== 2) {
446 v
= boost::any(format
);
449 } catch (const boost::bad_lexical_cast
&) {
451 throw po::validation_error(po::validation_error::invalid_option_value
);
454 void validate(boost::any
& v
, const std::vector
<std::string
>& values
,
455 ImageNewFormat
*target_type
, int dummy
) {
456 v
= boost::any(true);
459 void validate(boost::any
& v
, const std::vector
<std::string
>& values
,
460 ImageFeatures
*target_type
, int) {
462 v
= boost::any(static_cast<uint64_t>(0));
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
;
480 throw po::validation_error(po::validation_error::invalid_option_value
);
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
);
495 throw po::validation_error(po::validation_error::invalid_option_value
);
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
));
506 throw po::validation_error(po::validation_error::invalid_option_value
);
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
);
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
);
521 throw po::validation_error(po::validation_error::invalid_option_value
);
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
);
533 throw po::validation_error(po::validation_error::invalid_option_value
);
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
);
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
});
548 throw po::validation_error(po::validation_error::invalid_option_value
);
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
);
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
);
563 v
= boost::any(format
);
566 void validate(boost::any
& v
, const std::vector
<std::string
>& values
,
567 Secret
*target_type
, int) {
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());
575 } // namespace argument_types