1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/Formatter.h"
5 #include "common/TextTable.h"
6 #include "common/ceph_context.h"
7 #include "common/ceph_json.h"
8 #include "common/escape.h"
9 #include "common/errno.h"
10 #include "common/options.h"
11 #include "global/global_context.h"
12 #include "include/stringify.h"
14 #include "tools/rbd/ArgumentTypes.h"
15 #include "tools/rbd/Shell.h"
16 #include "tools/rbd/Utils.h"
20 #include <boost/algorithm/string/predicate.hpp>
21 #include <boost/program_options.hpp>
27 namespace at
= argument_types
;
28 namespace po
= boost::program_options
;
32 const std::string METADATA_CONF_PREFIX
= "conf_";
33 const uint32_t MAX_KEYS
= 64;
35 void add_config_entity_option(
36 boost::program_options::options_description
*positional
) {
37 positional
->add_options()
38 ("config-entity", "config entity (global, client, client.<id>)");
41 void add_pool_option(boost::program_options::options_description
*positional
) {
42 positional
->add_options()
43 ("pool-name", "pool name");
46 void add_key_option(po::options_description
*positional
) {
47 positional
->add_options()
48 ("key", "config key");
51 int get_config_entity(const po::variables_map
&vm
, std::string
*config_entity
) {
52 *config_entity
= utils::get_positional_argument(vm
, 0);
54 if (*config_entity
!= "global" && *config_entity
!= "client" &&
55 !boost::starts_with(*config_entity
, ("client."))) {
56 std::cerr
<< "rbd: invalid config entity: " << *config_entity
57 << " (must be global, client or client.<id>)" << std::endl
;
64 int get_pool(const po::variables_map
&vm
, std::string
*pool_name
) {
65 *pool_name
= utils::get_positional_argument(vm
, 0);
66 if (pool_name
->empty()) {
67 std::cerr
<< "rbd: pool name was not specified" << std::endl
;
74 int get_key(const po::variables_map
&vm
, size_t *arg_index
,
76 *key
= utils::get_positional_argument(vm
, *arg_index
);
78 std::cerr
<< "rbd: config key was not specified" << std::endl
;
84 if (!boost::starts_with(*key
, "rbd_")) {
85 std::cerr
<< "rbd: not rbd option: " << *key
<< std::endl
;
90 int r
= g_ceph_context
->_conf
.get_val(key
->c_str(), &value
);
92 std::cerr
<< "rbd: invalid config key: " << *key
<< std::endl
;
99 std::ostream
& operator<<(std::ostream
& os
,
100 const librbd::config_source_t
& source
) {
102 case RBD_CONFIG_SOURCE_CONFIG
:
105 case RBD_CONFIG_SOURCE_POOL
:
108 case RBD_CONFIG_SOURCE_IMAGE
:
112 os
<< "unknown (" << static_cast<uint32_t>(source
) << ")";
118 int config_global_list(
119 librados::Rados
&rados
, const std::string
&config_entity
,
120 std::map
<std::string
, std::pair
<std::string
, std::string
>> *options
) {
121 bool client_id_config_entity
=
122 boost::starts_with(config_entity
, ("client."));
125 "\"prefix\": \"config dump\", "
126 "\"format\": \"json\" "
131 int r
= rados
.mon_command(cmd
, in_bl
, &out_bl
, &ss
);
133 std::cerr
<< "rbd: error reading config: " << ss
<< std::endl
;
137 json_spirit::mValue json_root
;
138 if (!json_spirit::read(out_bl
.to_str(), json_root
)) {
139 std::cerr
<< "rbd: error parsing config dump" << std::endl
;
144 auto &json_array
= json_root
.get_array();
145 for (auto& e
: json_array
) {
146 auto &json_obj
= e
.get_obj();
151 for (auto &pairs
: json_obj
) {
152 if (pairs
.first
== "section") {
153 section
= pairs
.second
.get_str();
154 } else if (pairs
.first
== "name") {
155 name
= pairs
.second
.get_str();
156 } else if (pairs
.first
== "value") {
157 value
= pairs
.second
.get_str();
161 if (!boost::starts_with(name
, "rbd_")) {
164 if (section
!= "global" && section
!= "client" &&
165 (!client_id_config_entity
|| section
!= config_entity
)) {
168 if (config_entity
== "global" && section
!= "global") {
171 auto it
= options
->find(name
);
172 if (it
== options
->end()) {
173 (*options
)[name
] = {value
, section
};
176 if (section
== "client") {
177 if (it
->second
.second
== "global") {
178 it
->second
= {value
, section
};
180 } else if (client_id_config_entity
) {
181 it
->second
= {value
, section
};
184 } catch (std::runtime_error
&e
) {
185 std::cerr
<< "rbd: error parsing config dump: " << e
.what() << std::endl
;
192 } // anonymous namespace
194 void get_global_get_arguments(po::options_description
*positional
,
195 po::options_description
*options
) {
196 add_config_entity_option(positional
);
197 add_key_option(positional
);
200 int execute_global_get(const po::variables_map
&vm
,
201 const std::vector
<std::string
> &ceph_global_init_args
) {
202 std::string config_entity
;
203 int r
= get_config_entity(vm
, &config_entity
);
209 size_t arg_index
= 1;
210 r
= get_key(vm
, &arg_index
, &key
);
215 librados::Rados rados
;
216 r
= utils::init_rados(&rados
);
221 std::map
<std::string
, std::pair
<std::string
, std::string
>> options
;
222 r
= config_global_list(rados
, config_entity
, &options
);
227 auto it
= options
.find(key
);
229 if (it
== options
.end() || it
->second
.second
!= config_entity
) {
230 std::cerr
<< "rbd: " << key
<< " is not set" << std::endl
;
234 std::cout
<< it
->second
.first
<< std::endl
;
238 void get_global_set_arguments(po::options_description
*positional
,
239 po::options_description
*options
) {
240 add_config_entity_option(positional
);
241 add_key_option(positional
);
242 positional
->add_options()
243 ("value", "config value");
246 int execute_global_set(const po::variables_map
&vm
,
247 const std::vector
<std::string
> &ceph_global_init_args
) {
248 std::string config_entity
;
249 int r
= get_config_entity(vm
, &config_entity
);
255 size_t arg_index
= 1;
256 r
= get_key(vm
, &arg_index
, &key
);
261 librados::Rados rados
;
262 r
= utils::init_rados(&rados
);
267 std::string value
= utils::get_positional_argument(vm
, 2);
270 "\"prefix\": \"config set\", "
271 "\"who\": \"" + stringify(json_stream_escaper(config_entity
)) + "\", "
272 "\"name\": \"" + key
+ "\", "
273 "\"value\": \"" + stringify(json_stream_escaper(value
)) + "\""
277 r
= rados
.mon_command(cmd
, in_bl
, nullptr, &ss
);
279 std::cerr
<< "rbd: error setting " << key
<< ": " << ss
<< std::endl
;
286 void get_global_remove_arguments(po::options_description
*positional
,
287 po::options_description
*options
) {
288 add_config_entity_option(positional
);
289 add_key_option(positional
);
292 int execute_global_remove(
293 const po::variables_map
&vm
,
294 const std::vector
<std::string
> &ceph_global_init_args
) {
295 std::string config_entity
;
296 int r
= get_config_entity(vm
, &config_entity
);
302 size_t arg_index
= 1;
303 r
= get_key(vm
, &arg_index
, &key
);
308 librados::Rados rados
;
309 r
= utils::init_rados(&rados
);
316 "\"prefix\": \"config rm\", "
317 "\"who\": \"" + stringify(json_stream_escaper(config_entity
)) + "\", "
318 "\"name\": \"" + key
+ "\""
322 r
= rados
.mon_command(cmd
, in_bl
, nullptr, &ss
);
324 std::cerr
<< "rbd: error removing " << key
<< ": " << ss
<< std::endl
;
331 void get_global_list_arguments(po::options_description
*positional
,
332 po::options_description
*options
) {
333 add_config_entity_option(positional
);
334 at::add_format_options(options
);
337 int execute_global_list(const po::variables_map
&vm
,
338 const std::vector
<std::string
> &ceph_global_init_args
) {
339 std::string config_entity
;
340 int r
= get_config_entity(vm
, &config_entity
);
345 at::Format::Formatter f
;
346 r
= utils::get_formatter(vm
, &f
);
351 librados::Rados rados
;
352 r
= utils::init_rados(&rados
);
357 std::map
<std::string
, std::pair
<std::string
, std::string
>> options
;
358 r
= config_global_list(rados
, config_entity
, &options
);
363 if (options
.empty() && !f
) {
370 f
->open_array_section("config");
372 tbl
.define_column("Name", TextTable::LEFT
, TextTable::LEFT
);
373 tbl
.define_column("Value", TextTable::LEFT
, TextTable::LEFT
);
374 tbl
.define_column("Section", TextTable::LEFT
, TextTable::LEFT
);
377 for (const auto &it
: options
) {
379 f
->open_object_section("option");
380 f
->dump_string("name", it
.first
);
381 f
->dump_string("value", it
.second
.first
);
382 f
->dump_string("section", it
.second
.second
);
385 tbl
<< it
.first
<< it
.second
.first
<< it
.second
.second
386 << TextTable::endrow
;
400 void get_pool_get_arguments(po::options_description
*positional
,
401 po::options_description
*options
) {
402 add_pool_option(positional
);
403 add_key_option(positional
);
406 int execute_pool_get(const po::variables_map
&vm
,
407 const std::vector
<std::string
> &ceph_global_init_args
) {
408 std::string pool_name
;
409 int r
= get_pool(vm
, &pool_name
);
415 size_t arg_index
= 1;
416 r
= get_key(vm
, &arg_index
, &key
);
421 librados::Rados rados
;
422 librados::IoCtx io_ctx
;
423 r
= utils::init(pool_name
, "", &rados
, &io_ctx
);
431 r
= rbd
.pool_metadata_get(io_ctx
, METADATA_CONF_PREFIX
+ key
, &value
);
434 std::cerr
<< "rbd: " << key
<< " is not set" << std::endl
;
436 std::cerr
<< "rbd: failed to get " << key
<< ": " << cpp_strerror(r
)
442 std::cout
<< value
<< std::endl
;
446 void get_pool_set_arguments(po::options_description
*positional
,
447 po::options_description
*options
) {
448 add_pool_option(positional
);
449 add_key_option(positional
);
450 positional
->add_options()
451 ("value", "config value");
454 int execute_pool_set(const po::variables_map
&vm
,
455 const std::vector
<std::string
> &ceph_global_init_args
) {
456 std::string pool_name
;
457 int r
= get_pool(vm
, &pool_name
);
463 size_t arg_index
= 1;
464 r
= get_key(vm
, &arg_index
, &key
);
469 std::string value
= utils::get_positional_argument(vm
, 2);
471 librados::Rados rados
;
472 librados::IoCtx io_ctx
;
473 r
= utils::init(pool_name
, "", &rados
, &io_ctx
);
479 r
= rbd
.pool_metadata_set(io_ctx
, METADATA_CONF_PREFIX
+ key
, value
);
481 std::cerr
<< "rbd: failed to set " << key
<< ": " << cpp_strerror(r
)
489 void get_pool_remove_arguments(po::options_description
*positional
,
490 po::options_description
*options
) {
491 add_pool_option(positional
);
492 add_key_option(positional
);
495 int execute_pool_remove(const po::variables_map
&vm
,
496 const std::vector
<std::string
> &ceph_global_init_args
) {
497 std::string pool_name
;
498 int r
= get_pool(vm
, &pool_name
);
504 size_t arg_index
= 1;
505 r
= get_key(vm
, &arg_index
, &key
);
510 librados::Rados rados
;
511 librados::IoCtx io_ctx
;
512 r
= utils::init(pool_name
, "", &rados
, &io_ctx
);
518 r
= rbd
.pool_metadata_remove(io_ctx
, METADATA_CONF_PREFIX
+ key
);
520 std::cerr
<< "rbd: failed to remove " << key
<< ": " << cpp_strerror(r
)
528 void get_pool_list_arguments(po::options_description
*positional
,
529 po::options_description
*options
) {
530 add_pool_option(positional
);
531 at::add_format_options(options
);
534 int execute_pool_list(const po::variables_map
&vm
,
535 const std::vector
<std::string
> &ceph_global_init_args
) {
536 std::string pool_name
;
537 int r
= get_pool(vm
, &pool_name
);
542 at::Format::Formatter f
;
543 r
= utils::get_formatter(vm
, &f
);
548 librados::Rados rados
;
549 librados::IoCtx io_ctx
;
550 r
= utils::init(pool_name
, "", &rados
, &io_ctx
);
557 std::vector
<librbd::config_option_t
> options
;
559 r
= rbd
.config_list(io_ctx
, &options
);
561 std::cerr
<< "rbd: failed to list config: " << cpp_strerror(r
) << std::endl
;
566 f
->open_array_section("config");
568 tbl
.define_column("Name", TextTable::LEFT
, TextTable::LEFT
);
569 tbl
.define_column("Value", TextTable::LEFT
, TextTable::LEFT
);
570 tbl
.define_column("Source", TextTable::LEFT
, TextTable::LEFT
);
573 for (auto &option
: options
) {
575 f
->open_object_section("option");
576 f
->dump_string("name", option
.name
);
577 f
->dump_string("value", option
.value
);
578 f
->dump_stream("source") << option
.source
;
581 std::ostringstream source
;
582 source
<< option
.source
;
583 tbl
<< option
.name
<< option
.value
<< source
.str() << TextTable::endrow
;
597 void get_image_get_arguments(po::options_description
*positional
,
598 po::options_description
*options
) {
599 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
600 add_key_option(positional
);
603 int execute_image_get(const po::variables_map
&vm
,
604 const std::vector
<std::string
> &ceph_global_init_args
) {
605 size_t arg_index
= 0;
606 std::string pool_name
;
607 std::string namespace_name
;
608 std::string image_name
;
609 std::string snap_name
;
610 int r
= utils::get_pool_image_snapshot_names(
611 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
612 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
613 utils::SPEC_VALIDATION_NONE
);
619 r
= get_key(vm
, &arg_index
, &key
);
624 librados::Rados rados
;
625 librados::IoCtx io_ctx
;
627 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
628 false, &rados
, &io_ctx
, &image
);
635 r
= image
.metadata_get(METADATA_CONF_PREFIX
+ key
, &value
);
638 std::cerr
<< "rbd: " << key
<< " is not set" << std::endl
;
640 std::cerr
<< "rbd: failed to get " << key
<< ": " << cpp_strerror(r
)
646 std::cout
<< value
<< std::endl
;
650 void get_image_set_arguments(po::options_description
*positional
,
651 po::options_description
*options
) {
652 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
653 add_key_option(positional
);
654 positional
->add_options()
655 ("value", "config value");
658 int execute_image_set(const po::variables_map
&vm
,
659 const std::vector
<std::string
> &ceph_global_init_args
) {
660 size_t arg_index
= 0;
661 std::string pool_name
;
662 std::string namespace_name
;
663 std::string image_name
;
664 std::string snap_name
;
665 int r
= utils::get_pool_image_snapshot_names(
666 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
667 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
668 utils::SPEC_VALIDATION_NONE
);
674 r
= get_key(vm
, &arg_index
, &key
);
679 std::string value
= utils::get_positional_argument(vm
, arg_index
);
681 std::cerr
<< "rbd: image config value was not specified" << std::endl
;
685 librados::Rados rados
;
686 librados::IoCtx io_ctx
;
688 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
689 false, &rados
, &io_ctx
, &image
);
694 r
= image
.metadata_set(METADATA_CONF_PREFIX
+ key
, value
);
696 std::cerr
<< "rbd: failed to set " << key
<< ": " << cpp_strerror(r
)
704 void get_image_remove_arguments(po::options_description
*positional
,
705 po::options_description
*options
) {
706 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
707 add_key_option(positional
);
710 int execute_image_remove(
711 const po::variables_map
&vm
,
712 const std::vector
<std::string
> &ceph_global_init_args
) {
713 size_t arg_index
= 0;
714 std::string pool_name
;
715 std::string namespace_name
;
716 std::string image_name
;
717 std::string snap_name
;
718 int r
= utils::get_pool_image_snapshot_names(
719 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
720 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
721 utils::SPEC_VALIDATION_NONE
);
727 r
= get_key(vm
, &arg_index
, &key
);
732 librados::Rados rados
;
733 librados::IoCtx io_ctx
;
735 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
736 false, &rados
, &io_ctx
, &image
);
741 r
= image
.metadata_remove(METADATA_CONF_PREFIX
+ key
);
743 std::cerr
<< "rbd: failed to remove " << key
<< ": " << cpp_strerror(r
)
751 void get_image_list_arguments(po::options_description
*positional
,
752 po::options_description
*options
) {
753 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
754 at::add_format_options(options
);
757 int execute_image_list(const po::variables_map
&vm
,
758 const std::vector
<std::string
> &ceph_global_init_args
) {
759 size_t arg_index
= 0;
760 std::string pool_name
;
761 std::string namespace_name
;
762 std::string image_name
;
763 std::string snap_name
;
764 int r
= utils::get_pool_image_snapshot_names(
765 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
766 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
767 utils::SPEC_VALIDATION_NONE
);
772 at::Format::Formatter f
;
773 r
= utils::get_formatter(vm
, &f
);
778 librados::Rados rados
;
779 librados::IoCtx io_ctx
;
781 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
782 false, &rados
, &io_ctx
, &image
);
788 std::vector
<librbd::config_option_t
> options
;
790 r
= image
.config_list(&options
);
792 std::cerr
<< "rbd: failed to list config: " << cpp_strerror(r
) << std::endl
;
796 if (options
.empty()) {
798 std::cout
<< "There are no values" << std::endl
;
804 f
->open_array_section("config");
806 tbl
.define_column("Name", TextTable::LEFT
, TextTable::LEFT
);
807 tbl
.define_column("Value", TextTable::LEFT
, TextTable::LEFT
);
808 tbl
.define_column("Source", TextTable::LEFT
, TextTable::LEFT
);
811 for (auto &option
: options
) {
813 f
->open_object_section("option");
814 f
->dump_string("name", option
.name
);
815 f
->dump_string("value", option
.value
);
816 f
->dump_stream("source") << option
.source
;
819 std::ostringstream source
;
820 source
<< option
.source
;
821 tbl
<< option
.name
<< option
.value
<< source
.str() << TextTable::endrow
;
826 bool single
= (options
.size() == 1);
827 std::cout
<< "There " << (single
? "is" : "are") << " " << options
.size()
828 << " " << (single
? "value" : "values") << ":" << std::endl
;
841 Shell::Action
action_global_get(
842 {"config", "global", "get"}, {},
843 "Get a global-level configuration override.", "",
844 &get_global_get_arguments
, &execute_global_get
);
845 Shell::Action
action_global_set(
846 {"config", "global", "set"}, {},
847 "Set a global-level configuration override.", "",
848 &get_global_set_arguments
, &execute_global_set
);
849 Shell::Action
action_global_remove(
850 {"config", "global", "remove"}, {"config", "global", "rm"},
851 "Remove a global-level configuration override.", "",
852 &get_global_remove_arguments
, &execute_global_remove
);
853 Shell::Action
action_global_list(
854 {"config", "global", "list"}, {"config", "global", "ls"},
855 "List global-level configuration overrides.", "",
856 &get_global_list_arguments
, &execute_global_list
);
858 Shell::Action
action_pool_get(
859 {"config", "pool", "get"}, {}, "Get a pool-level configuration override.", "",
860 &get_pool_get_arguments
, &execute_pool_get
);
861 Shell::Action
action_pool_set(
862 {"config", "pool", "set"}, {}, "Set a pool-level configuration override.", "",
863 &get_pool_set_arguments
, &execute_pool_set
);
864 Shell::Action
action_pool_remove(
865 {"config", "pool", "remove"}, {"config", "pool", "rm"},
866 "Remove a pool-level configuration override.", "",
867 &get_pool_remove_arguments
, &execute_pool_remove
);
868 Shell::Action
action_pool_list(
869 {"config", "pool", "list"}, {"config", "pool", "ls"},
870 "List pool-level configuration overrides.", "",
871 &get_pool_list_arguments
, &execute_pool_list
);
873 Shell::Action
action_image_get(
874 {"config", "image", "get"}, {}, "Get an image-level configuration override.",
875 "", &get_image_get_arguments
, &execute_image_get
);
876 Shell::Action
action_image_set(
877 {"config", "image", "set"}, {}, "Set an image-level configuration override.",
878 "", &get_image_set_arguments
, &execute_image_set
);
879 Shell::Action
action_image_remove(
880 {"config", "image", "remove"}, {"config", "image", "rm"},
881 "Remove an image-level configuration override.", "",
882 &get_image_remove_arguments
, &execute_image_remove
);
883 Shell::Action
action_image_list(
884 {"config", "image", "list"}, {"config", "image", "ls"},
885 "List image-level configuration overrides.", "",
886 &get_image_list_arguments
, &execute_image_list
);
888 } // namespace config
889 } // namespace action