1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/api/Mirror.h"
5 #include "include/rados/librados.hpp"
6 #include "include/stringify.h"
7 #include "common/ceph_json.h"
8 #include "common/dout.h"
9 #include "common/errno.h"
10 #include "cls/rbd/cls_rbd_client.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/Journal.h"
14 #include "librbd/MirroringWatcher.h"
15 #include "librbd/Operations.h"
16 #include "librbd/Utils.h"
17 #include "librbd/api/Image.h"
18 #include "librbd/api/Namespace.h"
19 #include "librbd/mirror/DemoteRequest.h"
20 #include "librbd/mirror/DisableRequest.h"
21 #include "librbd/mirror/EnableRequest.h"
22 #include "librbd/mirror/GetInfoRequest.h"
23 #include "librbd/mirror/GetStatusRequest.h"
24 #include "librbd/mirror/GetUuidRequest.h"
25 #include "librbd/mirror/PromoteRequest.h"
26 #include "librbd/mirror/Types.h"
27 #include "librbd/MirroringWatcher.h"
28 #include "librbd/mirror/snapshot/CreatePrimaryRequest.h"
29 #include "librbd/mirror/snapshot/ImageMeta.h"
30 #include "librbd/mirror/snapshot/UnlinkPeerRequest.h"
31 #include "librbd/mirror/snapshot/Utils.h"
32 #include <boost/algorithm/string/trim.hpp>
33 #include <boost/algorithm/string/replace.hpp>
34 #include <boost/scope_exit.hpp>
35 #include "json_spirit/json_spirit.h"
40 #define dout_subsys ceph_subsys_rbd
42 #define dout_prefix *_dout << "librbd::api::Mirror: " << __func__ << ": "
49 int get_config_key(librados::Rados
& rados
, const std::string
& key
,
53 "\"prefix\": \"config-key get\", "
54 "\"key\": \"" + key
+ "\""
60 int r
= rados
.mon_command(cmd
, in_bl
, &out_bl
, nullptr);
63 } else if (r
< 0 && r
!= -ENOENT
) {
67 *value
= out_bl
.to_str();
71 int set_config_key(librados::Rados
& rados
, const std::string
& key
,
72 const std::string
& value
) {
76 "\"prefix\": \"config-key rm\", "
77 "\"key\": \"" + key
+ "\""
81 "\"prefix\": \"config-key set\", "
82 "\"key\": \"" + key
+ "\", "
83 "\"val\": \"" + value
+ "\""
89 int r
= rados
.mon_command(cmd
, in_bl
, &out_bl
, nullptr);
99 std::string
get_peer_config_key_name(int64_t pool_id
,
100 const std::string
& peer_uuid
) {
101 return RBD_MIRROR_PEER_CONFIG_KEY_PREFIX
+ stringify(pool_id
) + "/" +
105 int remove_peer_config_key(librados::IoCtx
& io_ctx
,
106 const std::string
& peer_uuid
) {
107 int64_t pool_id
= io_ctx
.get_id();
108 auto key
= get_peer_config_key_name(pool_id
, peer_uuid
);
110 librados::Rados
rados(io_ctx
);
111 int r
= set_config_key(rados
, key
, "");
112 if (r
< 0 && r
!= -ENOENT
&& r
!= -EPERM
) {
118 int create_bootstrap_user(CephContext
* cct
, librados::Rados
& rados
,
119 std::string
* peer_client_id
, std::string
* cephx_key
) {
120 ldout(cct
, 20) << dendl
;
122 // retrieve peer CephX user from config-key
123 int r
= get_config_key(rados
, RBD_MIRROR_PEER_CLIENT_ID_CONFIG_KEY
,
126 ldout(cct
, 5) << "insufficient permissions to get peer-client-id "
127 << "config-key" << dendl
;
129 } else if (r
< 0 && r
!= -ENOENT
) {
130 lderr(cct
) << "failed to retrieve peer client id key: "
131 << cpp_strerror(r
) << dendl
;
133 } else if (r
== -ENOENT
|| peer_client_id
->empty()) {
134 ldout(cct
, 20) << "creating new peer-client-id config-key" << dendl
;
136 *peer_client_id
= "rbd-mirror-peer";
137 r
= set_config_key(rados
, RBD_MIRROR_PEER_CLIENT_ID_CONFIG_KEY
,
140 ldout(cct
, 5) << "insufficient permissions to update peer-client-id "
141 << "config-key" << dendl
;
144 lderr(cct
) << "failed to update peer client id key: "
145 << cpp_strerror(r
) << dendl
;
149 ldout(cct
, 20) << "peer_client_id=" << *peer_client_id
<< dendl
;
151 // create peer client user
154 R
"( "prefix
": "auth get
-or-create
",)" \
155 R
"( "entity
": "client
.)" + *peer_client_id + R"(",)" \
157 R
"( "mon
", "profile rbd
-mirror
-peer
",)" \
158 R
"( "osd
", "profile rbd
"],)" \
159 R
"( "format
": "json
")" \
165 r
= rados
.mon_command(cmd
, in_bl
, &out_bl
, nullptr);
167 ldout(cct
, 5) << "caps mismatch for existing user" << dendl
;
169 } else if (r
== -EACCES
) {
170 ldout(cct
, 5) << "insufficient permissions to create user" << dendl
;
173 lderr(cct
) << "failed to create or update RBD mirroring bootstrap user: "
174 << cpp_strerror(r
) << dendl
;
178 // extract key from response
179 bool json_valid
= false;
180 json_spirit::mValue json_root
;
181 if(json_spirit::read(out_bl
.to_str(), json_root
)) {
183 auto& json_obj
= json_root
.get_array()[0].get_obj();
184 *cephx_key
= json_obj
["key"].get_str();
186 } catch (std::runtime_error
&) {
191 lderr(cct
) << "invalid auth keyring JSON received" << dendl
;
198 int create_bootstrap_peer(CephContext
* cct
, librados::IoCtx
& io_ctx
,
199 mirror_peer_direction_t direction
,
200 const std::string
& site_name
, const std::string
& fsid
,
201 const std::string
& client_id
, const std::string
& key
,
202 const std::string
& mon_host
,
203 const std::string
& cluster1
,
204 const std::string
& cluster2
) {
205 ldout(cct
, 20) << dendl
;
207 std::string peer_uuid
;
208 std::vector
<mirror_peer_site_t
> peers
;
209 int r
= Mirror
<>::peer_site_list(io_ctx
, &peers
);
210 if (r
< 0 && r
!= -ENOENT
) {
211 lderr(cct
) << "failed to list mirror peers: " << cpp_strerror(r
) << dendl
;
216 r
= Mirror
<>::peer_site_add(io_ctx
, &peer_uuid
, direction
, site_name
,
217 "client." + client_id
);
219 lderr(cct
) << "failed to add " << cluster1
<< " peer to "
220 << cluster2
<< " " << "cluster: " << cpp_strerror(r
) << dendl
;
223 } else if (peers
[0].site_name
!= site_name
&&
224 peers
[0].site_name
!= fsid
) {
225 // only support a single peer
226 lderr(cct
) << "multiple peers are not currently supported" << dendl
;
229 peer_uuid
= peers
[0].uuid
;
231 if (peers
[0].site_name
!= site_name
) {
232 r
= Mirror
<>::peer_site_set_name(io_ctx
, peer_uuid
, site_name
);
234 // non-fatal attempt to update site name
235 lderr(cct
) << "failed to update peer site name" << dendl
;
240 Mirror
<>::Attributes attributes
{
241 {"mon_host", mon_host
},
243 r
= Mirror
<>::peer_site_set_attributes(io_ctx
, peer_uuid
, attributes
);
245 lderr(cct
) << "failed to update " << cluster1
<< " cluster connection "
246 << "attributes in " << cluster2
<< " cluster: "
247 << cpp_strerror(r
) << dendl
;
254 int list_mirror_images(librados::IoCtx
& io_ctx
,
255 std::set
<std::string
>& mirror_image_ids
) {
256 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
258 std::string last_read
= "";
262 std::map
<std::string
, std::string
> mirror_images
;
263 r
= cls_client::mirror_image_list(&io_ctx
, last_read
, max_read
,
265 if (r
< 0 && r
!= -ENOENT
) {
266 lderr(cct
) << "error listing mirrored image directory: "
267 << cpp_strerror(r
) << dendl
;
270 for (auto it
= mirror_images
.begin(); it
!= mirror_images
.end(); ++it
) {
271 mirror_image_ids
.insert(it
->first
);
273 if (!mirror_images
.empty()) {
274 last_read
= mirror_images
.rbegin()->first
;
276 r
= mirror_images
.size();
277 } while (r
== max_read
);
282 struct C_ImageGetInfo
: public Context
{
283 mirror_image_info_t
*mirror_image_info
;
284 mirror_image_mode_t
*mirror_image_mode
;
287 cls::rbd::MirrorImage mirror_image
;
288 mirror::PromotionState promotion_state
= mirror::PROMOTION_STATE_PRIMARY
;
289 std::string primary_mirror_uuid
;
291 C_ImageGetInfo(mirror_image_info_t
*mirror_image_info
,
292 mirror_image_mode_t
*mirror_image_mode
, Context
*on_finish
)
293 : mirror_image_info(mirror_image_info
),
294 mirror_image_mode(mirror_image_mode
), on_finish(on_finish
) {
297 void finish(int r
) override
{
298 if (r
< 0 && r
!= -ENOENT
) {
299 on_finish
->complete(r
);
303 if (mirror_image_info
!= nullptr) {
304 mirror_image_info
->global_id
= mirror_image
.global_image_id
;
305 mirror_image_info
->state
= static_cast<rbd_mirror_image_state_t
>(
307 mirror_image_info
->primary
= (
308 promotion_state
== mirror::PROMOTION_STATE_PRIMARY
);
311 if (mirror_image_mode
!= nullptr) {
313 static_cast<rbd_mirror_image_mode_t
>(mirror_image
.mode
);
316 on_finish
->complete(0);
320 struct C_ImageGetGlobalStatus
: public C_ImageGetInfo
{
321 std::string image_name
;
322 mirror_image_global_status_t
*mirror_image_global_status
;
324 cls::rbd::MirrorImageStatus mirror_image_status_internal
;
326 C_ImageGetGlobalStatus(
327 const std::string
&image_name
,
328 mirror_image_global_status_t
*mirror_image_global_status
,
330 : C_ImageGetInfo(&mirror_image_global_status
->info
, nullptr, on_finish
),
331 image_name(image_name
),
332 mirror_image_global_status(mirror_image_global_status
) {
335 void finish(int r
) override
{
336 if (r
< 0 && r
!= -ENOENT
) {
337 on_finish
->complete(r
);
341 mirror_image_global_status
->name
= image_name
;
342 mirror_image_global_status
->site_statuses
.clear();
343 mirror_image_global_status
->site_statuses
.reserve(
344 mirror_image_status_internal
.mirror_image_site_statuses
.size());
345 for (auto& site_status
:
346 mirror_image_status_internal
.mirror_image_site_statuses
) {
347 mirror_image_global_status
->site_statuses
.push_back({
348 site_status
.mirror_uuid
,
349 static_cast<mirror_image_status_state_t
>(site_status
.state
),
350 site_status
.description
, site_status
.last_update
.sec(),
353 C_ImageGetInfo::finish(0);
357 template <typename I
>
358 struct C_ImageSnapshotCreate
: public Context
{
363 cls::rbd::MirrorImage mirror_image
;
364 mirror::PromotionState promotion_state
;
365 std::string primary_mirror_uuid
;
367 C_ImageSnapshotCreate(I
*ictx
, uint64_t *snap_id
, Context
*on_finish
)
368 : ictx(ictx
), snap_id(snap_id
), on_finish(on_finish
) {
371 void finish(int r
) override
{
372 if (r
< 0 && r
!= -ENOENT
) {
373 on_finish
->complete(r
);
377 if (mirror_image
.mode
!= cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
||
378 mirror_image
.state
!= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
379 lderr(ictx
->cct
) << "snapshot based mirroring is not enabled" << dendl
;
380 on_finish
->complete(-EINVAL
);
384 auto req
= mirror::snapshot::CreatePrimaryRequest
<I
>::create(
385 ictx
, mirror_image
.global_image_id
, CEPH_NOSNAP
, 0U, snap_id
, on_finish
);
390 } // anonymous namespace
392 template <typename I
>
393 int Mirror
<I
>::image_enable(I
*ictx
, mirror_image_mode_t mode
,
394 bool relax_same_pool_parent_check
) {
395 CephContext
*cct
= ictx
->cct
;
396 ldout(cct
, 20) << "ictx=" << ictx
<< " mode=" << mode
397 << " relax_same_pool_parent_check="
398 << relax_same_pool_parent_check
<< dendl
;
400 int r
= ictx
->state
->refresh_if_required();
405 cls::rbd::MirrorMode mirror_mode
;
406 r
= cls_client::mirror_mode_get(&ictx
->md_ctx
, &mirror_mode
);
408 lderr(cct
) << "cannot enable mirroring: failed to retrieve mirror mode: "
409 << cpp_strerror(r
) << dendl
;
413 if (mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
414 lderr(cct
) << "cannot enable mirroring in the current pool mirroring mode"
419 // is mirroring not enabled for the parent?
421 std::shared_lock image_locker
{ictx
->image_lock
};
422 ImageCtx
*parent
= ictx
->parent
;
424 if (parent
->md_ctx
.get_id() != ictx
->md_ctx
.get_id() ||
425 !relax_same_pool_parent_check
) {
426 cls::rbd::MirrorImage mirror_image_internal
;
427 r
= cls_client::mirror_image_get(&(parent
->md_ctx
), parent
->id
,
428 &mirror_image_internal
);
430 lderr(cct
) << "mirroring is not enabled for the parent" << dendl
;
437 if (mode
== RBD_MIRROR_IMAGE_MODE_JOURNAL
&&
438 !ictx
->test_features(RBD_FEATURE_JOURNALING
)) {
439 uint64_t features
= RBD_FEATURE_JOURNALING
;
440 if (!ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
441 features
|= RBD_FEATURE_EXCLUSIVE_LOCK
;
443 r
= ictx
->operations
->update_features(features
, true);
445 lderr(cct
) << "cannot enable journaling: " << cpp_strerror(r
) << dendl
;
451 auto req
= mirror::EnableRequest
<ImageCtx
>::create(
452 ictx
, static_cast<cls::rbd::MirrorImageMode
>(mode
), "", false, &ctx
);
457 lderr(cct
) << "cannot enable mirroring: " << cpp_strerror(r
) << dendl
;
464 template <typename I
>
465 int Mirror
<I
>::image_disable(I
*ictx
, bool force
) {
466 CephContext
*cct
= ictx
->cct
;
467 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
469 int r
= ictx
->state
->refresh_if_required();
474 cls::rbd::MirrorMode mirror_mode
;
475 r
= cls_client::mirror_mode_get(&ictx
->md_ctx
, &mirror_mode
);
477 lderr(cct
) << "cannot disable mirroring: failed to retrieve pool "
478 "mirroring mode: " << cpp_strerror(r
) << dendl
;
482 if (mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
483 lderr(cct
) << "cannot disable mirroring in the current pool mirroring "
488 // is mirroring enabled for the image?
489 cls::rbd::MirrorImage mirror_image_internal
;
490 r
= cls_client::mirror_image_get(&ictx
->md_ctx
, ictx
->id
,
491 &mirror_image_internal
);
493 // mirroring is not enabled for this image
494 ldout(cct
, 20) << "ignoring disable command: mirroring is not enabled for "
495 << "this image" << dendl
;
497 } else if (r
== -EOPNOTSUPP
) {
498 ldout(cct
, 5) << "mirroring not supported by OSD" << dendl
;
501 lderr(cct
) << "failed to retrieve mirror image metadata: "
502 << cpp_strerror(r
) << dendl
;
506 mirror_image_internal
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
507 r
= cls_client::mirror_image_set(&ictx
->md_ctx
, ictx
->id
,
508 mirror_image_internal
);
510 lderr(cct
) << "cannot disable mirroring: " << cpp_strerror(r
) << dendl
;
514 bool rollback
= false;
515 BOOST_SCOPE_EXIT_ALL(ictx
, &mirror_image_internal
, &rollback
) {
517 // restore the mask bit for treating the non-primary feature as read-only
518 ictx
->image_lock
.lock();
519 ictx
->read_only_mask
|= IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
520 ictx
->image_lock
.unlock();
522 ictx
->state
->handle_update_notification();
524 // attempt to restore the image state
525 CephContext
*cct
= ictx
->cct
;
526 mirror_image_internal
.state
= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
;
527 int r
= cls_client::mirror_image_set(&ictx
->md_ctx
, ictx
->id
,
528 mirror_image_internal
);
530 lderr(cct
) << "failed to re-enable image mirroring: "
531 << cpp_strerror(r
) << dendl
;
536 std::unique_lock image_locker
{ictx
->image_lock
};
537 map
<librados::snap_t
, SnapInfo
> snap_info
= ictx
->snap_info
;
538 for (auto &info
: snap_info
) {
539 cls::rbd::ParentImageSpec parent_spec
{ictx
->md_ctx
.get_id(),
540 ictx
->md_ctx
.get_namespace(),
541 ictx
->id
, info
.first
};
542 std::vector
<librbd::linked_image_spec_t
> child_images
;
543 r
= Image
<I
>::list_children(ictx
, parent_spec
, &child_images
);
549 if (child_images
.empty()) {
553 librados::IoCtx child_io_ctx
;
554 int64_t child_pool_id
= -1;
555 for (auto &child_image
: child_images
){
556 std::string pool
= child_image
.pool_name
;
557 if (child_pool_id
== -1 ||
558 child_pool_id
!= child_image
.pool_id
||
559 child_io_ctx
.get_namespace() != child_image
.pool_namespace
) {
560 r
= util::create_ioctx(ictx
->md_ctx
, "child image",
562 child_image
.pool_namespace
,
569 child_pool_id
= child_image
.pool_id
;
572 cls::rbd::MirrorImage child_mirror_image_internal
;
573 r
= cls_client::mirror_image_get(&child_io_ctx
, child_image
.image_id
,
574 &child_mirror_image_internal
);
577 lderr(cct
) << "mirroring is enabled on one or more children "
583 image_locker
.unlock();
585 if (mirror_image_internal
.mode
== cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
) {
586 // don't let the non-primary feature bit prevent image updates
587 ictx
->image_lock
.lock();
588 ictx
->read_only_mask
&= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
589 ictx
->image_lock
.unlock();
591 r
= ictx
->state
->refresh();
597 // remove any snapshot-based mirroring image-meta from image
598 std::string mirror_uuid
;
599 r
= uuid_get(ictx
->md_ctx
, &mirror_uuid
);
605 r
= ictx
->operations
->metadata_remove(
606 mirror::snapshot::util::get_image_meta_key(mirror_uuid
));
607 if (r
< 0 && r
!= -ENOENT
) {
608 lderr(cct
) << "cannot remove snapshot image-meta key: " << cpp_strerror(r
)
616 auto req
= mirror::DisableRequest
<ImageCtx
>::create(ictx
, force
, true,
622 lderr(cct
) << "cannot disable mirroring: " << cpp_strerror(r
) << dendl
;
627 if (mirror_image_internal
.mode
== cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
628 r
= ictx
->operations
->update_features(RBD_FEATURE_JOURNALING
, false);
630 lderr(cct
) << "cannot disable journaling: " << cpp_strerror(r
) << dendl
;
638 template <typename I
>
639 int Mirror
<I
>::image_promote(I
*ictx
, bool force
) {
640 CephContext
*cct
= ictx
->cct
;
643 Mirror
<I
>::image_promote(ictx
, force
, &ctx
);
646 lderr(cct
) << "failed to promote image" << dendl
;
653 template <typename I
>
654 void Mirror
<I
>::image_promote(I
*ictx
, bool force
, Context
*on_finish
) {
655 CephContext
*cct
= ictx
->cct
;
656 ldout(cct
, 20) << "ictx=" << ictx
<< ", "
657 << "force=" << force
<< dendl
;
659 // don't let the non-primary feature bit prevent image updates
660 ictx
->image_lock
.lock();
661 ictx
->read_only_mask
&= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
662 ictx
->image_lock
.unlock();
664 auto on_promote
= new LambdaContext([ictx
, on_finish
](int r
) {
665 ictx
->image_lock
.lock();
666 ictx
->read_only_mask
|= IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
667 ictx
->image_lock
.unlock();
669 ictx
->state
->handle_update_notification();
670 on_finish
->complete(r
);
673 auto on_refresh
= new LambdaContext([ictx
, force
, on_promote
](int r
) {
675 lderr(ictx
->cct
) << "refresh failed: " << cpp_strerror(r
) << dendl
;
676 on_promote
->complete(r
);
680 auto req
= mirror::PromoteRequest
<>::create(*ictx
, force
, on_promote
);
683 ictx
->state
->refresh(on_refresh
);
686 template <typename I
>
687 int Mirror
<I
>::image_demote(I
*ictx
) {
688 CephContext
*cct
= ictx
->cct
;
691 Mirror
<I
>::image_demote(ictx
, &ctx
);
694 lderr(cct
) << "failed to demote image" << dendl
;
701 template <typename I
>
702 void Mirror
<I
>::image_demote(I
*ictx
, Context
*on_finish
) {
703 CephContext
*cct
= ictx
->cct
;
704 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
706 auto on_cleanup
= new LambdaContext([ictx
, on_finish
](int r
) {
707 ictx
->image_lock
.lock();
708 ictx
->read_only_mask
|= IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
709 ictx
->image_lock
.unlock();
711 ictx
->state
->handle_update_notification();
713 on_finish
->complete(r
);
715 auto on_refresh
= new LambdaContext([ictx
, on_cleanup
](int r
) {
717 lderr(ictx
->cct
) << "refresh failed: " << cpp_strerror(r
) << dendl
;
718 on_cleanup
->complete(r
);
722 auto req
= mirror::DemoteRequest
<>::create(*ictx
, on_cleanup
);
726 // ensure we can create a snapshot after setting the non-primary
728 ictx
->image_lock
.lock();
729 ictx
->read_only_mask
&= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
730 ictx
->image_lock
.unlock();
732 ictx
->state
->refresh(on_refresh
);
735 template <typename I
>
736 int Mirror
<I
>::image_resync(I
*ictx
) {
737 CephContext
*cct
= ictx
->cct
;
738 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
740 int r
= ictx
->state
->refresh_if_required();
745 cls::rbd::MirrorImage mirror_image
;
746 mirror::PromotionState promotion_state
;
747 std::string primary_mirror_uuid
;
748 C_SaferCond get_info_ctx
;
749 auto req
= mirror::GetInfoRequest
<I
>::create(*ictx
, &mirror_image
,
751 &primary_mirror_uuid
,
755 r
= get_info_ctx
.wait();
760 if (promotion_state
== mirror::PROMOTION_STATE_PRIMARY
) {
761 lderr(cct
) << "image is primary, cannot resync to itself" << dendl
;
765 if (mirror_image
.mode
== cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
) {
766 // flag the journal indicating that we want to rebuild the local image
767 r
= Journal
<I
>::request_resync(ictx
);
769 lderr(cct
) << "failed to request resync: " << cpp_strerror(r
) << dendl
;
772 } else if (mirror_image
.mode
== cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
) {
773 std::string mirror_uuid
;
774 r
= uuid_get(ictx
->md_ctx
, &mirror_uuid
);
779 mirror::snapshot::ImageMeta
image_meta(ictx
, mirror_uuid
);
781 C_SaferCond load_meta_ctx
;
782 image_meta
.load(&load_meta_ctx
);
783 r
= load_meta_ctx
.wait();
784 if (r
< 0 && r
!= -ENOENT
) {
785 lderr(cct
) << "failed to load mirror image-meta: " << cpp_strerror(r
)
790 image_meta
.resync_requested
= true;
792 C_SaferCond save_meta_ctx
;
793 image_meta
.save(&save_meta_ctx
);
794 r
= save_meta_ctx
.wait();
796 lderr(cct
) << "failed to request resync: " << cpp_strerror(r
) << dendl
;
800 lderr(cct
) << "unknown mirror mode" << dendl
;
807 template <typename I
>
808 void Mirror
<I
>::image_get_info(I
*ictx
, mirror_image_info_t
*mirror_image_info
,
809 Context
*on_finish
) {
810 CephContext
*cct
= ictx
->cct
;
811 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
813 auto on_refresh
= new LambdaContext(
814 [ictx
, mirror_image_info
, on_finish
](int r
) {
816 lderr(ictx
->cct
) << "refresh failed: " << cpp_strerror(r
) << dendl
;
817 on_finish
->complete(r
);
821 auto ctx
= new C_ImageGetInfo(mirror_image_info
, nullptr, on_finish
);
822 auto req
= mirror::GetInfoRequest
<I
>::create(*ictx
, &ctx
->mirror_image
,
823 &ctx
->promotion_state
,
824 &ctx
->primary_mirror_uuid
,
829 if (ictx
->state
->is_refresh_required()) {
830 ictx
->state
->refresh(on_refresh
);
832 on_refresh
->complete(0);
836 template <typename I
>
837 int Mirror
<I
>::image_get_info(I
*ictx
, mirror_image_info_t
*mirror_image_info
) {
839 image_get_info(ictx
, mirror_image_info
, &ctx
);
848 template <typename I
>
849 void Mirror
<I
>::image_get_info(librados::IoCtx
& io_ctx
,
850 ContextWQ
*op_work_queue
,
851 const std::string
&image_id
,
852 mirror_image_info_t
*mirror_image_info
,
853 Context
*on_finish
) {
854 auto cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
855 ldout(cct
, 20) << "pool_id=" << io_ctx
.get_id() << ", image_id=" << image_id
858 auto ctx
= new C_ImageGetInfo(mirror_image_info
, nullptr, on_finish
);
859 auto req
= mirror::GetInfoRequest
<I
>::create(io_ctx
, op_work_queue
, image_id
,
861 &ctx
->promotion_state
,
862 &ctx
->primary_mirror_uuid
, ctx
);
866 template <typename I
>
867 int Mirror
<I
>::image_get_info(librados::IoCtx
& io_ctx
,
868 ContextWQ
*op_work_queue
,
869 const std::string
&image_id
,
870 mirror_image_info_t
*mirror_image_info
) {
872 image_get_info(io_ctx
, op_work_queue
, image_id
, mirror_image_info
, &ctx
);
881 template <typename I
>
882 void Mirror
<I
>::image_get_mode(I
*ictx
, mirror_image_mode_t
*mode
,
883 Context
*on_finish
) {
884 CephContext
*cct
= ictx
->cct
;
885 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
887 auto ctx
= new C_ImageGetInfo(nullptr, mode
, on_finish
);
888 auto req
= mirror::GetInfoRequest
<I
>::create(*ictx
, &ctx
->mirror_image
,
889 &ctx
->promotion_state
,
890 &ctx
->primary_mirror_uuid
, ctx
);
894 template <typename I
>
895 int Mirror
<I
>::image_get_mode(I
*ictx
, mirror_image_mode_t
*mode
) {
897 image_get_mode(ictx
, mode
, &ctx
);
906 template <typename I
>
907 void Mirror
<I
>::image_get_global_status(I
*ictx
,
908 mirror_image_global_status_t
*status
,
909 Context
*on_finish
) {
910 CephContext
*cct
= ictx
->cct
;
911 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
913 auto ctx
= new C_ImageGetGlobalStatus(ictx
->name
, status
, on_finish
);
914 auto req
= mirror::GetStatusRequest
<I
>::create(
915 *ictx
, &ctx
->mirror_image_status_internal
, &ctx
->mirror_image
,
916 &ctx
->promotion_state
, ctx
);
920 template <typename I
>
921 int Mirror
<I
>::image_get_global_status(I
*ictx
,
922 mirror_image_global_status_t
*status
) {
924 image_get_global_status(ictx
, status
, &ctx
);
933 template <typename I
>
934 int Mirror
<I
>::image_get_instance_id(I
*ictx
, std::string
*instance_id
) {
935 CephContext
*cct
= ictx
->cct
;
936 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
938 cls::rbd::MirrorImage mirror_image
;
939 int r
= cls_client::mirror_image_get(&ictx
->md_ctx
, ictx
->id
, &mirror_image
);
940 if (r
< 0 && r
!= -ENOENT
) {
941 lderr(cct
) << "failed to retrieve mirroring state: " << cpp_strerror(r
)
944 } else if (mirror_image
.state
!= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
945 lderr(cct
) << "mirroring is not currently enabled" << dendl
;
949 entity_inst_t instance
;
950 r
= cls_client::mirror_image_instance_get(&ictx
->md_ctx
,
951 mirror_image
.global_image_id
,
954 if (r
!= -ENOENT
&& r
!= -ESTALE
) {
955 lderr(cct
) << "failed to get mirror image instance: " << cpp_strerror(r
)
961 *instance_id
= stringify(instance
.name
.num());
965 template <typename I
>
966 int Mirror
<I
>::site_name_get(librados::Rados
& rados
, std::string
* name
) {
967 CephContext
*cct
= reinterpret_cast<CephContext
*>(rados
.cct());
968 ldout(cct
, 20) << dendl
;
970 int r
= get_config_key(rados
, RBD_MIRROR_SITE_NAME_CONFIG_KEY
, name
);
971 if (r
== -EOPNOTSUPP
) {
973 } else if (r
== -ENOENT
|| name
->empty()) {
974 // default to the cluster fsid
975 r
= rados
.cluster_fsid(name
);
977 lderr(cct
) << "failed to retrieve cluster fsid: " << cpp_strerror(r
)
982 lderr(cct
) << "failed to retrieve site name: " << cpp_strerror(r
)
990 template <typename I
>
991 int Mirror
<I
>::site_name_set(librados::Rados
& rados
, const std::string
& name
) {
992 CephContext
*cct
= reinterpret_cast<CephContext
*>(rados
.cct());
994 std::string site_name
{name
};
995 boost::algorithm::trim(site_name
);
996 ldout(cct
, 20) << "site_name=" << site_name
<< dendl
;
998 int r
= set_config_key(rados
, RBD_MIRROR_SITE_NAME_CONFIG_KEY
, name
);
999 if (r
== -EOPNOTSUPP
) {
1001 } else if (r
< 0 && r
!= -ENOENT
) {
1002 lderr(cct
) << "failed to update site name: " << cpp_strerror(r
)
1010 template <typename I
>
1011 int Mirror
<I
>::mode_get(librados::IoCtx
& io_ctx
,
1012 rbd_mirror_mode_t
*mirror_mode
) {
1013 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1014 ldout(cct
, 20) << dendl
;
1016 cls::rbd::MirrorMode mirror_mode_internal
;
1017 int r
= cls_client::mirror_mode_get(&io_ctx
, &mirror_mode_internal
);
1019 lderr(cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
1024 switch (mirror_mode_internal
) {
1025 case cls::rbd::MIRROR_MODE_DISABLED
:
1026 case cls::rbd::MIRROR_MODE_IMAGE
:
1027 case cls::rbd::MIRROR_MODE_POOL
:
1028 *mirror_mode
= static_cast<rbd_mirror_mode_t
>(mirror_mode_internal
);
1031 lderr(cct
) << "unknown mirror mode ("
1032 << static_cast<uint32_t>(mirror_mode_internal
) << ")"
1039 template <typename I
>
1040 int Mirror
<I
>::mode_set(librados::IoCtx
& io_ctx
,
1041 rbd_mirror_mode_t mirror_mode
) {
1042 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1043 ldout(cct
, 20) << dendl
;
1045 cls::rbd::MirrorMode next_mirror_mode
;
1046 switch (mirror_mode
) {
1047 case RBD_MIRROR_MODE_DISABLED
:
1048 case RBD_MIRROR_MODE_IMAGE
:
1049 case RBD_MIRROR_MODE_POOL
:
1050 next_mirror_mode
= static_cast<cls::rbd::MirrorMode
>(mirror_mode
);
1053 lderr(cct
) << "unknown mirror mode ("
1054 << static_cast<uint32_t>(mirror_mode
) << ")" << dendl
;
1059 if (next_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
1060 // fail early if pool still has peers registered and attempting to disable
1061 std::vector
<cls::rbd::MirrorPeer
> mirror_peers
;
1062 r
= cls_client::mirror_peer_list(&io_ctx
, &mirror_peers
);
1063 if (r
< 0 && r
!= -ENOENT
) {
1064 lderr(cct
) << "failed to list peers: " << cpp_strerror(r
) << dendl
;
1066 } else if (!mirror_peers
.empty()) {
1067 lderr(cct
) << "mirror peers still registered" << dendl
;
1072 cls::rbd::MirrorMode current_mirror_mode
;
1073 r
= cls_client::mirror_mode_get(&io_ctx
, ¤t_mirror_mode
);
1075 lderr(cct
) << "failed to retrieve mirror mode: " << cpp_strerror(r
)
1080 if (current_mirror_mode
== next_mirror_mode
) {
1082 } else if (current_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
1084 uuid_gen
.generate_random();
1085 r
= cls_client::mirror_uuid_set(&io_ctx
, uuid_gen
.to_string());
1087 lderr(cct
) << "failed to allocate mirroring uuid: " << cpp_strerror(r
)
1093 if (current_mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
1094 r
= cls_client::mirror_mode_set(&io_ctx
, cls::rbd::MIRROR_MODE_IMAGE
);
1096 lderr(cct
) << "failed to set mirror mode to image: "
1097 << cpp_strerror(r
) << dendl
;
1101 r
= MirroringWatcher
<>::notify_mode_updated(io_ctx
,
1102 cls::rbd::MIRROR_MODE_IMAGE
);
1104 lderr(cct
) << "failed to send update notification: " << cpp_strerror(r
)
1109 if (next_mirror_mode
== cls::rbd::MIRROR_MODE_IMAGE
) {
1113 if (next_mirror_mode
== cls::rbd::MIRROR_MODE_POOL
) {
1114 map
<string
, string
> images
;
1115 r
= Image
<I
>::list_images_v2(io_ctx
, &images
);
1117 lderr(cct
) << "failed listing images: " << cpp_strerror(r
) << dendl
;
1121 for (const auto& img_pair
: images
) {
1123 uint64_t incompatible_features
;
1124 r
= cls_client::get_features(&io_ctx
, util::header_name(img_pair
.second
),
1125 true, &features
, &incompatible_features
);
1127 lderr(cct
) << "error getting features for image " << img_pair
.first
1128 << ": " << cpp_strerror(r
) << dendl
;
1132 // Enable only journal based mirroring
1134 if ((features
& RBD_FEATURE_JOURNALING
) != 0) {
1135 I
*img_ctx
= I::create("", img_pair
.second
, nullptr, io_ctx
, false);
1136 r
= img_ctx
->state
->open(0);
1138 lderr(cct
) << "error opening image "<< img_pair
.first
<< ": "
1139 << cpp_strerror(r
) << dendl
;
1143 r
= image_enable(img_ctx
, RBD_MIRROR_IMAGE_MODE_JOURNAL
, true);
1144 int close_r
= img_ctx
->state
->close();
1146 lderr(cct
) << "error enabling mirroring for image "
1147 << img_pair
.first
<< ": " << cpp_strerror(r
) << dendl
;
1149 } else if (close_r
< 0) {
1150 lderr(cct
) << "failed to close image " << img_pair
.first
<< ": "
1151 << cpp_strerror(close_r
) << dendl
;
1156 } else if (next_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
1158 bool retry_busy
= false;
1159 bool pending_busy
= false;
1161 std::set
<std::string
> image_ids
;
1162 r
= list_mirror_images(io_ctx
, image_ids
);
1164 lderr(cct
) << "failed listing images: " << cpp_strerror(r
) << dendl
;
1168 for (const auto& img_id
: image_ids
) {
1169 if (current_mirror_mode
== cls::rbd::MIRROR_MODE_IMAGE
) {
1170 cls::rbd::MirrorImage mirror_image
;
1171 r
= cls_client::mirror_image_get(&io_ctx
, img_id
, &mirror_image
);
1172 if (r
< 0 && r
!= -ENOENT
) {
1173 lderr(cct
) << "failed to retrieve mirroring state for image id "
1174 << img_id
<< ": " << cpp_strerror(r
) << dendl
;
1177 if (mirror_image
.state
== cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
1178 lderr(cct
) << "failed to disable mirror mode: there are still "
1179 << "images with mirroring enabled" << dendl
;
1183 I
*img_ctx
= I::create("", img_id
, nullptr, io_ctx
, false);
1184 r
= img_ctx
->state
->open(0);
1186 lderr(cct
) << "error opening image id "<< img_id
<< ": "
1187 << cpp_strerror(r
) << dendl
;
1191 r
= image_disable(img_ctx
, false);
1192 int close_r
= img_ctx
->state
->close();
1194 pending_busy
= true;
1196 lderr(cct
) << "error disabling mirroring for image id " << img_id
1197 << cpp_strerror(r
) << dendl
;
1199 } else if (close_r
< 0) {
1200 lderr(cct
) << "failed to close image id " << img_id
<< ": "
1201 << cpp_strerror(close_r
) << dendl
;
1203 } else if (pending_busy
) {
1204 // at least one mirrored image was successfully disabled, so we can
1205 // retry any failures caused by busy parent/child relationships
1211 if (!retry_busy
&& pending_busy
) {
1212 lderr(cct
) << "error disabling mirroring for one or more images"
1215 } else if (!retry_busy
) {
1221 r
= cls_client::mirror_mode_set(&io_ctx
, next_mirror_mode
);
1223 lderr(cct
) << "failed to set mirror mode: " << cpp_strerror(r
) << dendl
;
1227 r
= MirroringWatcher
<>::notify_mode_updated(io_ctx
, next_mirror_mode
);
1229 lderr(cct
) << "failed to send update notification: " << cpp_strerror(r
)
1235 template <typename I
>
1236 int Mirror
<I
>::uuid_get(librados::IoCtx
& io_ctx
, std::string
* mirror_uuid
) {
1237 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1238 ldout(cct
, 20) << dendl
;
1241 uuid_get(io_ctx
, mirror_uuid
, &ctx
);
1245 lderr(cct
) << "failed to retrieve mirroring uuid: " << cpp_strerror(r
)
1254 template <typename I
>
1255 void Mirror
<I
>::uuid_get(librados::IoCtx
& io_ctx
, std::string
* mirror_uuid
,
1256 Context
* on_finish
) {
1257 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1258 ldout(cct
, 20) << dendl
;
1260 auto req
= mirror::GetUuidRequest
<I
>::create(io_ctx
, mirror_uuid
, on_finish
);
1264 template <typename I
>
1265 int Mirror
<I
>::peer_bootstrap_create(librados::IoCtx
& io_ctx
,
1266 std::string
* token
) {
1267 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1268 ldout(cct
, 20) << dendl
;
1270 auto mirror_mode
= cls::rbd::MIRROR_MODE_DISABLED
;
1271 int r
= cls_client::mirror_mode_get(&io_ctx
, &mirror_mode
);
1272 if (r
< 0 && r
!= -ENOENT
) {
1273 lderr(cct
) << "failed to retrieve mirroring mode: " << cpp_strerror(r
)
1276 } else if (mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
1280 // retrieve the cluster fsid
1282 librados::Rados
rados(io_ctx
);
1283 r
= rados
.cluster_fsid(&fsid
);
1285 lderr(cct
) << "failed to retrieve cluster fsid: " << cpp_strerror(r
)
1290 std::string peer_client_id
;
1291 std::string cephx_key
;
1292 r
= create_bootstrap_user(cct
, rados
, &peer_client_id
, &cephx_key
);
1297 std::string mon_host
= cct
->_conf
.get_val
<std::string
>("mon_host");
1298 ldout(cct
, 20) << "mon_host=" << mon_host
<< dendl
;
1300 // format the token response
1301 bufferlist token_bl
;
1304 R
"("fsid
":")" + fsid + R"(",)" + \
1305 R
"("client_id
":")" + peer_client_id + R"(",)" + \
1306 R
"("key
":")" + cephx_key + R"(",)" + \
1307 R
"("mon_host
":")" + \
1308 boost::replace_all_copy(mon_host, "\"", "\\\"") + R"(")" + \
1310 ldout(cct
, 20) << "token=" << token_bl
.to_str() << dendl
;
1312 bufferlist base64_bl
;
1313 token_bl
.encode_base64(base64_bl
);
1314 *token
= base64_bl
.to_str();
1319 template <typename I
>
1320 int Mirror
<I
>::peer_bootstrap_import(librados::IoCtx
& io_ctx
,
1321 rbd_mirror_peer_direction_t direction
,
1322 const std::string
& token
) {
1323 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1324 ldout(cct
, 20) << dendl
;
1326 if (direction
!= RBD_MIRROR_PEER_DIRECTION_RX
&&
1327 direction
!= RBD_MIRROR_PEER_DIRECTION_RX_TX
) {
1328 lderr(cct
) << "invalid mirror peer direction" << dendl
;
1332 bufferlist token_bl
;
1334 bufferlist base64_bl
;
1335 base64_bl
.append(token
);
1336 token_bl
.decode_base64(base64_bl
);
1337 } catch (buffer::error
& err
) {
1338 lderr(cct
) << "failed to decode base64" << dendl
;
1342 ldout(cct
, 20) << "token=" << token_bl
.to_str() << dendl
;
1344 bool json_valid
= false;
1345 std::string expected_remote_fsid
;
1346 std::string remote_client_id
;
1347 std::string remote_key
;
1348 std::string remote_mon_host
;
1350 json_spirit::mValue json_root
;
1351 if(json_spirit::read(token_bl
.to_str(), json_root
)) {
1353 auto& json_obj
= json_root
.get_obj();
1354 expected_remote_fsid
= json_obj
["fsid"].get_str();
1355 remote_client_id
= json_obj
["client_id"].get_str();
1356 remote_key
= json_obj
["key"].get_str();
1357 remote_mon_host
= json_obj
["mon_host"].get_str();
1359 } catch (std::runtime_error
&) {
1364 lderr(cct
) << "invalid bootstrap token JSON received" << dendl
;
1368 // sanity check import process
1369 std::string local_fsid
;
1370 librados::Rados
rados(io_ctx
);
1371 int r
= rados
.cluster_fsid(&local_fsid
);
1373 lderr(cct
) << "failed to retrieve cluster fsid: " << cpp_strerror(r
)
1378 std::string local_site_name
;
1379 r
= site_name_get(rados
, &local_site_name
);
1381 lderr(cct
) << "failed to retrieve cluster site name: " << cpp_strerror(r
)
1386 // attempt to connect to remote cluster
1387 librados::Rados remote_rados
;
1388 remote_rados
.init(remote_client_id
.c_str());
1390 auto remote_cct
= reinterpret_cast<CephContext
*>(remote_rados
.cct());
1391 remote_cct
->_conf
.set_val("mon_host", remote_mon_host
);
1392 remote_cct
->_conf
.set_val("key", remote_key
);
1394 r
= remote_rados
.connect();
1396 lderr(cct
) << "failed to connect to peer cluster: " << cpp_strerror(r
)
1401 std::string remote_fsid
;
1402 r
= remote_rados
.cluster_fsid(&remote_fsid
);
1404 lderr(cct
) << "failed to retrieve remote cluster fsid: "
1405 << cpp_strerror(r
) << dendl
;
1407 } else if (local_fsid
== remote_fsid
) {
1408 lderr(cct
) << "cannot import token for local cluster" << dendl
;
1410 } else if (expected_remote_fsid
!= remote_fsid
) {
1411 lderr(cct
) << "unexpected remote cluster fsid" << dendl
;
1415 std::string remote_site_name
;
1416 r
= site_name_get(remote_rados
, &remote_site_name
);
1418 lderr(cct
) << "failed to retrieve remote cluster site name: "
1419 << cpp_strerror(r
) << dendl
;
1421 } else if (local_site_name
== remote_site_name
) {
1422 lderr(cct
) << "cannot import token for duplicate site name" << dendl
;
1426 librados::IoCtx remote_io_ctx
;
1427 r
= remote_rados
.ioctx_create(io_ctx
.get_pool_name().c_str(), remote_io_ctx
);
1429 ldout(cct
, 10) << "remote pool does not exist" << dendl
;
1432 lderr(cct
) << "failed to open remote pool '" << io_ctx
.get_pool_name()
1433 << "': " << cpp_strerror(r
) << dendl
;
1437 auto remote_mirror_mode
= cls::rbd::MIRROR_MODE_DISABLED
;
1438 r
= cls_client::mirror_mode_get(&remote_io_ctx
, &remote_mirror_mode
);
1439 if (r
< 0 && r
!= -ENOENT
) {
1440 lderr(cct
) << "failed to retrieve remote mirroring mode: "
1441 << cpp_strerror(r
) << dendl
;
1443 } else if (remote_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
1447 auto local_mirror_mode
= cls::rbd::MIRROR_MODE_DISABLED
;
1448 r
= cls_client::mirror_mode_get(&io_ctx
, &local_mirror_mode
);
1449 if (r
< 0 && r
!= -ENOENT
) {
1450 lderr(cct
) << "failed to retrieve local mirroring mode: " << cpp_strerror(r
)
1453 } else if (local_mirror_mode
== cls::rbd::MIRROR_MODE_DISABLED
) {
1454 // copy mirror mode from remote peer
1455 r
= mode_set(io_ctx
, static_cast<rbd_mirror_mode_t
>(remote_mirror_mode
));
1461 if (direction
== RBD_MIRROR_PEER_DIRECTION_RX_TX
) {
1462 // create a local mirror peer user and export it to the remote cluster
1463 std::string local_client_id
;
1464 std::string local_key
;
1465 r
= create_bootstrap_user(cct
, rados
, &local_client_id
, &local_key
);
1470 std::string local_mon_host
= cct
->_conf
.get_val
<std::string
>("mon_host");
1472 // create local cluster peer in remote cluster
1473 r
= create_bootstrap_peer(cct
, remote_io_ctx
,
1474 RBD_MIRROR_PEER_DIRECTION_RX_TX
, local_site_name
,
1475 local_fsid
, local_client_id
, local_key
,
1476 local_mon_host
, "local", "remote");
1482 // create remote cluster peer in local cluster
1483 r
= create_bootstrap_peer(cct
, io_ctx
, direction
, remote_site_name
,
1484 remote_fsid
, remote_client_id
, remote_key
,
1485 remote_mon_host
, "remote", "local");
1493 template <typename I
>
1494 int Mirror
<I
>::peer_site_add(librados::IoCtx
& io_ctx
, std::string
*uuid
,
1495 mirror_peer_direction_t direction
,
1496 const std::string
&site_name
,
1497 const std::string
&client_name
) {
1498 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1499 ldout(cct
, 20) << "name=" << site_name
<< ", "
1500 << "client=" << client_name
<< dendl
;
1502 if (cct
->_conf
->cluster
== site_name
) {
1503 lderr(cct
) << "cannot add self as remote peer" << dendl
;
1507 if (direction
== RBD_MIRROR_PEER_DIRECTION_TX
) {
1514 uuid_gen
.generate_random();
1516 *uuid
= uuid_gen
.to_string();
1517 r
= cls_client::mirror_peer_add(
1518 &io_ctx
, {*uuid
, static_cast<cls::rbd::MirrorPeerDirection
>(direction
),
1519 site_name
, client_name
, ""});
1521 ldout(cct
, 5) << "duplicate UUID detected, retrying" << dendl
;
1523 lderr(cct
) << "failed to add mirror peer '" << site_name
<< "': "
1524 << cpp_strerror(r
) << dendl
;
1527 } while (r
== -ESTALE
);
1531 template <typename I
>
1532 int Mirror
<I
>::peer_site_remove(librados::IoCtx
& io_ctx
,
1533 const std::string
&uuid
) {
1534 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1535 ldout(cct
, 20) << "uuid=" << uuid
<< dendl
;
1537 int r
= remove_peer_config_key(io_ctx
, uuid
);
1539 lderr(cct
) << "failed to remove peer attributes '" << uuid
<< "': "
1540 << cpp_strerror(r
) << dendl
;
1544 r
= cls_client::mirror_peer_remove(&io_ctx
, uuid
);
1545 if (r
< 0 && r
!= -ENOENT
) {
1546 lderr(cct
) << "failed to remove peer '" << uuid
<< "': "
1547 << cpp_strerror(r
) << dendl
;
1551 vector
<string
> names
;
1552 r
= Namespace
<I
>::list(io_ctx
, &names
);
1557 names
.push_back("");
1559 librados::IoCtx ns_io_ctx
;
1560 ns_io_ctx
.dup(io_ctx
);
1562 for (auto &name
: names
) {
1563 ns_io_ctx
.set_namespace(name
);
1565 std::set
<std::string
> image_ids
;
1566 r
= list_mirror_images(ns_io_ctx
, image_ids
);
1568 lderr(cct
) << "failed listing images in "
1569 << (name
.empty() ? "default" : name
) << " namespace : "
1570 << cpp_strerror(r
) << dendl
;
1574 for (const auto& image_id
: image_ids
) {
1575 cls::rbd::MirrorImage mirror_image
;
1576 r
= cls_client::mirror_image_get(&ns_io_ctx
, image_id
, &mirror_image
);
1581 lderr(cct
) << "error getting mirror info for image " << image_id
1582 << ": " << cpp_strerror(r
) << dendl
;
1585 if (mirror_image
.mode
!= cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
) {
1589 // Snapshot based mirroring. Unlink the peer from mirroring snapshots.
1592 I
*img_ctx
= I::create("", image_id
, nullptr, ns_io_ctx
, false);
1593 img_ctx
->read_only_mask
&= ~IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
1595 r
= img_ctx
->state
->open(0);
1600 lderr(cct
) << "error opening image " << image_id
<< ": "
1601 << cpp_strerror(r
) << dendl
;
1605 std::list
<uint64_t> snap_ids
;
1607 std::shared_lock image_locker
{img_ctx
->image_lock
};
1608 for (auto &it
: img_ctx
->snap_info
) {
1609 auto info
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
1610 &it
.second
.snap_namespace
);
1611 if (info
&& info
->mirror_peer_uuids
.count(uuid
)) {
1612 snap_ids
.push_back(it
.first
);
1616 for (auto snap_id
: snap_ids
) {
1618 auto req
= mirror::snapshot::UnlinkPeerRequest
<I
>::create(
1619 img_ctx
, snap_id
, uuid
, &cond
);
1630 int close_r
= img_ctx
->state
->close();
1632 lderr(cct
) << "error unlinking peer for image " << image_id
<< ": "
1633 << cpp_strerror(r
) << dendl
;
1635 } else if (close_r
< 0) {
1636 lderr(cct
) << "failed to close image " << image_id
<< ": "
1637 << cpp_strerror(close_r
) << dendl
;
1646 template <typename I
>
1647 int Mirror
<I
>::peer_site_list(librados::IoCtx
& io_ctx
,
1648 std::vector
<mirror_peer_site_t
> *peers
) {
1649 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1650 ldout(cct
, 20) << dendl
;
1652 std::vector
<cls::rbd::MirrorPeer
> mirror_peers
;
1653 int r
= cls_client::mirror_peer_list(&io_ctx
, &mirror_peers
);
1654 if (r
< 0 && r
!= -ENOENT
) {
1655 lderr(cct
) << "failed to list peers: " << cpp_strerror(r
) << dendl
;
1660 peers
->reserve(mirror_peers
.size());
1661 for (auto &mirror_peer
: mirror_peers
) {
1662 mirror_peer_site_t peer
;
1663 peer
.uuid
= mirror_peer
.uuid
;
1664 peer
.direction
= static_cast<mirror_peer_direction_t
>(
1665 mirror_peer
.mirror_peer_direction
);
1666 peer
.site_name
= mirror_peer
.site_name
;
1667 peer
.mirror_uuid
= mirror_peer
.mirror_uuid
;
1668 peer
.client_name
= mirror_peer
.client_name
;
1669 peer
.last_seen
= mirror_peer
.last_seen
.sec();
1670 peers
->push_back(peer
);
1675 template <typename I
>
1676 int Mirror
<I
>::peer_site_set_client(librados::IoCtx
& io_ctx
,
1677 const std::string
&uuid
,
1678 const std::string
&client_name
) {
1679 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1680 ldout(cct
, 20) << "uuid=" << uuid
<< ", "
1681 << "client=" << client_name
<< dendl
;
1683 int r
= cls_client::mirror_peer_set_client(&io_ctx
, uuid
, client_name
);
1685 lderr(cct
) << "failed to update client '" << uuid
<< "': "
1686 << cpp_strerror(r
) << dendl
;
1692 template <typename I
>
1693 int Mirror
<I
>::peer_site_set_name(librados::IoCtx
& io_ctx
,
1694 const std::string
&uuid
,
1695 const std::string
&site_name
) {
1696 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1697 ldout(cct
, 20) << "uuid=" << uuid
<< ", "
1698 << "name=" << site_name
<< dendl
;
1700 if (cct
->_conf
->cluster
== site_name
) {
1701 lderr(cct
) << "cannot set self as remote peer" << dendl
;
1705 int r
= cls_client::mirror_peer_set_cluster(&io_ctx
, uuid
, site_name
);
1707 lderr(cct
) << "failed to update site '" << uuid
<< "': "
1708 << cpp_strerror(r
) << dendl
;
1714 template <typename I
>
1715 int Mirror
<I
>::peer_site_set_direction(librados::IoCtx
& io_ctx
,
1716 const std::string
&uuid
,
1717 mirror_peer_direction_t direction
) {
1718 cls::rbd::MirrorPeerDirection mirror_peer_direction
= static_cast<
1719 cls::rbd::MirrorPeerDirection
>(direction
);
1721 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1722 ldout(cct
, 20) << "uuid=" << uuid
<< ", "
1723 << "direction=" << mirror_peer_direction
<< dendl
;
1725 int r
= cls_client::mirror_peer_set_direction(&io_ctx
, uuid
,
1726 mirror_peer_direction
);
1728 lderr(cct
) << "failed to update direction '" << uuid
<< "': "
1729 << cpp_strerror(r
) << dendl
;
1735 template <typename I
>
1736 int Mirror
<I
>::peer_site_get_attributes(librados::IoCtx
& io_ctx
,
1737 const std::string
&uuid
,
1738 Attributes
* attributes
) {
1739 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1740 ldout(cct
, 20) << "uuid=" << uuid
<< dendl
;
1742 attributes
->clear();
1744 librados::Rados
rados(io_ctx
);
1746 int r
= get_config_key(rados
, get_peer_config_key_name(io_ctx
.get_id(), uuid
),
1748 if (r
== -ENOENT
|| value
.empty()) {
1751 lderr(cct
) << "failed to retrieve peer attributes: " << cpp_strerror(r
)
1756 bool json_valid
= false;
1757 json_spirit::mValue json_root
;
1758 if(json_spirit::read(value
, json_root
)) {
1760 auto& json_obj
= json_root
.get_obj();
1761 for (auto& pairs
: json_obj
) {
1762 (*attributes
)[pairs
.first
] = pairs
.second
.get_str();
1765 } catch (std::runtime_error
&) {
1770 lderr(cct
) << "invalid peer attributes JSON received" << dendl
;
1776 template <typename I
>
1777 int Mirror
<I
>::peer_site_set_attributes(librados::IoCtx
& io_ctx
,
1778 const std::string
&uuid
,
1779 const Attributes
& attributes
) {
1780 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1781 ldout(cct
, 20) << "uuid=" << uuid
<< ", "
1782 << "attributes=" << attributes
<< dendl
;
1784 std::vector
<mirror_peer_site_t
> mirror_peers
;
1785 int r
= peer_site_list(io_ctx
, &mirror_peers
);
1790 if (std::find_if(mirror_peers
.begin(), mirror_peers
.end(),
1791 [&uuid
](const librbd::mirror_peer_site_t
& peer
) {
1792 return uuid
== peer
.uuid
;
1793 }) == mirror_peers
.end()) {
1794 ldout(cct
, 5) << "mirror peer uuid " << uuid
<< " does not exist" << dendl
;
1798 std::stringstream ss
;
1800 for (auto& pair
: attributes
) {
1801 ss
<< "\\\"" << pair
.first
<< "\\\": "
1802 << "\\\"" << pair
.second
<< "\\\"";
1803 if (&pair
!= &(*attributes
.rbegin())) {
1809 librados::Rados
rados(io_ctx
);
1810 r
= set_config_key(rados
, get_peer_config_key_name(io_ctx
.get_id(), uuid
),
1812 if (r
< 0 && r
!= -ENOENT
) {
1813 lderr(cct
) << "failed to update peer attributes: " << cpp_strerror(r
)
1821 template <typename I
>
1822 int Mirror
<I
>::image_global_status_list(
1823 librados::IoCtx
& io_ctx
, const std::string
&start_id
, size_t max
,
1824 IdToMirrorImageGlobalStatus
*images
) {
1825 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1828 map
<string
, string
> id_to_name
;
1830 map
<string
, string
> name_to_id
;
1831 r
= Image
<I
>::list_images_v2(io_ctx
, &name_to_id
);
1835 for (auto it
: name_to_id
) {
1836 id_to_name
[it
.second
] = it
.first
;
1840 map
<std::string
, cls::rbd::MirrorImage
> images_
;
1841 map
<std::string
, cls::rbd::MirrorImageStatus
> statuses_
;
1843 r
= librbd::cls_client::mirror_image_status_list(&io_ctx
, start_id
, max
,
1844 &images_
, &statuses_
);
1845 if (r
< 0 && r
!= -ENOENT
) {
1846 lderr(cct
) << "failed to list mirror image statuses: "
1847 << cpp_strerror(r
) << dendl
;
1851 const std::string
STATUS_NOT_FOUND("status not found");
1852 for (auto it
= images_
.begin(); it
!= images_
.end(); ++it
) {
1853 auto &image_id
= it
->first
;
1854 auto &info
= it
->second
;
1855 if (info
.state
== cls::rbd::MIRROR_IMAGE_STATE_DISABLED
) {
1859 auto &image_name
= id_to_name
[image_id
];
1860 if (image_name
.empty()) {
1861 lderr(cct
) << "failed to find image name for image " << image_id
<< ", "
1862 << "using image id as name" << dendl
;
1863 image_name
= image_id
;
1866 mirror_image_global_status_t
& global_status
= (*images
)[image_id
];
1867 global_status
.name
= image_name
;
1868 global_status
.info
= mirror_image_info_t
{
1869 info
.global_image_id
,
1870 static_cast<mirror_image_state_t
>(info
.state
),
1871 false}; // XXX: To set "primary" right would require an additional call.
1873 auto s_it
= statuses_
.find(image_id
);
1874 if (s_it
!= statuses_
.end()) {
1875 auto& status
= s_it
->second
;
1877 global_status
.site_statuses
.reserve(
1878 status
.mirror_image_site_statuses
.size());
1879 for (auto& site_status
: status
.mirror_image_site_statuses
) {
1880 global_status
.site_statuses
.push_back(mirror_image_site_status_t
{
1881 site_status
.mirror_uuid
,
1882 static_cast<mirror_image_status_state_t
>(site_status
.state
),
1883 site_status
.state
== cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
?
1884 STATUS_NOT_FOUND
: site_status
.description
,
1885 site_status
.last_update
.sec(), site_status
.up
});
1888 // older OSD that only returns local status
1889 global_status
.site_statuses
.push_back(mirror_image_site_status_t
{
1890 cls::rbd::MirrorImageSiteStatus::LOCAL_MIRROR_UUID
,
1891 MIRROR_IMAGE_STATUS_STATE_UNKNOWN
, STATUS_NOT_FOUND
, 0, false});
1898 template <typename I
>
1899 int Mirror
<I
>::image_status_summary(librados::IoCtx
& io_ctx
,
1900 MirrorImageStatusStates
*states
) {
1901 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1903 std::vector
<cls::rbd::MirrorPeer
> mirror_peers
;
1904 int r
= cls_client::mirror_peer_list(&io_ctx
, &mirror_peers
);
1905 if (r
< 0 && r
!= -ENOENT
) {
1906 lderr(cct
) << "failed to list mirror peers: " << cpp_strerror(r
) << dendl
;
1910 std::map
<cls::rbd::MirrorImageStatusState
, int> states_
;
1911 r
= cls_client::mirror_image_status_get_summary(&io_ctx
, mirror_peers
,
1913 if (r
< 0 && r
!= -ENOENT
) {
1914 lderr(cct
) << "failed to get mirror status summary: "
1915 << cpp_strerror(r
) << dendl
;
1918 for (auto &s
: states_
) {
1919 (*states
)[static_cast<mirror_image_status_state_t
>(s
.first
)] = s
.second
;
1924 template <typename I
>
1925 int Mirror
<I
>::image_instance_id_list(
1926 librados::IoCtx
& io_ctx
, const std::string
&start_image_id
, size_t max
,
1927 std::map
<std::string
, std::string
> *instance_ids
) {
1928 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1929 std::map
<std::string
, entity_inst_t
> instances
;
1931 int r
= librbd::cls_client::mirror_image_instance_list(
1932 &io_ctx
, start_image_id
, max
, &instances
);
1933 if (r
< 0 && r
!= -ENOENT
) {
1934 lderr(cct
) << "failed to list mirror image instances: " << cpp_strerror(r
)
1939 for (auto it
: instances
) {
1940 (*instance_ids
)[it
.first
] = stringify(it
.second
.name
.num());
1946 template <typename I
>
1947 int Mirror
<I
>::image_info_list(
1948 librados::IoCtx
& io_ctx
, mirror_image_mode_t
*mode_filter
,
1949 const std::string
&start_id
, size_t max
,
1950 std::map
<std::string
, std::pair
<mirror_image_mode_t
,
1951 mirror_image_info_t
>> *entries
) {
1952 CephContext
*cct
= reinterpret_cast<CephContext
*>(io_ctx
.cct());
1953 ldout(cct
, 20) << "pool=" << io_ctx
.get_pool_name() << ", mode_filter="
1954 << (mode_filter
? stringify(*mode_filter
) : "null")
1955 << ", start_id=" << start_id
<< ", max=" << max
<< dendl
;
1957 std::string last_read
= start_id
;
1960 while (entries
->size() < max
) {
1961 map
<std::string
, cls::rbd::MirrorImage
> images
;
1962 map
<std::string
, cls::rbd::MirrorImageStatus
> statuses
;
1964 int r
= librbd::cls_client::mirror_image_status_list(&io_ctx
, last_read
,
1967 if (r
< 0 && r
!= -ENOENT
) {
1968 lderr(cct
) << "failed to list mirror image statuses: "
1969 << cpp_strerror(r
) << dendl
;
1973 if (images
.empty()) {
1977 ThreadPool
*thread_pool
;
1978 ContextWQ
*op_work_queue
;
1979 ImageCtx::get_thread_pool_instance(cct
, &thread_pool
, &op_work_queue
);
1981 for (auto &it
: images
) {
1982 auto &image_id
= it
.first
;
1983 auto &image
= it
.second
;
1984 auto mode
= static_cast<mirror_image_mode_t
>(image
.mode
);
1986 if ((mode_filter
&& mode
!= *mode_filter
) ||
1987 image
.state
!= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
) {
1991 // need to call get_info for every image to retrieve promotion state
1993 mirror_image_info_t info
;
1994 r
= image_get_info(io_ctx
, op_work_queue
, image_id
, &info
);
1999 (*entries
)[image_id
] = std::make_pair(mode
, info
);
2000 if (entries
->size() == max
) {
2005 last_read
= images
.rbegin()->first
;
2011 template <typename I
>
2012 int Mirror
<I
>::image_snapshot_create(I
*ictx
, uint32_t flags
,
2013 uint64_t *snap_id
) {
2015 Mirror
<I
>::image_snapshot_create(ictx
, flags
, snap_id
, &ctx
);
2020 template <typename I
>
2021 void Mirror
<I
>::image_snapshot_create(I
*ictx
, uint32_t flags
,
2022 uint64_t *snap_id
, Context
*on_finish
) {
2023 CephContext
*cct
= ictx
->cct
;
2024 ldout(cct
, 20) << "ictx=" << ictx
<< dendl
;
2027 lderr(cct
) << "invalid snap create flags: " << std::bitset
<32>(flags
)
2029 on_finish
->complete(-EINVAL
);
2033 auto on_refresh
= new LambdaContext(
2034 [ictx
, snap_id
, on_finish
](int r
) {
2036 lderr(ictx
->cct
) << "refresh failed: " << cpp_strerror(r
) << dendl
;
2037 on_finish
->complete(r
);
2041 auto ctx
= new C_ImageSnapshotCreate
<I
>(ictx
, snap_id
, on_finish
);
2042 auto req
= mirror::GetInfoRequest
<I
>::create(*ictx
, &ctx
->mirror_image
,
2043 &ctx
->promotion_state
,
2044 &ctx
->primary_mirror_uuid
,
2049 if (ictx
->state
->is_refresh_required()) {
2050 ictx
->state
->refresh(on_refresh
);
2052 on_refresh
->complete(0);
2057 } // namespace librbd
2059 template class librbd::api::Mirror
<librbd::ImageCtx
>;