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.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
},
31 Format::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
));
40 std::string
get_name_prefix(ArgumentModifier modifier
) {
42 case ARGUMENT_MODIFIER_SOURCE
:
44 case ARGUMENT_MODIFIER_DEST
:
51 std::string
get_description_prefix(ArgumentModifier modifier
) {
53 case ARGUMENT_MODIFIER_SOURCE
:
55 case ARGUMENT_MODIFIER_DEST
:
56 return "destination ";
62 void add_special_pool_option(po::options_description
*opt
,
64 std::string name
= prefix
+ "-" + POOL_NAME
;
65 std::string description
= prefix
+ " pool name";
68 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
71 void 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";
77 case ARGUMENT_MODIFIER_NONE
:
79 case ARGUMENT_MODIFIER_SOURCE
:
80 description
= "source " + description
;
82 case ARGUMENT_MODIFIER_DEST
:
83 name
= DEST_POOL_NAME
;
84 description
= "destination " + description
;
87 description
+= desc_suffix
;
91 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
94 void 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";
100 case ARGUMENT_MODIFIER_NONE
:
102 case ARGUMENT_MODIFIER_SOURCE
:
103 description
= "source " + description
;
105 case ARGUMENT_MODIFIER_DEST
:
106 name
= DEST_IMAGE_NAME
;
107 description
= "destination " + description
;
110 description
+= desc_suffix
;
112 // TODO add validator
114 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
117 void 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
;
123 // TODO add validator
125 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
128 void 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";
134 case ARGUMENT_MODIFIER_NONE
:
136 case ARGUMENT_MODIFIER_SOURCE
:
137 description
= "source " + description
;
139 case ARGUMENT_MODIFIER_DEST
:
140 name
= DEST_GROUP_NAME
;
141 description
= "destination " + description
;
144 description
+= desc_suffix
;
146 // TODO add validator
148 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
151 void add_snap_option(po::options_description
*opt
,
152 ArgumentModifier modifier
) {
154 std::string name
= SNAPSHOT_NAME
;
155 std::string description
= "snapshot name";
157 case ARGUMENT_MODIFIER_NONE
:
159 case ARGUMENT_MODIFIER_DEST
:
160 name
= DEST_SNAPSHOT_NAME
;
161 description
= "destination " + description
;
163 case ARGUMENT_MODIFIER_SOURCE
:
164 description
= "source " + description
;
168 // TODO add validator
170 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
173 void 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";
179 case ARGUMENT_MODIFIER_NONE
:
181 case ARGUMENT_MODIFIER_SOURCE
:
182 description
= "source " + description
;
184 case ARGUMENT_MODIFIER_DEST
:
185 name
= DEST_JOURNAL_NAME
;
186 description
= "destination " + description
;
189 description
+= desc_suffix
;
191 // TODO add validator
193 (name
.c_str(), po::value
<std::string
>(), description
.c_str());
196 void add_pool_options(boost::program_options::options_description
*pos
,
197 boost::program_options::options_description
*opt
) {
199 ("pool-name", "pool name");
201 ((POOL_NAME
+ ",p").c_str(), po::value
<std::string
>(), "pool name");
204 void add_image_spec_options(po::options_description
*pos
,
205 po::options_description
*opt
,
206 ArgumentModifier modifier
) {
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
);
215 void add_group_spec_options(po::options_description
*pos
,
216 po::options_description
*opt
,
217 ArgumentModifier modifier
) {
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
);
226 void add_snap_spec_options(po::options_description
*pos
,
227 po::options_description
*opt
,
228 ArgumentModifier modifier
) {
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
);
238 void add_image_or_snap_spec_options(po::options_description
*pos
,
239 po::options_description
*opt
,
240 ArgumentModifier modifier
) {
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
);
250 void add_journal_spec_options(po::options_description
*pos
,
251 po::options_description
*opt
,
252 ArgumentModifier modifier
) {
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
);
263 void add_create_image_options(po::options_description
*opt
,
264 bool include_format
) {
265 // TODO get default image format from conf
266 if (include_format
) {
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)");
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");
287 add_create_journal_options(opt
);
290 void add_create_journal_options(po::options_description
*opt
) {
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");
300 void add_size_option(boost::program_options::options_description
*opt
) {
302 ((IMAGE_SIZE
+ ",s").c_str(), po::value
<ImageSize
>()->required(),
303 "image size (in M/G/T) [default: M]");
306 void add_sparse_size_option(boost::program_options::options_description
*opt
) {
308 (IMAGE_SPARSE_SIZE
.c_str(), po::value
<ImageObjectSize
>(),
309 "sparse size in B/K/M [default: 4K]");
312 void add_path_options(boost::program_options::options_description
*pos
,
313 boost::program_options::options_description
*opt
,
314 const std::string
&description
) {
316 (PATH_NAME
.c_str(), po::value
<std::string
>(), description
.c_str());
318 (PATH
.c_str(), po::value
<std::string
>(), description
.c_str());
321 void add_limit_option(po::options_description
*opt
) {
322 std::string description
= "maximum allowed snapshot count";
325 (LIMIT
.c_str(), po::value
<uint64_t>(), description
.c_str());
328 void add_no_progress_option(boost::program_options::options_description
*opt
) {
330 (NO_PROGRESS
.c_str(), po::bool_switch(), "disable progress output");
333 void add_format_options(boost::program_options::options_description
*opt
) {
335 (FORMAT
.c_str(), po::value
<Format
>(), "output format [plain, json, or xml]")
336 (PRETTY_FORMAT
.c_str(), po::bool_switch(),
337 "pretty formatting (json and xml)");
340 void add_verbose_option(boost::program_options::options_description
*opt
) {
342 (VERBOSE
.c_str(), po::bool_switch(), "be verbose");
345 void add_no_error_option(boost::program_options::options_description
*opt
) {
347 (NO_ERROR
.c_str(), po::bool_switch(), "continue after error");
350 void add_export_format_option(boost::program_options::options_description
*opt
) {
352 ("export-format", po::value
<ExportFormat
>(), "format of image file");
355 std::string
get_short_features_help(bool append_suffix
) {
356 std::ostringstream oss
;
357 bool first_feature
= true;
359 for (auto &pair
: ImageFeatures::FEATURE_MAPPING
) {
360 if (!first_feature
) {
363 first_feature
= false;
367 if ((pair
.first
& rbd::utils::get_rbd_default_features(g_ceph_context
)) != 0) {
370 if ((pair
.first
& RBD_FEATURES_MUTABLE
) != 0) {
372 } else if ((pair
.first
& RBD_FEATURES_DISABLE_ONLY
) != 0) {
375 if (!suffix
.empty()) {
376 suffix
= "(" + suffix
+ ")";
379 oss
<< pair
.second
<< suffix
;
385 std::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"
395 void 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
);
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
);
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
411 v
= boost::any(size
);
414 void 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
);
419 uint64_t order
= boost::lexical_cast
<uint64_t>(s
);
420 if (order
>= 12 && order
<= 25) {
421 v
= boost::any(order
);
424 } catch (const boost::bad_lexical_cast
&) {
426 throw po::validation_error(po::validation_error::invalid_option_value
);
429 void 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
);
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
);
439 v
= boost::any(objectsize
);
442 void 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
);
447 uint32_t format
= boost::lexical_cast
<uint32_t>(s
);
448 if (format
== 1 || format
== 2) {
449 v
= boost::any(format
);
452 } catch (const boost::bad_lexical_cast
&) {
454 throw po::validation_error(po::validation_error::invalid_option_value
);
457 void 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"
461 v
= boost::any(true);
464 void validate(boost::any
& v
, const std::vector
<std::string
>& values
,
465 ImageFeatures
*target_type
, int) {
467 v
= boost::any(static_cast<uint64_t>(0));
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
;
485 throw po::validation_error(po::validation_error::invalid_option_value
);
491 void 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
));
498 throw po::validation_error(po::validation_error::invalid_option_value
);
502 void 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
);
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
);
513 throw po::validation_error(po::validation_error::invalid_option_value
);
516 void 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
);
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
);
527 v
= boost::any(format
);
530 void 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
;
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());
540 } // namespace argument_types