]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/Config.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / tools / rbd / action / Config.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 "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"
13
14 #include "tools/rbd/ArgumentTypes.h"
15 #include "tools/rbd/Shell.h"
16 #include "tools/rbd/Utils.h"
17
18 #include <iostream>
19
20 #include <boost/algorithm/string/predicate.hpp>
21 #include <boost/program_options.hpp>
22
23 #include "json_spirit/json_spirit.h"
24
25 namespace rbd {
26 namespace action {
27 namespace config {
28
29 namespace at = argument_types;
30 namespace po = boost::program_options;
31
32 namespace {
33
34 const std::string METADATA_CONF_PREFIX = "conf_";
35
36 void add_config_entity_option(
37 boost::program_options::options_description *positional) {
38 positional->add_options()
39 ("config-entity", "config entity (global, client, client.<id>)");
40 }
41
42 void add_pool_option(boost::program_options::options_description *positional) {
43 positional->add_options()
44 ("pool-name", "pool name");
45 }
46
47 void add_key_option(po::options_description *positional) {
48 positional->add_options()
49 ("key", "config key");
50 }
51
52 int get_config_entity(const po::variables_map &vm, std::string *config_entity) {
53 *config_entity = utils::get_positional_argument(vm, 0);
54
55 if (*config_entity != "global" && *config_entity != "client" &&
56 !boost::starts_with(*config_entity, ("client."))) {
57 std::cerr << "rbd: invalid config entity: " << *config_entity
58 << " (must be global, client or client.<id>)" << std::endl;
59 return -EINVAL;
60 }
61
62 return 0;
63 }
64
65 int get_pool(const po::variables_map &vm, std::string *pool_name) {
66 *pool_name = utils::get_positional_argument(vm, 0);
67 if (pool_name->empty()) {
68 std::cerr << "rbd: pool name was not specified" << std::endl;
69 return -EINVAL;
70 }
71
72 return 0;
73 }
74
75 int get_key(const po::variables_map &vm, size_t *arg_index,
76 std::string *key) {
77 *key = utils::get_positional_argument(vm, *arg_index);
78 if (key->empty()) {
79 std::cerr << "rbd: config key was not specified" << std::endl;
80 return -EINVAL;
81 } else {
82 ++(*arg_index);
83 }
84
85 if (!boost::starts_with(*key, "rbd_")) {
86 std::cerr << "rbd: not rbd option: " << *key << std::endl;
87 return -EINVAL;
88 }
89
90 std::string value;
91 int r = g_ceph_context->_conf.get_val(key->c_str(), &value);
92 if (r < 0) {
93 std::cerr << "rbd: invalid config key: " << *key << std::endl;
94 return -EINVAL;
95 }
96
97 return 0;
98 }
99
100 std::ostream& operator<<(std::ostream& os,
101 const librbd::config_source_t& source) {
102 switch (source) {
103 case RBD_CONFIG_SOURCE_CONFIG:
104 os << "config";
105 break;
106 case RBD_CONFIG_SOURCE_POOL:
107 os << "pool";
108 break;
109 case RBD_CONFIG_SOURCE_IMAGE:
110 os << "image";
111 break;
112 default:
113 os << "unknown (" << static_cast<uint32_t>(source) << ")";
114 break;
115 }
116 return os;
117 }
118
119 int config_global_list(
120 librados::Rados &rados, const std::string &config_entity,
121 std::map<std::string, std::pair<std::string, std::string>> *options) {
122 bool client_id_config_entity =
123 boost::starts_with(config_entity, ("client."));
124 std::string cmd =
125 "{"
126 "\"prefix\": \"config dump\", "
127 "\"format\": \"json\" "
128 "}";
129 bufferlist in_bl;
130 bufferlist out_bl;
131 std::string ss;
132 int r = rados.mon_command(cmd, in_bl, &out_bl, &ss);
133 if (r < 0) {
134 std::cerr << "rbd: error reading config: " << ss << std::endl;
135 return r;
136 }
137
138 json_spirit::mValue json_root;
139 if (!json_spirit::read(out_bl.to_str(), json_root)) {
140 std::cerr << "rbd: error parsing config dump" << std::endl;
141 return -EINVAL;
142 }
143
144 try {
145 auto &json_array = json_root.get_array();
146 for (auto& e : json_array) {
147 auto &json_obj = e.get_obj();
148 std::string section;
149 std::string name;
150 std::string value;
151
152 for (auto &pairs : json_obj) {
153 if (pairs.first == "section") {
154 section = pairs.second.get_str();
155 } else if (pairs.first == "name") {
156 name = pairs.second.get_str();
157 } else if (pairs.first == "value") {
158 value = pairs.second.get_str();
159 }
160 }
161
162 if (!boost::starts_with(name, "rbd_")) {
163 continue;
164 }
165 if (section != "global" && section != "client" &&
166 (!client_id_config_entity || section != config_entity)) {
167 continue;
168 }
169 if (config_entity == "global" && section != "global") {
170 continue;
171 }
172 auto it = options->find(name);
173 if (it == options->end()) {
174 (*options)[name] = {value, section};
175 continue;
176 }
177 if (section == "client") {
178 if (it->second.second == "global") {
179 it->second = {value, section};
180 }
181 } else if (client_id_config_entity) {
182 it->second = {value, section};
183 }
184 }
185 } catch (std::runtime_error &e) {
186 std::cerr << "rbd: error parsing config dump: " << e.what() << std::endl;
187 return -EINVAL;
188 }
189
190 return 0;
191 }
192
193 } // anonymous namespace
194
195 void get_global_get_arguments(po::options_description *positional,
196 po::options_description *options) {
197 add_config_entity_option(positional);
198 add_key_option(positional);
199 }
200
201 int execute_global_get(const po::variables_map &vm,
202 const std::vector<std::string> &ceph_global_init_args) {
203 std::string config_entity;
204 int r = get_config_entity(vm, &config_entity);
205 if (r < 0) {
206 return r;
207 }
208
209 std::string key;
210 size_t arg_index = 1;
211 r = get_key(vm, &arg_index, &key);
212 if (r < 0) {
213 return r;
214 }
215
216 librados::Rados rados;
217 r = utils::init_rados(&rados);
218 if (r < 0) {
219 return r;
220 }
221
222 std::map<std::string, std::pair<std::string, std::string>> options;
223 r = config_global_list(rados, config_entity, &options);
224 if (r < 0) {
225 return r;
226 }
227
228 auto it = options.find(key);
229
230 if (it == options.end() || it->second.second != config_entity) {
231 std::cerr << "rbd: " << key << " is not set" << std::endl;
232 return -ENOENT;
233 }
234
235 std::cout << it->second.first << std::endl;
236 return 0;
237 }
238
239 void get_global_set_arguments(po::options_description *positional,
240 po::options_description *options) {
241 add_config_entity_option(positional);
242 add_key_option(positional);
243 positional->add_options()
244 ("value", "config value");
245 }
246
247 int execute_global_set(const po::variables_map &vm,
248 const std::vector<std::string> &ceph_global_init_args) {
249 std::string config_entity;
250 int r = get_config_entity(vm, &config_entity);
251 if (r < 0) {
252 return r;
253 }
254
255 std::string key;
256 size_t arg_index = 1;
257 r = get_key(vm, &arg_index, &key);
258 if (r < 0) {
259 return r;
260 }
261
262 librados::Rados rados;
263 r = utils::init_rados(&rados);
264 if (r < 0) {
265 return r;
266 }
267
268 std::string value = utils::get_positional_argument(vm, 2);
269 std::string cmd =
270 "{"
271 "\"prefix\": \"config set\", "
272 "\"who\": \"" + stringify(json_stream_escaper(config_entity)) + "\", "
273 "\"name\": \"" + key + "\", "
274 "\"value\": \"" + stringify(json_stream_escaper(value)) + "\""
275 "}";
276 bufferlist in_bl;
277 std::string ss;
278 r = rados.mon_command(cmd, in_bl, nullptr, &ss);
279 if (r < 0) {
280 std::cerr << "rbd: error setting " << key << ": " << ss << std::endl;
281 return r;
282 }
283
284 return 0;
285 }
286
287 void get_global_remove_arguments(po::options_description *positional,
288 po::options_description *options) {
289 add_config_entity_option(positional);
290 add_key_option(positional);
291 }
292
293 int execute_global_remove(
294 const po::variables_map &vm,
295 const std::vector<std::string> &ceph_global_init_args) {
296 std::string config_entity;
297 int r = get_config_entity(vm, &config_entity);
298 if (r < 0) {
299 return r;
300 }
301
302 std::string key;
303 size_t arg_index = 1;
304 r = get_key(vm, &arg_index, &key);
305 if (r < 0) {
306 return r;
307 }
308
309 librados::Rados rados;
310 r = utils::init_rados(&rados);
311 if (r < 0) {
312 return r;
313 }
314
315 std::string cmd =
316 "{"
317 "\"prefix\": \"config rm\", "
318 "\"who\": \"" + stringify(json_stream_escaper(config_entity)) + "\", "
319 "\"name\": \"" + key + "\""
320 "}";
321 bufferlist in_bl;
322 std::string ss;
323 r = rados.mon_command(cmd, in_bl, nullptr, &ss);
324 if (r < 0) {
325 std::cerr << "rbd: error removing " << key << ": " << ss << std::endl;
326 return r;
327 }
328
329 return 0;
330 }
331
332 void get_global_list_arguments(po::options_description *positional,
333 po::options_description *options) {
334 add_config_entity_option(positional);
335 at::add_format_options(options);
336 }
337
338 int execute_global_list(const po::variables_map &vm,
339 const std::vector<std::string> &ceph_global_init_args) {
340 std::string config_entity;
341 int r = get_config_entity(vm, &config_entity);
342 if (r < 0) {
343 return r;
344 }
345
346 at::Format::Formatter f;
347 r = utils::get_formatter(vm, &f);
348 if (r < 0) {
349 return r;
350 }
351
352 librados::Rados rados;
353 r = utils::init_rados(&rados);
354 if (r < 0) {
355 return r;
356 }
357
358 std::map<std::string, std::pair<std::string, std::string>> options;
359 r = config_global_list(rados, config_entity, &options);
360 if (r < 0) {
361 return r;
362 }
363
364 if (options.empty() && !f) {
365 return 0;
366 }
367
368 TextTable tbl;
369
370 if (f) {
371 f->open_array_section("config");
372 } else {
373 tbl.define_column("Name", TextTable::LEFT, TextTable::LEFT);
374 tbl.define_column("Value", TextTable::LEFT, TextTable::LEFT);
375 tbl.define_column("Section", TextTable::LEFT, TextTable::LEFT);
376 }
377
378 for (const auto &it : options) {
379 if (f) {
380 f->open_object_section("option");
381 f->dump_string("name", it.first);
382 f->dump_string("value", it.second.first);
383 f->dump_string("section", it.second.second);
384 f->close_section();
385 } else {
386 tbl << it.first << it.second.first << it.second.second
387 << TextTable::endrow;
388 }
389 }
390
391 if (f) {
392 f->close_section();
393 f->flush(std::cout);
394 } else {
395 std::cout << tbl;
396 }
397
398 return 0;
399 }
400
401 void get_pool_get_arguments(po::options_description *positional,
402 po::options_description *options) {
403 add_pool_option(positional);
404 add_key_option(positional);
405 }
406
407 int execute_pool_get(const po::variables_map &vm,
408 const std::vector<std::string> &ceph_global_init_args) {
409 std::string pool_name;
410 int r = get_pool(vm, &pool_name);
411 if (r < 0) {
412 return r;
413 }
414
415 std::string key;
416 size_t arg_index = 1;
417 r = get_key(vm, &arg_index, &key);
418 if (r < 0) {
419 return r;
420 }
421
422 librados::Rados rados;
423 librados::IoCtx io_ctx;
424 r = utils::init(pool_name, "", &rados, &io_ctx);
425 if (r < 0) {
426 return r;
427 }
428
429 librbd::RBD rbd;
430 std::string value;
431
432 r = rbd.pool_metadata_get(io_ctx, METADATA_CONF_PREFIX + key, &value);
433 if (r < 0) {
434 if (r == -ENOENT) {
435 std::cerr << "rbd: " << key << " is not set" << std::endl;
436 } else {
437 std::cerr << "rbd: failed to get " << key << ": " << cpp_strerror(r)
438 << std::endl;
439 }
440 return r;
441 }
442
443 std::cout << value << std::endl;
444 return 0;
445 }
446
447 void get_pool_set_arguments(po::options_description *positional,
448 po::options_description *options) {
449 add_pool_option(positional);
450 add_key_option(positional);
451 positional->add_options()
452 ("value", "config value");
453 }
454
455 int execute_pool_set(const po::variables_map &vm,
456 const std::vector<std::string> &ceph_global_init_args) {
457 std::string pool_name;
458 int r = get_pool(vm, &pool_name);
459 if (r < 0) {
460 return r;
461 }
462
463 std::string key;
464 size_t arg_index = 1;
465 r = get_key(vm, &arg_index, &key);
466 if (r < 0) {
467 return r;
468 }
469
470 std::string value = utils::get_positional_argument(vm, 2);
471
472 librados::Rados rados;
473 librados::IoCtx io_ctx;
474 r = utils::init(pool_name, "", &rados, &io_ctx);
475 if (r < 0) {
476 return r;
477 }
478
479 librbd::RBD rbd;
480 r = rbd.pool_metadata_set(io_ctx, METADATA_CONF_PREFIX + key, value);
481 if (r < 0) {
482 std::cerr << "rbd: failed to set " << key << ": " << cpp_strerror(r)
483 << std::endl;
484 return r;
485 }
486
487 return 0;
488 }
489
490 void get_pool_remove_arguments(po::options_description *positional,
491 po::options_description *options) {
492 add_pool_option(positional);
493 add_key_option(positional);
494 }
495
496 int execute_pool_remove(const po::variables_map &vm,
497 const std::vector<std::string> &ceph_global_init_args) {
498 std::string pool_name;
499 int r = get_pool(vm, &pool_name);
500 if (r < 0) {
501 return r;
502 }
503
504 std::string key;
505 size_t arg_index = 1;
506 r = get_key(vm, &arg_index, &key);
507 if (r < 0) {
508 return r;
509 }
510
511 librados::Rados rados;
512 librados::IoCtx io_ctx;
513 r = utils::init(pool_name, "", &rados, &io_ctx);
514 if (r < 0) {
515 return r;
516 }
517
518 librbd::RBD rbd;
519 r = rbd.pool_metadata_remove(io_ctx, METADATA_CONF_PREFIX + key);
520 if (r < 0) {
521 std::cerr << "rbd: failed to remove " << key << ": " << cpp_strerror(r)
522 << std::endl;
523 return r;
524 }
525
526 return 0;
527 }
528
529 void get_pool_list_arguments(po::options_description *positional,
530 po::options_description *options) {
531 add_pool_option(positional);
532 at::add_format_options(options);
533 }
534
535 int execute_pool_list(const po::variables_map &vm,
536 const std::vector<std::string> &ceph_global_init_args) {
537 std::string pool_name;
538 int r = get_pool(vm, &pool_name);
539 if (r < 0) {
540 return r;
541 }
542
543 at::Format::Formatter f;
544 r = utils::get_formatter(vm, &f);
545 if (r < 0) {
546 return r;
547 }
548
549 librados::Rados rados;
550 librados::IoCtx io_ctx;
551 r = utils::init(pool_name, "", &rados, &io_ctx);
552 if (r < 0) {
553 return r;
554 }
555
556 TextTable tbl;
557 librbd::RBD rbd;
558 std::vector<librbd::config_option_t> options;
559
560 r = rbd.config_list(io_ctx, &options);
561 if (r < 0) {
562 std::cerr << "rbd: failed to list config: " << cpp_strerror(r) << std::endl;
563 return r;
564 }
565
566 if (f) {
567 f->open_array_section("config");
568 } else {
569 tbl.define_column("Name", TextTable::LEFT, TextTable::LEFT);
570 tbl.define_column("Value", TextTable::LEFT, TextTable::LEFT);
571 tbl.define_column("Source", TextTable::LEFT, TextTable::LEFT);
572 }
573
574 for (auto &option : options) {
575 if (f) {
576 f->open_object_section("option");
577 f->dump_string("name", option.name);
578 f->dump_string("value", option.value);
579 f->dump_stream("source") << option.source;
580 f->close_section();
581 } else {
582 std::ostringstream source;
583 source << option.source;
584 tbl << option.name << option.value << source.str() << TextTable::endrow;
585 }
586 }
587
588 if (f) {
589 f->close_section();
590 f->flush(std::cout);
591 } else {
592 std::cout << tbl;
593 }
594
595 return 0;
596 }
597
598 void get_image_get_arguments(po::options_description *positional,
599 po::options_description *options) {
600 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
601 add_key_option(positional);
602 }
603
604 int execute_image_get(const po::variables_map &vm,
605 const std::vector<std::string> &ceph_global_init_args) {
606 size_t arg_index = 0;
607 std::string pool_name;
608 std::string namespace_name;
609 std::string image_name;
610 std::string snap_name;
611 int r = utils::get_pool_image_snapshot_names(
612 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
613 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
614 utils::SPEC_VALIDATION_NONE);
615 if (r < 0) {
616 return r;
617 }
618
619 std::string key;
620 r = get_key(vm, &arg_index, &key);
621 if (r < 0) {
622 return r;
623 }
624
625 librados::Rados rados;
626 librados::IoCtx io_ctx;
627 librbd::Image image;
628 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
629 false, &rados, &io_ctx, &image);
630 if (r < 0) {
631 return r;
632 }
633
634 std::string value;
635
636 r = image.metadata_get(METADATA_CONF_PREFIX + key, &value);
637 if (r < 0) {
638 if (r == -ENOENT) {
639 std::cerr << "rbd: " << key << " is not set" << std::endl;
640 } else {
641 std::cerr << "rbd: failed to get " << key << ": " << cpp_strerror(r)
642 << std::endl;
643 }
644 return r;
645 }
646
647 std::cout << value << std::endl;
648 return 0;
649 }
650
651 void get_image_set_arguments(po::options_description *positional,
652 po::options_description *options) {
653 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
654 add_key_option(positional);
655 positional->add_options()
656 ("value", "config value");
657 }
658
659 int execute_image_set(const po::variables_map &vm,
660 const std::vector<std::string> &ceph_global_init_args) {
661 size_t arg_index = 0;
662 std::string pool_name;
663 std::string namespace_name;
664 std::string image_name;
665 std::string snap_name;
666 int r = utils::get_pool_image_snapshot_names(
667 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
668 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
669 utils::SPEC_VALIDATION_NONE);
670 if (r < 0) {
671 return r;
672 }
673
674 std::string key;
675 r = get_key(vm, &arg_index, &key);
676 if (r < 0) {
677 return r;
678 }
679
680 std::string value = utils::get_positional_argument(vm, arg_index);
681 if (value.empty()) {
682 std::cerr << "rbd: image config value was not specified" << std::endl;
683 return -EINVAL;
684 }
685
686 librados::Rados rados;
687 librados::IoCtx io_ctx;
688 librbd::Image image;
689 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
690 false, &rados, &io_ctx, &image);
691 if (r < 0) {
692 return r;
693 }
694
695 r = image.metadata_set(METADATA_CONF_PREFIX + key, value);
696 if (r < 0) {
697 std::cerr << "rbd: failed to set " << key << ": " << cpp_strerror(r)
698 << std::endl;
699 return r;
700 }
701
702 return 0;
703 }
704
705 void get_image_remove_arguments(po::options_description *positional,
706 po::options_description *options) {
707 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
708 add_key_option(positional);
709 }
710
711 int execute_image_remove(
712 const po::variables_map &vm,
713 const std::vector<std::string> &ceph_global_init_args) {
714 size_t arg_index = 0;
715 std::string pool_name;
716 std::string namespace_name;
717 std::string image_name;
718 std::string snap_name;
719 int r = utils::get_pool_image_snapshot_names(
720 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
721 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
722 utils::SPEC_VALIDATION_NONE);
723 if (r < 0) {
724 return r;
725 }
726
727 std::string key;
728 r = get_key(vm, &arg_index, &key);
729 if (r < 0) {
730 return r;
731 }
732
733 librados::Rados rados;
734 librados::IoCtx io_ctx;
735 librbd::Image image;
736 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
737 false, &rados, &io_ctx, &image);
738 if (r < 0) {
739 return r;
740 }
741
742 r = image.metadata_remove(METADATA_CONF_PREFIX + key);
743 if (r < 0) {
744 std::cerr << "rbd: failed to remove " << key << ": " << cpp_strerror(r)
745 << std::endl;
746 return r;
747 }
748
749 return 0;
750 }
751
752 void get_image_list_arguments(po::options_description *positional,
753 po::options_description *options) {
754 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
755 at::add_format_options(options);
756 }
757
758 int execute_image_list(const po::variables_map &vm,
759 const std::vector<std::string> &ceph_global_init_args) {
760 size_t arg_index = 0;
761 std::string pool_name;
762 std::string namespace_name;
763 std::string image_name;
764 std::string snap_name;
765 int r = utils::get_pool_image_snapshot_names(
766 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
767 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
768 utils::SPEC_VALIDATION_NONE);
769 if (r < 0) {
770 return r;
771 }
772
773 at::Format::Formatter f;
774 r = utils::get_formatter(vm, &f);
775 if (r < 0) {
776 return r;
777 }
778
779 librados::Rados rados;
780 librados::IoCtx io_ctx;
781 librbd::Image image;
782 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
783 false, &rados, &io_ctx, &image);
784 if (r < 0) {
785 return r;
786 }
787
788 TextTable tbl;
789 std::vector<librbd::config_option_t> options;
790
791 r = image.config_list(&options);
792 if (r < 0) {
793 std::cerr << "rbd: failed to list config: " << cpp_strerror(r) << std::endl;
794 return r;
795 }
796
797 if (options.empty()) {
798 if (f == nullptr) {
799 std::cout << "There are no values" << std::endl;
800 }
801 return 0;
802 }
803
804 if (f) {
805 f->open_array_section("config");
806 } else {
807 tbl.define_column("Name", TextTable::LEFT, TextTable::LEFT);
808 tbl.define_column("Value", TextTable::LEFT, TextTable::LEFT);
809 tbl.define_column("Source", TextTable::LEFT, TextTable::LEFT);
810 }
811
812 for (auto &option : options) {
813 if (f) {
814 f->open_object_section("option");
815 f->dump_string("name", option.name);
816 f->dump_string("value", option.value);
817 f->dump_stream("source") << option.source;
818 f->close_section();
819 } else {
820 std::ostringstream source;
821 source << option.source;
822 tbl << option.name << option.value << source.str() << TextTable::endrow;
823 }
824 }
825
826 if (f == nullptr) {
827 bool single = (options.size() == 1);
828 std::cout << "There " << (single ? "is" : "are") << " " << options.size()
829 << " " << (single ? "value" : "values") << ":" << std::endl;
830 }
831
832 if (f) {
833 f->close_section();
834 f->flush(std::cout);
835 } else {
836 std::cout << tbl;
837 }
838
839 return 0;
840 }
841
842 Shell::Action action_global_get(
843 {"config", "global", "get"}, {},
844 "Get a global-level configuration override.", "",
845 &get_global_get_arguments, &execute_global_get);
846 Shell::Action action_global_set(
847 {"config", "global", "set"}, {},
848 "Set a global-level configuration override.", "",
849 &get_global_set_arguments, &execute_global_set);
850 Shell::Action action_global_remove(
851 {"config", "global", "remove"}, {"config", "global", "rm"},
852 "Remove a global-level configuration override.", "",
853 &get_global_remove_arguments, &execute_global_remove);
854 Shell::Action action_global_list(
855 {"config", "global", "list"}, {"config", "global", "ls"},
856 "List global-level configuration overrides.", "",
857 &get_global_list_arguments, &execute_global_list);
858
859 Shell::Action action_pool_get(
860 {"config", "pool", "get"}, {}, "Get a pool-level configuration override.", "",
861 &get_pool_get_arguments, &execute_pool_get);
862 Shell::Action action_pool_set(
863 {"config", "pool", "set"}, {}, "Set a pool-level configuration override.", "",
864 &get_pool_set_arguments, &execute_pool_set);
865 Shell::Action action_pool_remove(
866 {"config", "pool", "remove"}, {"config", "pool", "rm"},
867 "Remove a pool-level configuration override.", "",
868 &get_pool_remove_arguments, &execute_pool_remove);
869 Shell::Action action_pool_list(
870 {"config", "pool", "list"}, {"config", "pool", "ls"},
871 "List pool-level configuration overrides.", "",
872 &get_pool_list_arguments, &execute_pool_list);
873
874 Shell::Action action_image_get(
875 {"config", "image", "get"}, {}, "Get an image-level configuration override.",
876 "", &get_image_get_arguments, &execute_image_get);
877 Shell::Action action_image_set(
878 {"config", "image", "set"}, {}, "Set an image-level configuration override.",
879 "", &get_image_set_arguments, &execute_image_set);
880 Shell::Action action_image_remove(
881 {"config", "image", "remove"}, {"config", "image", "rm"},
882 "Remove an image-level configuration override.", "",
883 &get_image_remove_arguments, &execute_image_remove);
884 Shell::Action action_image_list(
885 {"config", "image", "list"}, {"config", "image", "ls"},
886 "List image-level configuration overrides.", "",
887 &get_image_list_arguments, &execute_image_list);
888
889 } // namespace config
890 } // namespace action
891 } // namespace rbd