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_uuid(const std::string
&uuid
) {
40 boost::regex
pattern("^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$",
43 if (!boost::regex_match(uuid
, match
, pattern
)) {
44 std::cerr
<< "rbd: invalid uuid '" << uuid
<< "'" << std::endl
;
50 void add_uuid_option(po::options_description
*positional
) {
51 positional
->add_options()
52 ("uuid", po::value
<std::string
>(), "peer uuid");
55 int get_uuid(const po::variables_map
&vm
, size_t arg_index
,
57 *uuid
= utils::get_positional_argument(vm
, arg_index
);
59 std::cerr
<< "rbd: must specify peer uuid" << std::endl
;
62 return validate_uuid(*uuid
);
65 int get_remote_cluster_spec(const po::variables_map
&vm
,
66 const std::string
&spec
,
67 std::string
*remote_client_name
,
68 std::string
*remote_cluster
) {
69 if (vm
.count("remote-client-name")) {
70 *remote_client_name
= vm
["remote-client-name"].as
<std::string
>();
72 if (vm
.count("remote-cluster")) {
73 *remote_cluster
= vm
["remote-cluster"].as
<std::string
>();
77 boost::regex
pattern("^(?:(client\\.[^@]+)@)?([^/@]+)$");
79 if (!boost::regex_match(spec
, match
, pattern
)) {
80 std::cerr
<< "rbd: invalid spec '" << spec
<< "'" << std::endl
;
83 if (match
[1].matched
) {
84 *remote_client_name
= match
[1];
86 *remote_cluster
= match
[2];
89 if (remote_cluster
->empty()) {
90 std::cerr
<< "rbd: remote cluster was not specified" << std::endl
;
96 void format_mirror_peers(const std::string
&config_path
,
97 at::Format::Formatter formatter
,
98 const std::vector
<librbd::mirror_peer_t
> &peers
) {
99 if (formatter
!= nullptr) {
100 formatter
->open_array_section("peers");
101 for (auto &peer
: peers
) {
102 formatter
->open_object_section("peer");
103 formatter
->dump_string("uuid", peer
.uuid
);
104 formatter
->dump_string("cluster_name", peer
.cluster_name
);
105 formatter
->dump_string("client_name", peer
.client_name
);
106 formatter
->close_section();
108 formatter
->close_section();
110 std::cout
<< "Peers: ";
112 std::cout
<< "none" << std::endl
;
115 tbl
.define_column("", TextTable::LEFT
, TextTable::LEFT
);
116 tbl
.define_column("UUID", TextTable::LEFT
, TextTable::LEFT
);
117 tbl
.define_column("NAME", TextTable::LEFT
, TextTable::LEFT
);
118 tbl
.define_column("CLIENT", TextTable::LEFT
, TextTable::LEFT
);
119 for (auto &peer
: peers
) {
124 << TextTable::endrow
;
126 std::cout
<< std::endl
<< tbl
;
131 class ImageRequestBase
{
134 dout(20) << this << " " << __func__
<< ": image_name=" << m_image_name
137 auto ctx
= new FunctionContext([this](int r
) {
141 // will pause here until slots are available
142 m_finalize_ctx
= m_throttle
.start_op(ctx
);
148 ImageRequestBase(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
149 const std::string
&image_name
)
150 : m_io_ctx(io_ctx
), m_throttle(throttle
), m_image_name(image_name
) {
152 virtual ~ImageRequestBase() {
155 virtual bool skip_get_info() const {
158 virtual void get_info(librbd::Image
&image
, librbd::mirror_image_info_t
*info
,
159 librbd::RBD::AioCompletion
*aio_comp
) {
160 image
.aio_mirror_image_get_info(info
, sizeof(librbd::mirror_image_info_t
),
164 virtual bool skip_action(const librbd::mirror_image_info_t
&info
) const {
167 virtual void execute_action(librbd::Image
&image
,
168 librbd::RBD::AioCompletion
*aio_comp
) = 0;
169 virtual void handle_execute_action(int r
) {
170 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
172 if (r
< 0 && r
!= -ENOENT
) {
173 std::cerr
<< "rbd: failed to " << get_action_type() << " image "
174 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
181 virtual void finalize_action() {
183 virtual std::string
get_action_type() const = 0;
212 librados::IoCtx
&m_io_ctx
;
213 OrderedThrottle
&m_throttle
;
214 const std::string m_image_name
;
216 librbd::Image m_image
;
217 Context
*m_finalize_ctx
;
219 librbd::mirror_image_info_t m_mirror_image_info
;
224 dout(20) << this << " " << __func__
<< dendl
;
227 auto aio_completion
= utils::create_aio_completion
<
228 ImageRequestBase
, &ImageRequestBase::handle_open_image
>(this);
229 rbd
.aio_open(m_io_ctx
, m_image
, m_image_name
.c_str(), nullptr,
233 void handle_open_image(int r
) {
234 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
237 std::cerr
<< "rbd: failed to open image "
238 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
239 m_finalize_ctx
->complete(r
);
247 if (skip_get_info()) {
251 dout(20) << this << " " << __func__
<< dendl
;
253 auto aio_completion
= utils::create_aio_completion
<
254 ImageRequestBase
, &ImageRequestBase::handle_get_info
>(this);
255 get_info(m_image
, &m_mirror_image_info
, aio_completion
);
258 void handle_get_info(int r
) {
259 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
265 std::cerr
<< "rbd: failed to retrieve mirror image info for "
266 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
275 void execute_action() {
276 if (skip_action(m_mirror_image_info
)) {
280 dout(20) << this << " " << __func__
<< dendl
;
282 auto aio_completion
= utils::create_aio_completion
<
283 ImageRequestBase
, &ImageRequestBase::handle_execute_action
>(this);
284 execute_action(m_image
, aio_completion
);
288 dout(20) << this << " " << __func__
<< dendl
;
290 auto aio_completion
= utils::create_aio_completion
<
291 ImageRequestBase
, &ImageRequestBase::handle_close_image
>(this);
292 m_image
.aio_close(aio_completion
);
295 void handle_close_image(int r
) {
296 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
299 std::cerr
<< "rbd: failed to close image "
300 << m_image_name
<< ": " << cpp_strerror(r
) << std::endl
;
303 m_finalize_ctx
->complete(r
);
306 void handle_finalize(int r
) {
307 dout(20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
309 if (r
== 0 && m_ret_val
< 0) {
315 m_throttle
.end_op(r
);
320 class PromoteImageRequest
: public ImageRequestBase
{
322 PromoteImageRequest(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
323 const std::string
&image_name
, std::atomic
<unsigned> *counter
,
325 : ImageRequestBase(io_ctx
, throttle
, image_name
), m_counter(counter
),
330 bool skip_action(const librbd::mirror_image_info_t
&info
) const override
{
334 void execute_action(librbd::Image
&image
,
335 librbd::RBD::AioCompletion
*aio_comp
) override
{
336 image
.aio_mirror_image_promote(m_force
, aio_comp
);
339 void handle_execute_action(int r
) override
{
345 std::string
get_action_type() const override
{
350 std::atomic
<unsigned> *m_counter
= nullptr;
354 class DemoteImageRequest
: public ImageRequestBase
{
356 DemoteImageRequest(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
357 const std::string
&image_name
, std::atomic
<unsigned> *counter
)
358 : ImageRequestBase(io_ctx
, throttle
, image_name
), m_counter(counter
) {
362 bool skip_action(const librbd::mirror_image_info_t
&info
) const override
{
363 return !info
.primary
;
366 void execute_action(librbd::Image
&image
,
367 librbd::RBD::AioCompletion
*aio_comp
) override
{
368 image
.aio_mirror_image_demote(aio_comp
);
370 void handle_execute_action(int r
) override
{
374 ImageRequestBase::handle_execute_action(r
);
377 std::string
get_action_type() const override
{
382 std::atomic
<unsigned> *m_counter
= nullptr;
385 class StatusImageRequest
: public ImageRequestBase
{
387 StatusImageRequest(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
388 const std::string
&image_name
,
389 at::Format::Formatter formatter
)
390 : ImageRequestBase(io_ctx
, throttle
, image_name
),
391 m_formatter(formatter
) {
395 bool skip_get_info() const override
{
399 void execute_action(librbd::Image
&image
,
400 librbd::RBD::AioCompletion
*aio_comp
) override
{
401 image
.aio_mirror_image_get_status(&m_mirror_image_status
,
402 sizeof(m_mirror_image_status
), aio_comp
);
405 void finalize_action() override
{
406 std::string state
= utils::mirror_image_status_state(m_mirror_image_status
);
407 std::string last_update
= (
408 m_mirror_image_status
.last_update
== 0 ?
409 "" : utils::timestr(m_mirror_image_status
.last_update
));
411 if (m_formatter
!= nullptr) {
412 m_formatter
->open_object_section("image");
413 m_formatter
->dump_string("name", m_mirror_image_status
.name
);
414 m_formatter
->dump_string("global_id",
415 m_mirror_image_status
.info
.global_id
);
416 m_formatter
->dump_string("state", state
);
417 m_formatter
->dump_string("description",
418 m_mirror_image_status
.description
);
419 m_formatter
->dump_string("last_update", last_update
);
420 m_formatter
->close_section(); // image
422 std::cout
<< "\n" << m_mirror_image_status
.name
<< ":\n"
424 << m_mirror_image_status
.info
.global_id
<< "\n"
425 << " state: " << state
<< "\n"
427 << m_mirror_image_status
.description
<< "\n"
428 << " last_update: " << last_update
<< std::endl
;
432 std::string
get_action_type() const override
{
437 at::Format::Formatter m_formatter
;
438 librbd::mirror_image_status_t m_mirror_image_status
;
442 template <typename RequestT
>
443 class ImageRequestAllocator
{
445 template <class... Args
>
446 RequestT
*operator()(librados::IoCtx
&io_ctx
, OrderedThrottle
&throttle
,
447 const std::string
&image_name
, Args
&&... args
) {
448 return new RequestT(io_ctx
, throttle
, image_name
,
449 std::forward
<Args
>(args
)...);
453 template <typename RequestT
>
454 class ImageRequestGenerator
{
456 template <class... Args
>
457 ImageRequestGenerator(librados::IoCtx
&io_ctx
, Args
&&... args
)
459 m_factory(std::bind(ImageRequestAllocator
<RequestT
>(),
460 std::ref(m_io_ctx
), std::ref(m_throttle
),
461 std::placeholders::_1
, std::forward
<Args
>(args
)...)),
462 m_throttle(g_conf
->rbd_concurrent_management_ops
, true) {
466 // use the alphabetical list of image names for pool-level
467 // mirror image operations
469 int r
= rbd
.list(m_io_ctx
, m_image_names
);
470 if (r
< 0 && r
!= -ENOENT
) {
471 std::cerr
<< "rbd: failed to list images within pool" << std::endl
;
475 for (auto &image_name
: m_image_names
) {
476 auto request
= m_factory(image_name
);
480 return m_throttle
.wait_for_ret();
483 typedef std::function
<RequestT
*(const std::string
&)> Factory
;
485 librados::IoCtx
&m_io_ctx
;
488 OrderedThrottle m_throttle
;
490 std::vector
<std::string
> m_image_names
;
494 } // anonymous namespace
496 void get_peer_add_arguments(po::options_description
*positional
,
497 po::options_description
*options
) {
498 at::add_pool_options(positional
, options
);
499 positional
->add_options()
500 ("remote-cluster-spec", "remote cluster spec\n"
501 "(example: [<client name>@]<cluster name>");
502 options
->add_options()
503 ("remote-client-name", po::value
<std::string
>(), "remote client name")
504 ("remote-cluster", po::value
<std::string
>(), "remote cluster name");
507 int execute_peer_add(const po::variables_map
&vm
) {
508 size_t arg_index
= 0;
509 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
511 std::string remote_client_name
= g_ceph_context
->_conf
->name
.to_str();
512 std::string remote_cluster
;
513 int r
= get_remote_cluster_spec(
514 vm
, utils::get_positional_argument(vm
, arg_index
),
515 &remote_client_name
, &remote_cluster
);
520 std::string config_path
;
521 if (vm
.count(at::CONFIG_PATH
)) {
522 config_path
= vm
[at::CONFIG_PATH
].as
<std::string
>();
525 librados::Rados rados
;
526 librados::IoCtx io_ctx
;
527 r
= utils::init(pool_name
, &rados
, &io_ctx
);
533 rbd_mirror_mode_t mirror_mode
;
534 r
= rbd
.mirror_mode_get(io_ctx
, &mirror_mode
);
536 std::cerr
<< "rbd: failed to retrieve mirror mode: "
537 << cpp_strerror(r
) << std::endl
;
541 if (mirror_mode
== RBD_MIRROR_MODE_DISABLED
) {
542 std::cerr
<< "rbd: failed to add mirror peer: "
543 << "mirroring must be enabled on the pool "
544 << pool_name
<< std::endl
;
548 // TODO: temporary restriction to prevent adding multiple peers
549 // until rbd-mirror daemon can properly handle the scenario
550 std::vector
<librbd::mirror_peer_t
> mirror_peers
;
551 r
= rbd
.mirror_peer_list(io_ctx
, &mirror_peers
);
553 std::cerr
<< "rbd: failed to list mirror peers" << std::endl
;
556 if (!mirror_peers
.empty()) {
557 std::cerr
<< "rbd: multiple peers are not currently supported" << std::endl
;
562 r
= rbd
.mirror_peer_add(io_ctx
, &uuid
, remote_cluster
, remote_client_name
);
564 std::cerr
<< "rbd: error adding mirror peer" << std::endl
;
568 std::cout
<< uuid
<< std::endl
;
572 void get_peer_remove_arguments(po::options_description
*positional
,
573 po::options_description
*options
) {
574 at::add_pool_options(positional
, options
);
575 add_uuid_option(positional
);
578 int execute_peer_remove(const po::variables_map
&vm
) {
579 size_t arg_index
= 0;
580 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
583 int r
= get_uuid(vm
, arg_index
, &uuid
);
588 librados::Rados rados
;
589 librados::IoCtx io_ctx
;
590 r
= utils::init(pool_name
, &rados
, &io_ctx
);
596 r
= rbd
.mirror_peer_remove(io_ctx
, uuid
);
598 std::cerr
<< "rbd: error removing mirror peer" << std::endl
;
604 void get_peer_set_arguments(po::options_description
*positional
,
605 po::options_description
*options
) {
606 at::add_pool_options(positional
, options
);
607 add_uuid_option(positional
);
608 positional
->add_options()
609 ("key", "peer parameter [client or cluster]")
610 ("value", "new client or cluster name");
613 int execute_peer_set(const po::variables_map
&vm
) {
614 size_t arg_index
= 0;
615 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
618 int r
= get_uuid(vm
, arg_index
++, &uuid
);
623 std::string key
= utils::get_positional_argument(vm
, arg_index
++);
624 if (key
!= "client" && key
!= "cluster") {
625 std::cerr
<< "rbd: must specify 'client' or 'cluster' key." << std::endl
;
629 std::string value
= utils::get_positional_argument(vm
, arg_index
++);
631 std::cerr
<< "rbd: must specify new " << key
<< " value." << std::endl
;
634 librados::Rados rados
;
635 librados::IoCtx io_ctx
;
636 r
= utils::init(pool_name
, &rados
, &io_ctx
);
642 if (key
== "client") {
643 r
= rbd
.mirror_peer_set_client(io_ctx
, uuid
.c_str(), value
.c_str());
645 r
= rbd
.mirror_peer_set_cluster(io_ctx
, uuid
.c_str(), value
.c_str());
653 void get_disable_arguments(po::options_description
*positional
,
654 po::options_description
*options
) {
655 at::add_pool_options(positional
, options
);
658 void get_enable_arguments(po::options_description
*positional
,
659 po::options_description
*options
) {
660 at::add_pool_options(positional
, options
);
661 positional
->add_options()
662 ("mode", "mirror mode [image or pool]");
665 int execute_enable_disable(const std::string
&pool_name
,
666 rbd_mirror_mode_t next_mirror_mode
,
667 const std::string
&mode
) {
668 librados::Rados rados
;
669 librados::IoCtx io_ctx
;
670 rbd_mirror_mode_t current_mirror_mode
;
672 int r
= utils::init(pool_name
, &rados
, &io_ctx
);
678 r
= rbd
.mirror_mode_get(io_ctx
, ¤t_mirror_mode
);
680 std::cerr
<< "rbd: failed to retrieve mirror mode: "
681 << cpp_strerror(r
) << std::endl
;
685 if (current_mirror_mode
== next_mirror_mode
) {
686 if (mode
== "disabled") {
687 std::cout
<< "mirroring is already " << mode
<< std::endl
;
689 std::cout
<< "mirroring is already configured for "
690 << mode
<< " mode" << std::endl
;
693 } else if (next_mirror_mode
== RBD_MIRROR_MODE_IMAGE
&&
694 current_mirror_mode
== RBD_MIRROR_MODE_POOL
) {
695 std::cout
<< "note: changing mirroring mode from pool to image"
697 } else if (next_mirror_mode
== RBD_MIRROR_MODE_POOL
&&
698 current_mirror_mode
== RBD_MIRROR_MODE_IMAGE
) {
699 std::cout
<< "note: changing mirroring mode from image to pool"
703 r
= rbd
.mirror_mode_set(io_ctx
, next_mirror_mode
);
710 int execute_disable(const po::variables_map
&vm
) {
711 size_t arg_index
= 0;
712 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
714 return execute_enable_disable(pool_name
, RBD_MIRROR_MODE_DISABLED
,
718 int execute_enable(const po::variables_map
&vm
) {
719 size_t arg_index
= 0;
720 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
722 rbd_mirror_mode_t mirror_mode
;
723 std::string mode
= utils::get_positional_argument(vm
, arg_index
++);
724 if (mode
== "image") {
725 mirror_mode
= RBD_MIRROR_MODE_IMAGE
;
726 } else if (mode
== "pool") {
727 mirror_mode
= RBD_MIRROR_MODE_POOL
;
729 std::cerr
<< "rbd: must specify 'image' or 'pool' mode." << std::endl
;
733 return execute_enable_disable(pool_name
, mirror_mode
, mode
);
736 void get_info_arguments(po::options_description
*positional
,
737 po::options_description
*options
) {
738 at::add_pool_options(positional
, options
);
739 at::add_format_options(options
);
742 int execute_info(const po::variables_map
&vm
) {
743 size_t arg_index
= 0;
744 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
746 at::Format::Formatter formatter
;
747 int r
= utils::get_formatter(vm
, &formatter
);
752 std::string config_path
;
753 if (vm
.count(at::CONFIG_PATH
)) {
754 config_path
= vm
[at::CONFIG_PATH
].as
<std::string
>();
757 librados::Rados rados
;
758 librados::IoCtx io_ctx
;
759 r
= utils::init(pool_name
, &rados
, &io_ctx
);
765 rbd_mirror_mode_t mirror_mode
;
766 r
= rbd
.mirror_mode_get(io_ctx
, &mirror_mode
);
771 std::vector
<librbd::mirror_peer_t
> mirror_peers
;
772 r
= rbd
.mirror_peer_list(io_ctx
, &mirror_peers
);
777 std::string mirror_mode_desc
;
778 switch (mirror_mode
) {
779 case RBD_MIRROR_MODE_DISABLED
:
780 mirror_mode_desc
= "disabled";
782 case RBD_MIRROR_MODE_IMAGE
:
783 mirror_mode_desc
= "image";
785 case RBD_MIRROR_MODE_POOL
:
786 mirror_mode_desc
= "pool";
789 mirror_mode_desc
= "unknown";
793 if (formatter
!= nullptr) {
794 formatter
->open_object_section("mirror");
795 formatter
->dump_string("mode", mirror_mode_desc
);
797 std::cout
<< "Mode: " << mirror_mode_desc
<< std::endl
;
800 if (mirror_mode
!= RBD_MIRROR_MODE_DISABLED
) {
801 format_mirror_peers(config_path
, formatter
, mirror_peers
);
803 if (formatter
!= nullptr) {
804 formatter
->close_section();
805 formatter
->flush(std::cout
);
810 void get_status_arguments(po::options_description
*positional
,
811 po::options_description
*options
) {
812 at::add_pool_options(positional
, options
);
813 at::add_format_options(options
);
814 at::add_verbose_option(options
);
817 int execute_status(const po::variables_map
&vm
) {
818 size_t arg_index
= 0;
819 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
821 at::Format::Formatter formatter
;
822 int r
= utils::get_formatter(vm
, &formatter
);
827 bool verbose
= vm
[at::VERBOSE
].as
<bool>();
829 std::string config_path
;
830 if (vm
.count(at::CONFIG_PATH
)) {
831 config_path
= vm
[at::CONFIG_PATH
].as
<std::string
>();
834 librados::Rados rados
;
835 librados::IoCtx io_ctx
;
836 r
= utils::init(pool_name
, &rados
, &io_ctx
);
843 std::map
<librbd::mirror_image_status_state_t
, int> states
;
844 r
= rbd
.mirror_image_status_summary(io_ctx
, &states
);
846 std::cerr
<< "rbd: failed to get status summary for mirrored images: "
847 << cpp_strerror(r
) << std::endl
;
851 if (formatter
!= nullptr) {
852 formatter
->open_object_section("status");
855 enum Health
{Ok
= 0, Warning
= 1, Error
= 2} health
= Ok
;
856 const char *names
[] = {"OK", "WARNING", "ERROR"};
859 for (auto &it
: states
) {
860 auto &state
= it
.first
;
861 if (health
< Warning
&&
862 (state
!= MIRROR_IMAGE_STATUS_STATE_REPLAYING
&&
863 state
!= MIRROR_IMAGE_STATUS_STATE_STOPPED
)) {
866 if (health
< Error
&&
867 state
== MIRROR_IMAGE_STATUS_STATE_ERROR
) {
873 if (formatter
!= nullptr) {
874 formatter
->open_object_section("summary");
875 formatter
->dump_string("health", names
[health
]);
876 formatter
->open_object_section("states");
877 for (auto &it
: states
) {
878 std::string state_name
= utils::mirror_image_status_state(it
.first
);
879 formatter
->dump_int(state_name
.c_str(), it
.second
);
881 formatter
->close_section(); // states
882 formatter
->close_section(); // summary
884 std::cout
<< "health: " << names
[health
] << std::endl
;
885 std::cout
<< "images: " << total
<< " total" << std::endl
;
886 for (auto &it
: states
) {
887 std::cout
<< " " << it
.second
<< " "
888 << utils::mirror_image_status_state(it
.first
) << std::endl
;
895 if (formatter
!= nullptr) {
896 formatter
->open_array_section("images");
899 ImageRequestGenerator
<StatusImageRequest
> generator(io_ctx
, formatter
);
900 ret
= generator
.execute();
902 if (formatter
!= nullptr) {
903 formatter
->close_section(); // images
907 if (formatter
!= nullptr) {
908 formatter
->close_section(); // status
909 formatter
->flush(std::cout
);
915 void get_promote_arguments(po::options_description
*positional
,
916 po::options_description
*options
) {
917 options
->add_options()
918 ("force", po::bool_switch(),
919 "promote even if not cleanly demoted by remote cluster");
920 at::add_pool_options(positional
, options
);
923 int execute_promote(const po::variables_map
&vm
) {
924 size_t arg_index
= 0;
925 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
927 librados::Rados rados
;
928 librados::IoCtx io_ctx
;
929 int r
= utils::init(pool_name
, &rados
, &io_ctx
);
934 std::atomic
<unsigned> counter
= { 0 };
935 ImageRequestGenerator
<PromoteImageRequest
> generator(io_ctx
, &counter
,
936 vm
["force"].as
<bool>());
937 r
= generator
.execute();
939 std::cout
<< "Promoted " << counter
.load() << " mirrored images" << std::endl
;
943 void get_demote_arguments(po::options_description
*positional
,
944 po::options_description
*options
) {
945 at::add_pool_options(positional
, options
);
948 int execute_demote(const po::variables_map
&vm
) {
949 size_t arg_index
= 0;
950 std::string pool_name
= utils::get_pool_name(vm
, &arg_index
);
952 librados::Rados rados
;
953 librados::IoCtx io_ctx
;
954 int r
= utils::init(pool_name
, &rados
, &io_ctx
);
959 std::atomic
<unsigned> counter
{ 0 };
960 ImageRequestGenerator
<DemoteImageRequest
> generator(io_ctx
, &counter
);
961 r
= generator
.execute();
963 std::cout
<< "Demoted " << counter
.load() << " mirrored images" << std::endl
;
967 Shell::Action
action_add(
968 {"mirror", "pool", "peer", "add"}, {},
969 "Add a mirroring peer to a pool.", "",
970 &get_peer_add_arguments
, &execute_peer_add
);
971 Shell::Action
action_remove(
972 {"mirror", "pool", "peer", "remove"}, {},
973 "Remove a mirroring peer from a pool.", "",
974 &get_peer_remove_arguments
, &execute_peer_remove
);
975 Shell::Action
action_set(
976 {"mirror", "pool", "peer", "set"}, {},
977 "Update mirroring peer settings.", "",
978 &get_peer_set_arguments
, &execute_peer_set
);
980 Shell::Action
action_disable(
981 {"mirror", "pool", "disable"}, {},
982 "Disable RBD mirroring by default within a pool.", "",
983 &get_disable_arguments
, &execute_disable
);
984 Shell::Action
action_enable(
985 {"mirror", "pool", "enable"}, {},
986 "Enable RBD mirroring by default within a pool.", "",
987 &get_enable_arguments
, &execute_enable
);
988 Shell::Action
action_info(
989 {"mirror", "pool", "info"}, {},
990 "Show information about the pool mirroring configuration.", {},
991 &get_info_arguments
, &execute_info
);
992 Shell::Action
action_status(
993 {"mirror", "pool", "status"}, {},
994 "Show status for all mirrored images in the pool.", {},
995 &get_status_arguments
, &execute_status
);
996 Shell::Action
action_promote(
997 {"mirror", "pool", "promote"}, {},
998 "Promote all non-primary images in the pool.", {},
999 &get_promote_arguments
, &execute_promote
);
1000 Shell::Action
action_demote(
1001 {"mirror", "pool", "demote"}, {},
1002 "Demote all primary images in the pool.", {},
1003 &get_demote_arguments
, &execute_demote
);
1005 } // namespace mirror_pool
1006 } // namespace action