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/Context.h"
8 #include "include/stringify.h"
9 #include "include/rbd/librbd.hpp"
10 #include "common/config.h"
11 #include "common/debug.h"
12 #include "common/errno.h"
13 #include "common/Formatter.h"
14 #include "common/TextTable.h"
15 #include "common/Throttle.h"
16 #include "global/global_context.h"
19 #include <boost/program_options.hpp>
20 #include <boost/regex.hpp>
21 #include "include/assert.h"
25 #define dout_context g_ceph_context
26 #define dout_subsys ceph_subsys_rbd
28 #define dout_prefix *_dout << "rbd::action::MirrorPool: "
32 namespace mirror_pool
{
34 namespace at
= argument_types
;
35 namespace po
= boost::program_options
;
39 int validate_mirroring_enabled(librados::IoCtx
& io_ctx
) {
41 rbd_mirror_mode_t mirror_mode
;
42 int r
= rbd
.mirror_mode_get(io_ctx
, &mirror_mode
);
44 std::cerr
<< "rbd: failed to retrieve mirror mode: "
45 << cpp_strerror(r
) << std::endl
;
49 if (mirror_mode
== RBD_MIRROR_MODE_DISABLED
) {
50 std::cerr
<< "rbd: mirroring not enabled on the pool" << std::endl
;
56 int validate_uuid(const std::string
&uuid
) {
57 boost::regex
pattern("^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$",
60 if (!boost::regex_match(uuid
, match
, pattern
)) {
61 std::cerr
<< "rbd: invalid uuid '" << uuid
<< "'" << std::endl
;
67 void add_uuid_option(po::options_description
*positional
) {
68 positional
->add_options()
69 ("uuid", po::value
<std::string
>(), "peer uuid");
72 int get_uuid(const po::variables_map
&vm
, size_t arg_index
,
74 *uuid
= utils::get_positional_argument(vm
, arg_index
);
76 std::cerr
<< "rbd: must specify peer uuid" << std::endl
;
79 return validate_uuid(*uuid
);
82 int get_remote_cluster_spec(const po::variables_map
&vm
,
83 const std::string
&spec
,
84 std::string
*remote_client_name
,
85 std::string
*remote_cluster
) {
86 if (vm
.count("remote-client-name")) {
87 *remote_client_name
= vm
["remote-client-name"].as
<std::string
>();
89 if (vm
.count("remote-cluster")) {
90 *remote_cluster
= vm
["remote-cluster"].as
<std::string
>();
94 boost::regex
pattern("^(?:(client\\.[^@]+)@)?([^/@]+)$");
96 if (!boost::regex_match(spec
, match
, pattern
)) {
97 std::cerr
<< "rbd: invalid spec '" << spec
<< "'" << std::endl
;
100 if (match
[1].matched
) {
101 *remote_client_name
= match
[1];
103 *remote_cluster
= match
[2];
106 if (remote_cluster
->empty()) {
107 std::cerr
<< "rbd: remote cluster was not specified" << std::endl
;
113 void format_mirror_peers(const std::string
&config_path
,
114 at::Format::Formatter formatter
,
115 const std::vector
<librbd::mirror_peer_t
> &peers
) {
116 if (formatter
!= nullptr) {
117 formatter
->open_array_section("peers");
118 for (auto &peer
: peers
) {
119 formatter
->open_object_section("peer");
120 formatter
->dump_string("uuid", peer
.uuid
);
121 formatter
->dump_string("cluster_name", peer
.cluster_name
);
122 formatter
->dump_string("client_name", peer
.client_name
);
123 formatter
->close_section();
125 formatter
->close_section();
127 std::cout
<< "Peers: ";
129 std::cout
<< "none" << std::endl
;
132 tbl
.define_column("", TextTable::LEFT
, TextTable::LEFT
);
133 tbl
.define_column("UUID", TextTable::LEFT
, TextTable::LEFT
);
134 tbl
.define_column("NAME", TextTable::LEFT
, TextTable::LEFT
);
135 tbl
.define_column("CLIENT", TextTable::LEFT
, TextTable::LEFT
);
136 for (auto &peer
: peers
) {
141 << TextTable::endrow
;
143 std::cout
<< std::endl
<< tbl
;
148 class ImageRequestBase
{
151 dout(20) << this << " " << __func__
<< ": image_name=" << m_image_name
154 auto ctx
= new FunctionContext([this](int r
) {
158 // will pause here until slots are available
159 m_finalize_ctx
= m_throttle
.start_op(ctx
);
165 ImageRequestBase(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
166 const std::string
&image_name
)
167 : m_io_ctx(io_ctx
), m_throttle(throttle
), m_image_name(image_name
) {
169 virtual ~ImageRequestBase() {
172 virtual bool skip_get_info() const {
175 virtual void get_info(librbd::Image
&image
, librbd::mirror_image_info_t
*info
,
176 librbd::RBD::AioCompletion
*aio_comp
) {
177 image
.aio_mirror_image_get_info(info
, sizeof(librbd::mirror_image_info_t
),
181 virtual bool skip_action(const librbd::mirror_image_info_t
&info
) const {
184 virtual void execute_action(librbd::Image
&image
,
185 librbd::RBD::AioCompletion
*aio_comp
) = 0;
186 virtual void handle_execute_action(int r
) {
187 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
189 if (r
< 0 && r
!= -ENOENT
) {
190 std::cerr
<< "rbd: failed to " << get_action_type() << " image "
191 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
198 virtual void finalize_action() {
200 virtual std::string
get_action_type() const = 0;
229 librados::IoCtx
&m_io_ctx
;
230 OrderedThrottle
&m_throttle
;
231 const std::string m_image_name
;
233 librbd::Image m_image
;
234 Context
*m_finalize_ctx
;
236 librbd::mirror_image_info_t m_mirror_image_info
;
241 dout(20) << this << " " << __func__
<< dendl
;
244 auto aio_completion
= utils::create_aio_completion
<
245 ImageRequestBase
, &ImageRequestBase::handle_open_image
>(this);
246 rbd
.aio_open(m_io_ctx
, m_image
, m_image_name
.c_str(), nullptr,
250 void handle_open_image(int r
) {
251 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
254 std::cerr
<< "rbd: failed to open image "
255 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
256 m_finalize_ctx
->complete(r
);
264 if (skip_get_info()) {
268 dout(20) << this << " " << __func__
<< dendl
;
270 auto aio_completion
= utils::create_aio_completion
<
271 ImageRequestBase
, &ImageRequestBase::handle_get_info
>(this);
272 get_info(m_image
, &m_mirror_image_info
, aio_completion
);
275 void handle_get_info(int r
) {
276 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
282 std::cerr
<< "rbd: failed to retrieve mirror image info for "
283 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
292 void execute_action() {
293 if (skip_action(m_mirror_image_info
)) {
297 dout(20) << this << " " << __func__
<< dendl
;
299 auto aio_completion
= utils::create_aio_completion
<
300 ImageRequestBase
, &ImageRequestBase::handle_execute_action
>(this);
301 execute_action(m_image
, aio_completion
);
305 dout(20) << this << " " << __func__
<< dendl
;
307 auto aio_completion
= utils::create_aio_completion
<
308 ImageRequestBase
, &ImageRequestBase::handle_close_image
>(this);
309 m_image
.aio_close(aio_completion
);
312 void handle_close_image(int r
) {
313 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
316 std::cerr
<< "rbd: failed to close image "
317 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
320 m_finalize_ctx
->complete(r
);
323 void handle_finalize(int r
) {
324 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
326 if (r
== 0 && m_ret_val
< 0) {
332 m_throttle
.end_op(r
);
337 class PromoteImageRequest
: public ImageRequestBase
{
339 PromoteImageRequest(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
340 const std::string
&image_name
, std::atomic
<unsigned> *counter
,
342 : ImageRequestBase(io_ctx
, throttle
, image_name
), m_counter(counter
),
347 bool skip_action(const librbd::mirror_image_info_t
&info
) const override
{
348 return (info
.state
!= RBD_MIRROR_IMAGE_ENABLED
|| info
.primary
);
351 void execute_action(librbd::Image
&image
,
352 librbd::RBD::AioCompletion
*aio_comp
) override
{
353 image
.aio_mirror_image_promote(m_force
, aio_comp
);
356 void handle_execute_action(int r
) override
{
360 ImageRequestBase::handle_execute_action(r
);
363 std::string
get_action_type() const override
{
368 std::atomic
<unsigned> *m_counter
= nullptr;
372 class DemoteImageRequest
: public ImageRequestBase
{
374 DemoteImageRequest(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
375 const std::string
&image_name
, std::atomic
<unsigned> *counter
)
376 : ImageRequestBase(io_ctx
, throttle
, image_name
), m_counter(counter
) {
380 bool skip_action(const librbd::mirror_image_info_t
&info
) const override
{
381 return (info
.state
!= RBD_MIRROR_IMAGE_ENABLED
|| !info
.primary
);
384 void execute_action(librbd::Image
&image
,
385 librbd::RBD::AioCompletion
*aio_comp
) override
{
386 image
.aio_mirror_image_demote(aio_comp
);
388 void handle_execute_action(int r
) override
{
392 ImageRequestBase::handle_execute_action(r
);
395 std::string
get_action_type() const override
{
400 std::atomic
<unsigned> *m_counter
= nullptr;
403 class StatusImageRequest
: public ImageRequestBase
{
405 StatusImageRequest(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
406 const std::string
&image_name
,
407 at::Format::Formatter formatter
)
408 : ImageRequestBase(io_ctx
, throttle
, image_name
),
409 m_formatter(formatter
) {
413 bool skip_get_info() const override
{
417 void execute_action(librbd::Image
&image
,
418 librbd::RBD::AioCompletion
*aio_comp
) override
{
419 image
.aio_mirror_image_get_status(&m_mirror_image_status
,
420 sizeof(m_mirror_image_status
), aio_comp
);
423 void finalize_action() override
{
424 if (m_mirror_image_status
.info
.global_id
.empty()) {
428 std::string state
= utils::mirror_image_status_state(m_mirror_image_status
);
429 std::string last_update
= (
430 m_mirror_image_status
.last_update
== 0 ?
431 "" : utils::timestr(m_mirror_image_status
.last_update
));
433 if (m_formatter
!= nullptr) {
434 m_formatter
->open_object_section("image");
435 m_formatter
->dump_string("name", m_mirror_image_status
.name
);
436 m_formatter
->dump_string("global_id",
437 m_mirror_image_status
.info
.global_id
);
438 m_formatter
->dump_string("state", state
);
439 m_formatter
->dump_string("description",
440 m_mirror_image_status
.description
);
441 m_formatter
->dump_string("last_update", last_update
);
442 m_formatter
->close_section(); // image
444 std::cout
<< "\n" << m_mirror_image_status
.name
<< ":\n"
446 << m_mirror_image_status
.info
.global_id
<< "\n"
447 << " state: " << state
<< "\n"
449 << m_mirror_image_status
.description
<< "\n"
450 << " last_update: " << last_update
<< std::endl
;
454 std::string
get_action_type() const override
{
459 at::Format::Formatter m_formatter
;
460 librbd::mirror_image_status_t m_mirror_image_status
;
464 template <typename RequestT
>
465 class ImageRequestAllocator
{
467 template <class... Args
>
468 RequestT
*operator()(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
469 const std::string
&image_name
, Args
&&... args
) {
470 return new RequestT(io_ctx
, throttle
, image_name
,
471 std::forward
<Args
>(args
)...);
475 template <typename RequestT
>
476 class ImageRequestGenerator
{
478 template <class... Args
>
479 ImageRequestGenerator(librados::IoCtx
&io_ctx
, Args
&&... args
)
481 m_factory(std::bind(ImageRequestAllocator
<RequestT
>(),
482 std::ref(m_io_ctx
), std::ref(m_throttle
),
483 std::placeholders::_1
, std::forward
<Args
>(args
)...)),
484 m_throttle(g_conf
->get_val
<int64_t>("rbd_concurrent_management_ops"),
489 // use the alphabetical list of image names for pool-level
490 // mirror image operations
492 int r
= rbd
.list(m_io_ctx
, m_image_names
);
493 if (r
< 0 && r
!= -ENOENT
) {
494 std::cerr
<< "rbd: failed to list images within pool" << std::endl
;
498 for (auto &image_name
: m_image_names
) {
499 auto request
= m_factory(image_name
);
503 return m_throttle
.wait_for_ret();
506 typedef std::function
<RequestT
*(const std::string
&)> Factory
;
508 librados::IoCtx
&m_io_ctx
;
511 OrderedThrottle m_throttle
;
513 std::vector
<std::string
> m_image_names
;
517 } // anonymous namespace
519 void get_peer_add_arguments(po::options_description
*positional
,
520 po::options_description
*options
) {
521 at::add_pool_options(positional
, options
);
522 positional
->add_options()
523 ("remote-cluster-spec", "remote cluster spec\n"
524 "(example: [<client name>@]<cluster name>");
525 options
->add_options()
526 ("remote-client-name", po::value
<std::string
>(), "remote client name")
527 ("remote-cluster", po::value
<std::string
>(), "remote cluster name");
530 int execute_peer_add(const po::variables_map
&vm
) {
531 size_t arg_index
= 0;
532 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
534 std::string remote_client_name
= g_ceph_context
->_conf
->name
.to_str();
535 std::string remote_cluster
;
536 int r
= get_remote_cluster_spec(
537 vm
, utils::get_positional_argument(vm
, arg_index
),
538 &remote_client_name
, &remote_cluster
);
543 std::string config_path
;
544 if (vm
.count(at::CONFIG_PATH
)) {
545 config_path
= vm
[at::CONFIG_PATH
].as
<std::string
>();
548 librados::Rados rados
;
549 librados::IoCtx io_ctx
;
550 r
= utils::init(pool_name
, &rados
, &io_ctx
);
555 r
= validate_mirroring_enabled(io_ctx
);
560 // TODO: temporary restriction to prevent adding multiple peers
561 // until rbd-mirror daemon can properly handle the scenario
563 std::vector
<librbd::mirror_peer_t
> mirror_peers
;
564 r
= rbd
.mirror_peer_list(io_ctx
, &mirror_peers
);
566 std::cerr
<< "rbd: failed to list mirror peers" << std::endl
;
569 if (!mirror_peers
.empty()) {
570 std::cerr
<< "rbd: multiple peers are not currently supported" << std::endl
;
575 r
= rbd
.mirror_peer_add(io_ctx
, &uuid
, remote_cluster
, remote_client_name
);
577 std::cerr
<< "rbd: error adding mirror peer" << std::endl
;
581 std::cout
<< uuid
<< std::endl
;
585 void get_peer_remove_arguments(po::options_description
*positional
,
586 po::options_description
*options
) {
587 at::add_pool_options(positional
, options
);
588 add_uuid_option(positional
);
591 int execute_peer_remove(const po::variables_map
&vm
) {
592 size_t arg_index
= 0;
593 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
596 int r
= get_uuid(vm
, arg_index
, &uuid
);
601 librados::Rados rados
;
602 librados::IoCtx io_ctx
;
603 r
= utils::init(pool_name
, &rados
, &io_ctx
);
608 r
= validate_mirroring_enabled(io_ctx
);
614 r
= rbd
.mirror_peer_remove(io_ctx
, uuid
);
616 std::cerr
<< "rbd: error removing mirror peer" << std::endl
;
622 void get_peer_set_arguments(po::options_description
*positional
,
623 po::options_description
*options
) {
624 at::add_pool_options(positional
, options
);
625 add_uuid_option(positional
);
626 positional
->add_options()
627 ("key", "peer parameter [client or cluster]")
628 ("value", "new client or cluster name");
631 int execute_peer_set(const po::variables_map
&vm
) {
632 size_t arg_index
= 0;
633 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
636 int r
= get_uuid(vm
, arg_index
++, &uuid
);
641 std::string key
= utils::get_positional_argument(vm
, arg_index
++);
642 if (key
!= "client" && key
!= "cluster") {
643 std::cerr
<< "rbd: must specify 'client' or 'cluster' key." << std::endl
;
647 std::string value
= utils::get_positional_argument(vm
, arg_index
++);
649 std::cerr
<< "rbd: must specify new " << key
<< " value." << std::endl
;
652 librados::Rados rados
;
653 librados::IoCtx io_ctx
;
654 r
= utils::init(pool_name
, &rados
, &io_ctx
);
659 r
= validate_mirroring_enabled(io_ctx
);
665 if (key
== "client") {
666 r
= rbd
.mirror_peer_set_client(io_ctx
, uuid
.c_str(), value
.c_str());
668 r
= rbd
.mirror_peer_set_cluster(io_ctx
, uuid
.c_str(), value
.c_str());
676 void get_disable_arguments(po::options_description
*positional
,
677 po::options_description
*options
) {
678 at::add_pool_options(positional
, options
);
681 void get_enable_arguments(po::options_description
*positional
,
682 po::options_description
*options
) {
683 at::add_pool_options(positional
, options
);
684 positional
->add_options()
685 ("mode", "mirror mode [image or pool]");
688 int execute_enable_disable(const std::string
&pool_name
,
689 rbd_mirror_mode_t next_mirror_mode
,
690 const std::string
&mode
) {
691 librados::Rados rados
;
692 librados::IoCtx io_ctx
;
693 rbd_mirror_mode_t current_mirror_mode
;
695 int r
= utils::init(pool_name
, &rados
, &io_ctx
);
701 r
= rbd
.mirror_mode_get(io_ctx
, ¤t_mirror_mode
);
703 std::cerr
<< "rbd: failed to retrieve mirror mode: "
704 << cpp_strerror(r
) << std::endl
;
708 if (current_mirror_mode
== next_mirror_mode
) {
709 if (mode
== "disabled") {
710 std::cout
<< "mirroring is already " << mode
<< std::endl
;
712 std::cout
<< "mirroring is already configured for "
713 << mode
<< " mode" << std::endl
;
716 } else if (next_mirror_mode
== RBD_MIRROR_MODE_IMAGE
&&
717 current_mirror_mode
== RBD_MIRROR_MODE_POOL
) {
718 std::cout
<< "note: changing mirroring mode from pool to image"
720 } else if (next_mirror_mode
== RBD_MIRROR_MODE_POOL
&&
721 current_mirror_mode
== RBD_MIRROR_MODE_IMAGE
) {
722 std::cout
<< "note: changing mirroring mode from image to pool"
726 r
= rbd
.mirror_mode_set(io_ctx
, next_mirror_mode
);
733 int execute_disable(const po::variables_map
&vm
) {
734 size_t arg_index
= 0;
735 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
737 return execute_enable_disable(pool_name
, RBD_MIRROR_MODE_DISABLED
,
741 int execute_enable(const po::variables_map
&vm
) {
742 size_t arg_index
= 0;
743 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
745 rbd_mirror_mode_t mirror_mode
;
746 std::string mode
= utils::get_positional_argument(vm
, arg_index
++);
747 if (mode
== "image") {
748 mirror_mode
= RBD_MIRROR_MODE_IMAGE
;
749 } else if (mode
== "pool") {
750 mirror_mode
= RBD_MIRROR_MODE_POOL
;
752 std::cerr
<< "rbd: must specify 'image' or 'pool' mode." << std::endl
;
756 return execute_enable_disable(pool_name
, mirror_mode
, mode
);
759 void get_info_arguments(po::options_description
*positional
,
760 po::options_description
*options
) {
761 at::add_pool_options(positional
, options
);
762 at::add_format_options(options
);
765 int execute_info(const po::variables_map
&vm
) {
766 size_t arg_index
= 0;
767 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
769 at::Format::Formatter formatter
;
770 int r
= utils::get_formatter(vm
, &formatter
);
775 std::string config_path
;
776 if (vm
.count(at::CONFIG_PATH
)) {
777 config_path
= vm
[at::CONFIG_PATH
].as
<std::string
>();
780 librados::Rados rados
;
781 librados::IoCtx io_ctx
;
782 r
= utils::init(pool_name
, &rados
, &io_ctx
);
788 rbd_mirror_mode_t mirror_mode
;
789 r
= rbd
.mirror_mode_get(io_ctx
, &mirror_mode
);
794 std::vector
<librbd::mirror_peer_t
> mirror_peers
;
795 r
= rbd
.mirror_peer_list(io_ctx
, &mirror_peers
);
800 std::string mirror_mode_desc
;
801 switch (mirror_mode
) {
802 case RBD_MIRROR_MODE_DISABLED
:
803 mirror_mode_desc
= "disabled";
805 case RBD_MIRROR_MODE_IMAGE
:
806 mirror_mode_desc
= "image";
808 case RBD_MIRROR_MODE_POOL
:
809 mirror_mode_desc
= "pool";
812 mirror_mode_desc
= "unknown";
816 if (formatter
!= nullptr) {
817 formatter
->open_object_section("mirror");
818 formatter
->dump_string("mode", mirror_mode_desc
);
820 std::cout
<< "Mode: " << mirror_mode_desc
<< std::endl
;
823 if (mirror_mode
!= RBD_MIRROR_MODE_DISABLED
) {
824 format_mirror_peers(config_path
, formatter
, mirror_peers
);
826 if (formatter
!= nullptr) {
827 formatter
->close_section();
828 formatter
->flush(std::cout
);
833 void get_status_arguments(po::options_description
*positional
,
834 po::options_description
*options
) {
835 at::add_pool_options(positional
, options
);
836 at::add_format_options(options
);
837 at::add_verbose_option(options
);
840 int execute_status(const po::variables_map
&vm
) {
841 size_t arg_index
= 0;
842 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
844 at::Format::Formatter formatter
;
845 int r
= utils::get_formatter(vm
, &formatter
);
850 bool verbose
= vm
[at::VERBOSE
].as
<bool>();
852 std::string config_path
;
853 if (vm
.count(at::CONFIG_PATH
)) {
854 config_path
= vm
[at::CONFIG_PATH
].as
<std::string
>();
857 librados::Rados rados
;
858 librados::IoCtx io_ctx
;
859 r
= utils::init(pool_name
, &rados
, &io_ctx
);
864 r
= validate_mirroring_enabled(io_ctx
);
871 std::map
<librbd::mirror_image_status_state_t
, int> states
;
872 r
= rbd
.mirror_image_status_summary(io_ctx
, &states
);
874 std::cerr
<< "rbd: failed to get status summary for mirrored images: "
875 << cpp_strerror(r
) << std::endl
;
879 if (formatter
!= nullptr) {
880 formatter
->open_object_section("status");
883 enum Health
{Ok
= 0, Warning
= 1, Error
= 2} health
= Ok
;
884 const char *names
[] = {"OK", "WARNING", "ERROR"};
887 for (auto &it
: states
) {
888 auto &state
= it
.first
;
889 if (health
< Warning
&&
890 (state
!= MIRROR_IMAGE_STATUS_STATE_REPLAYING
&&
891 state
!= MIRROR_IMAGE_STATUS_STATE_STOPPED
)) {
894 if (health
< Error
&&
895 state
== MIRROR_IMAGE_STATUS_STATE_ERROR
) {
901 if (formatter
!= nullptr) {
902 formatter
->open_object_section("summary");
903 formatter
->dump_string("health", names
[health
]);
904 formatter
->open_object_section("states");
905 for (auto &it
: states
) {
906 std::string state_name
= utils::mirror_image_status_state(it
.first
);
907 formatter
->dump_int(state_name
.c_str(), it
.second
);
909 formatter
->close_section(); // states
910 formatter
->close_section(); // summary
912 std::cout
<< "health: " << names
[health
] << std::endl
;
913 std::cout
<< "images: " << total
<< " total" << std::endl
;
914 for (auto &it
: states
) {
915 std::cout
<< " " << it
.second
<< " "
916 << utils::mirror_image_status_state(it
.first
) << std::endl
;
923 if (formatter
!= nullptr) {
924 formatter
->open_array_section("images");
927 ImageRequestGenerator
<StatusImageRequest
> generator(io_ctx
, formatter
);
928 ret
= generator
.execute();
930 if (formatter
!= nullptr) {
931 formatter
->close_section(); // images
935 if (formatter
!= nullptr) {
936 formatter
->close_section(); // status
937 formatter
->flush(std::cout
);
943 void get_promote_arguments(po::options_description
*positional
,
944 po::options_description
*options
) {
945 options
->add_options()
946 ("force", po::bool_switch(),
947 "promote even if not cleanly demoted by remote cluster");
948 at::add_pool_options(positional
, options
);
951 int execute_promote(const po::variables_map
&vm
) {
952 size_t arg_index
= 0;
953 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
955 librados::Rados rados
;
956 librados::IoCtx io_ctx
;
957 int r
= utils::init(pool_name
, &rados
, &io_ctx
);
962 r
= validate_mirroring_enabled(io_ctx
);
967 std::atomic
<unsigned> counter
= { 0 };
968 ImageRequestGenerator
<PromoteImageRequest
> generator(io_ctx
, &counter
,
969 vm
["force"].as
<bool>());
970 r
= generator
.execute();
972 std::cout
<< "Promoted " << counter
.load() << " mirrored images" << std::endl
;
976 void get_demote_arguments(po::options_description
*positional
,
977 po::options_description
*options
) {
978 at::add_pool_options(positional
, options
);
981 int execute_demote(const po::variables_map
&vm
) {
982 size_t arg_index
= 0;
983 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
985 librados::Rados rados
;
986 librados::IoCtx io_ctx
;
987 int r
= utils::init(pool_name
, &rados
, &io_ctx
);
992 r
= validate_mirroring_enabled(io_ctx
);
997 std::atomic
<unsigned> counter
{ 0 };
998 ImageRequestGenerator
<DemoteImageRequest
> generator(io_ctx
, &counter
);
999 r
= generator
.execute();
1001 std::cout
<< "Demoted " << counter
.load() << " mirrored images" << std::endl
;
1005 Shell::Action
action_add(
1006 {"mirror", "pool", "peer", "add"}, {},
1007 "Add a mirroring peer to a pool.", "",
1008 &get_peer_add_arguments
, &execute_peer_add
);
1009 Shell::Action
action_remove(
1010 {"mirror", "pool", "peer", "remove"}, {},
1011 "Remove a mirroring peer from a pool.", "",
1012 &get_peer_remove_arguments
, &execute_peer_remove
);
1013 Shell::Action
action_set(
1014 {"mirror", "pool", "peer", "set"}, {},
1015 "Update mirroring peer settings.", "",
1016 &get_peer_set_arguments
, &execute_peer_set
);
1018 Shell::Action
action_disable(
1019 {"mirror", "pool", "disable"}, {},
1020 "Disable RBD mirroring by default within a pool.", "",
1021 &get_disable_arguments
, &execute_disable
);
1022 Shell::Action
action_enable(
1023 {"mirror", "pool", "enable"}, {},
1024 "Enable RBD mirroring by default within a pool.", "",
1025 &get_enable_arguments
, &execute_enable
);
1026 Shell::Action
action_info(
1027 {"mirror", "pool", "info"}, {},
1028 "Show information about the pool mirroring configuration.", {},
1029 &get_info_arguments
, &execute_info
);
1030 Shell::Action
action_status(
1031 {"mirror", "pool", "status"}, {},
1032 "Show status for all mirrored images in the pool.", {},
1033 &get_status_arguments
, &execute_status
);
1034 Shell::Action
action_promote(
1035 {"mirror", "pool", "promote"}, {},
1036 "Promote all non-primary images in the pool.", {},
1037 &get_promote_arguments
, &execute_promote
);
1038 Shell::Action
action_demote(
1039 {"mirror", "pool", "demote"}, {},
1040 "Demote all primary images in the pool.", {},
1041 &get_demote_arguments
, &execute_demote
);
1043 } // namespace mirror_pool
1044 } // namespace action