]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-mirror: allow mirroring to a different namespace
authorN Balachandran <nibalach@redhat.com>
Fri, 23 Aug 2024 12:09:16 +0000 (17:39 +0530)
committerN Balachandran <nibalach@redhat.com>
Tue, 17 Sep 2024 09:10:27 +0000 (14:40 +0530)
Allows a namespace in a pool to be mirrored to a differently named
namespace in the secondary cluster.

Signed-off-by: N Balachandran <nibalach@redhat.com>
27 files changed:
doc/man/8/rbd.rst
qa/workunits/rbd/rbd_mirror.sh
qa/workunits/rbd/rbd_mirror_bootstrap.sh
qa/workunits/rbd/rbd_mirror_ha.sh
qa/workunits/rbd/rbd_mirror_helpers.sh
qa/workunits/rbd/rbd_mirror_stress.sh
src/cls/rbd/cls_rbd.cc
src/cls/rbd/cls_rbd_client.cc
src/cls/rbd/cls_rbd_client.h
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Mirror.cc
src/librbd/api/Mirror.h
src/librbd/librbd.cc
src/pybind/rbd/c_rbd.pxd
src/pybind/rbd/mock_rbd.pxi
src/pybind/rbd/rbd.pyx
src/test/cli/rbd/help.t
src/test/cls_rbd/test_cls_rbd.cc
src/test/pybind/test_rbd.py
src/test/rbd_mirror/test_mock_NamespaceReplayer.cc
src/test/rbd_mirror/test_mock_PoolReplayer.cc
src/tools/rbd/action/MirrorPool.cc
src/tools/rbd_mirror/NamespaceReplayer.cc
src/tools/rbd_mirror/NamespaceReplayer.h
src/tools/rbd_mirror/PoolReplayer.cc
src/tools/rbd_mirror/PoolReplayer.h

index 0f490506aa6b414a0563ec26ea75f978e82194bb..24d4fa4a31d51118e75ec4e9fe6442fee6afa974 100644 (file)
@@ -543,8 +543,9 @@ Commands
 
 :command:`mirror pool info` [*pool-name*]
   Show information about the pool or namespace mirroring configuration.
-  For a pool, it includes mirroring mode, peer UUID, remote cluster name,
-  and remote client name. For a namespace, it includes only mirroring mode.
+  For both pools and namespaces, it includes the mirroring mode
+  and remote namespace. For pools, it additionally includes the site name,
+  peer UUID, mirror UUID, remote cluster name, and remote client name.
 
 :command:`mirror pool peer add` [*pool-name*] *remote-cluster-spec*
   Add a mirroring peer to a pool.
@@ -555,7 +556,7 @@ Commands
   This requires mirroring to be enabled on the pool.
 
 :command:`mirror pool peer remove` [*pool-name*] *uuid*
-  Remove a mirroring peer from a pool. The peer uuid is available
+  Remove a mirroring peer from a pool. The peer UUID is available
   from ``mirror pool info`` command.
 
 :command:`mirror pool peer set` [*pool-name*] *uuid* *key* *value*
index 1cda355039eb80b29bfc0420ce632d1f088c1a01..90d5204b92feb52375f1924aadff702e2d0affd8 100755 (executable)
@@ -37,12 +37,12 @@ set_image_meta ${CLUSTER2} ${POOL} ${image} "key1" "value1"
 set_image_meta ${CLUSTER2} ${POOL} ${image} "key2" "value2"
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
 write_image ${CLUSTER2} ${POOL} ${image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
 if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then
   wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'down+unknown'
 fi
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 compare_image_meta ${CLUSTER1} ${POOL} ${image} "key1" "value1"
 compare_image_meta ${CLUSTER1} ${POOL} ${image} "key2" "value2"
 
@@ -53,19 +53,19 @@ create_image_and_enable_mirror ${CLUSTER2} ${POOL} ${image1} ${RBD_MIRROR_MODE}
 write_image ${CLUSTER2} ${POOL} ${image1} 100
 start_mirrors ${CLUSTER1}
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image1}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image1}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image1}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image1}
 if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then
   wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image1} 'down+unknown'
 fi
-compare_images ${POOL} ${image1}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image1}
 
 testlog "TEST: test the first image is replaying after restart"
 write_image ${CLUSTER2} ${POOL} ${image} 100
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
 if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then
   testlog "TEST: stop/start/restart mirror via admin socket"
@@ -173,7 +173,7 @@ wait_for_image_in_omap ${CLUSTER2} ${POOL}
 create_image_and_enable_mirror ${CLUSTER2} ${POOL} ${image} ${RBD_MIRROR_MODE}
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
 write_image ${CLUSTER2} ${POOL} ${image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying'
 
 testlog "TEST: failover and failback"
@@ -187,10 +187,10 @@ wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown'
 promote_image ${CLUSTER2} ${POOL} ${image}
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
 write_image ${CLUSTER2} ${POOL} ${image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+stopped'
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
 # failover (unmodified)
 demote_image ${CLUSTER2} ${POOL} ${image}
@@ -207,10 +207,10 @@ wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+unknown'
 wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown'
 promote_image ${CLUSTER2} ${POOL} ${image}
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
 wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+stopped'
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
 # failover
 demote_image ${CLUSTER2} ${POOL} ${image}
@@ -220,10 +220,10 @@ wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown'
 promote_image ${CLUSTER1} ${POOL} ${image}
 wait_for_image_replay_started ${CLUSTER2} ${POOL} ${image}
 write_image ${CLUSTER1} ${POOL} ${image} 100
-wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${POOL} ${POOL} ${image}
 wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+stopped'
 wait_for_replaying_status_in_pool_dir ${CLUSTER2} ${POOL} ${image}
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
 # failback
 demote_image ${CLUSTER1} ${POOL} ${image}
@@ -233,10 +233,10 @@ wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown'
 promote_image ${CLUSTER2} ${POOL} ${image}
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
 write_image ${CLUSTER2} ${POOL} ${image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
 wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+stopped'
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
 testlog "TEST: failover / failback loop"
 for i in `seq 1 20`; do
@@ -246,7 +246,7 @@ for i in `seq 1 20`; do
   wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown'
   promote_image ${CLUSTER1} ${POOL} ${image}
   wait_for_image_replay_started ${CLUSTER2} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${POOL} ${POOL} ${image}
   wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+stopped'
   wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+replaying'
   demote_image ${CLUSTER1} ${POOL} ${image}
@@ -255,7 +255,7 @@ for i in `seq 1 20`; do
   wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+unknown'
   promote_image ${CLUSTER2} ${POOL} ${image}
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} 'up+stopped'
   wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying'
 done
@@ -271,7 +271,7 @@ create_image_and_enable_mirror ${CLUSTER2} ${POOL} ${force_promote_image} ${RBD_
 write_image ${CLUSTER2} ${POOL} ${force_promote_image} 100
 wait_for_image_replay_stopped ${CLUSTER2} ${POOL} ${force_promote_image}
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${force_promote_image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${force_promote_image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${force_promote_image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${force_promote_image}
 wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${force_promote_image} 'up+stopped'
 promote_image ${CLUSTER1} ${POOL} ${force_promote_image} '--force'
@@ -302,14 +302,14 @@ else
   enable_mirror ${CLUSTER2} ${PARENT_POOL} ${parent_image} ${RBD_MIRROR_MODE}
 fi
 wait_for_image_replay_started ${CLUSTER1} ${PARENT_POOL} ${parent_image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${PARENT_POOL} ${parent_image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${PARENT_POOL} ${PARENT_POOL} ${parent_image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${PARENT_POOL} ${parent_image}
-compare_images ${PARENT_POOL} ${parent_image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${PARENT_POOL} ${PARENT_POOL} ${parent_image}
 
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${clone_image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${clone_image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${clone_image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${clone_image}
-compare_images ${POOL} ${clone_image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${clone_image}
 remove_image_retry ${CLUSTER2} ${POOL} ${clone_image}
 
 testlog " - clone v1"
@@ -383,11 +383,11 @@ create_snapshot ${CLUSTER2} ${POOL} ${dp_image} 'snap1'
 write_image ${CLUSTER2} ${POOL} ${dp_image} 100
 create_snapshot ${CLUSTER2} ${POOL} ${dp_image} 'snap2'
 write_image ${CLUSTER2} ${POOL} ${dp_image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${dp_image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${dp_image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${dp_image}
-compare_images ${POOL} ${dp_image}@snap1
-compare_images ${POOL} ${dp_image}@snap2
-compare_images ${POOL} ${dp_image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${dp_image}@snap1
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${dp_image}@snap2
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${dp_image}
 remove_image_retry ${CLUSTER2} ${POOL} ${dp_image}
 
 testlog "TEST: disable mirroring / delete non-primary image"
@@ -436,8 +436,8 @@ if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
     wait_for_image_present ${CLUSTER1} ${POOL} ${i} 'present'
     wait_for_snap_present ${CLUSTER1} ${POOL} ${i} 'snap2'
     wait_for_image_replay_started ${CLUSTER1} ${POOL} ${i}
-    wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${i}
-    compare_images ${POOL} ${i}
+    wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${i}
+    compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${i}
   done
 
   testlog "TEST: remove mirroring pool"
@@ -454,9 +454,9 @@ if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
   create_image ${CLUSTER2} ${POOL} ${rdp_image} 128 --data-pool ${pool}
   write_image ${CLUSTER2} ${pool} ${image} 100
   write_image ${CLUSTER2} ${POOL} ${rdp_image} 100
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${pool} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${pool} ${pool} ${image}
   wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${pool} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${rdp_image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${rdp_image}
   wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${rdp_image}
   for cluster in ${CLUSTER1} ${CLUSTER2}; do
     CEPH_ARGS='' ceph --cluster ${cluster} osd pool rm ${pool} ${pool} --yes-i-really-really-mean-it
@@ -519,12 +519,12 @@ wait_for_image_replay_started ${CLUSTER1} ${POOL}/${NS1} ${image}
 wait_for_image_replay_started ${CLUSTER1} ${POOL}/${NS2} ${image}
 write_image ${CLUSTER2} ${POOL}/${NS1} ${image} 100
 write_image ${CLUSTER2} ${POOL}/${NS2} ${image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS1} ${image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS2} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS1} ${POOL}/${NS1} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS2} ${POOL}/${NS2} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL}/${NS1} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL}/${NS2} ${image}
-compare_images ${POOL}/${NS1} ${image}
-compare_images ${POOL}/${NS2} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS1} ${POOL}/${NS1} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS2} ${POOL}/${NS2} ${image}
 
 testlog " - disable mirroring / delete image"
 remove_image_retry ${CLUSTER2} ${POOL}/${NS1} ${image}
@@ -533,6 +533,40 @@ wait_for_image_present ${CLUSTER1} ${POOL}/${NS1} ${image} 'deleted'
 wait_for_image_present ${CLUSTER1} ${POOL}/${NS2} ${image} 'deleted'
 remove_image_retry ${CLUSTER2} ${POOL}/${NS2} ${image}
 
+testlog "TEST: mirror to a different remote namespace"
+testlog " - replay"
+NS3=ns3
+NS4=ns4
+rbd --cluster ${CLUSTER1} namespace create ${POOL}/${NS3}
+rbd --cluster ${CLUSTER2} namespace create ${POOL}/${NS4}
+rbd --cluster ${CLUSTER1} mirror pool enable ${POOL}/${NS3} ${MIRROR_POOL_MODE} --remote-namespace ${NS4}
+rbd --cluster ${CLUSTER2} mirror pool enable ${POOL}/${NS4} ${MIRROR_POOL_MODE} --remote-namespace ${NS3}
+create_image_and_enable_mirror ${CLUSTER2} ${POOL}/${NS4} ${image} ${RBD_MIRROR_MODE}
+wait_for_image_replay_started ${CLUSTER1} ${POOL}/${NS3} ${image}
+write_image ${CLUSTER2} ${POOL}/${NS4} ${image} 100
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS3} ${POOL}/${NS4} ${image}
+wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL}/${NS3} ${image}
+compare_images  ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS3} ${POOL}/${NS4} ${image}
+
+testlog " - disable mirroring and re-enable without remote-namespace"
+remove_image_retry ${CLUSTER2} ${POOL}/${NS4} ${image}
+wait_for_image_present ${CLUSTER1} ${POOL}/${NS3} ${image} 'deleted'
+rbd --cluster ${CLUSTER1} mirror pool disable ${POOL}/${NS3}
+rbd --cluster ${CLUSTER2} mirror pool disable ${POOL}/${NS4}
+rbd --cluster ${CLUSTER2} namespace create ${POOL}/${NS3}
+rbd --cluster ${CLUSTER2} mirror pool enable ${POOL}/${NS3} ${MIRROR_POOL_MODE}
+rbd --cluster ${CLUSTER1} mirror pool enable ${POOL}/${NS3} ${MIRROR_POOL_MODE}
+create_image_and_enable_mirror ${CLUSTER2} ${POOL}/${NS3} ${image} ${RBD_MIRROR_MODE}
+wait_for_image_replay_started ${CLUSTER1} ${POOL}/${NS3} ${image}
+write_image ${CLUSTER2} ${POOL}/${NS3} ${image} 100
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS3} ${POOL}/${NS3} ${image}
+wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL}/${NS3} ${image}
+compare_images  ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS3} ${POOL}/${NS3} ${image}
+remove_image_retry ${CLUSTER2} ${POOL}/${NS3} ${image}
+wait_for_image_present ${CLUSTER1} ${POOL}/${NS3} ${image} 'deleted'
+rbd --cluster ${CLUSTER1} mirror pool disable ${POOL}/${NS3}
+rbd --cluster ${CLUSTER2} mirror pool disable ${POOL}/${NS3}
+
 testlog " - data pool"
 dp_image=test_data_pool
 create_image_and_enable_mirror ${CLUSTER2} ${POOL}/${NS1} ${dp_image} ${RBD_MIRROR_MODE} 128 --data-pool ${PARENT_POOL}
@@ -542,9 +576,9 @@ wait_for_image_replay_started ${CLUSTER1} ${POOL}/${NS1} ${dp_image}
 data_pool=$(get_image_data_pool ${CLUSTER1} ${POOL}/${NS1} ${dp_image})
 test "${data_pool}" = "${PARENT_POOL}"
 write_image ${CLUSTER2} ${POOL}/${NS1} ${dp_image} 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS1} ${dp_image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS1} ${POOL}/${NS1} ${dp_image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL}/${NS1} ${dp_image}
-compare_images ${POOL}/${NS1} ${dp_image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL}/${NS1} ${POOL}/${NS1} ${dp_image}
 remove_image_retry ${CLUSTER2} ${POOL}/${NS1} ${dp_image}
 
 testlog "TEST: simple image resync"
@@ -553,7 +587,7 @@ wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id}
 wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present'
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
 if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then
   testlog "TEST: image resync while replayer is stopped"
@@ -566,7 +600,7 @@ if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present'
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
   wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
-  compare_images ${POOL} ${image}
+  compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 fi
 
 testlog "TEST: request image resync while daemon is offline"
@@ -577,7 +611,7 @@ wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id}
 wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present'
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${POOL} ${image}
-compare_images ${POOL} ${image}
+compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 remove_image_retry ${CLUSTER2} ${POOL} ${image}
 
 if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
@@ -588,7 +622,7 @@ if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
 
   testlog " - replay stopped after disconnect"
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   test -n "$(get_mirror_journal_position ${CLUSTER2} ${POOL} ${image})"
   disconnect_image ${CLUSTER2} ${POOL} ${image}
   test -z "$(get_mirror_journal_position ${CLUSTER2} ${POOL} ${image})"
@@ -600,9 +634,9 @@ if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id}
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present'
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   test -n "$(get_mirror_journal_position ${CLUSTER2} ${POOL} ${image})"
-  compare_images ${POOL} ${image}
+  compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
   testlog " - disconnected after max_concurrent_object_sets reached"
   if [ -z "${RBD_MIRROR_USE_RBD_MIRROR}" ]; then
@@ -628,25 +662,25 @@ if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id}
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present'
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   test -n "$(get_mirror_journal_position ${CLUSTER2} ${POOL} ${image})"
-  compare_images ${POOL} ${image}
+  compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 
   testlog " - rbd_mirroring_resync_after_disconnect config option"
   set_image_meta ${CLUSTER2} ${POOL} ${image} \
          conf_rbd_mirroring_resync_after_disconnect true
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   image_id=$(get_image_id ${CLUSTER1} ${POOL} ${image})
   disconnect_image ${CLUSTER2} ${POOL} ${image}
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'deleted' ${image_id}
   wait_for_image_present ${CLUSTER1} ${POOL} ${image} 'present'
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   test -n "$(get_mirror_journal_position ${CLUSTER2} ${POOL} ${image})"
-  compare_images ${POOL} ${image}
+  compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   set_image_meta ${CLUSTER2} ${POOL} ${image} \
          conf_rbd_mirroring_resync_after_disconnect false
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   disconnect_image ${CLUSTER2} ${POOL} ${image}
   test -z "$(get_mirror_journal_position ${CLUSTER2} ${POOL} ${image})"
   wait_for_image_replay_stopped ${CLUSTER1} ${POOL} ${image}
index 412e84c88a64bb71ff9099bea26e0facb425822d..3ddb0aa219b79fcb191d8724d425da8cc8acee00 100755 (executable)
@@ -38,7 +38,7 @@ create_image_and_enable_mirror ${CLUSTER1} ${POOL} image1
 
 wait_for_image_replay_started ${CLUSTER2} ${POOL} image1
 write_image ${CLUSTER1} ${POOL} image1 100
-wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${POOL} image1
+wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${POOL} ${POOL} image1
 wait_for_replaying_status_in_pool_dir ${CLUSTER2} ${POOL} image1
 
 testlog "TEST: verify rx-tx direction"
@@ -54,12 +54,12 @@ enable_mirror ${CLUSTER2} ${PARENT_POOL} image2
 
 wait_for_image_replay_started ${CLUSTER2} ${PARENT_POOL} image1
 write_image ${CLUSTER1} ${PARENT_POOL} image1 100
-wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${PARENT_POOL} image1
+wait_for_replay_complete ${CLUSTER2} ${CLUSTER1} ${PARENT_POOL} ${PARENT_POOL} image1
 wait_for_replaying_status_in_pool_dir ${CLUSTER2} ${PARENT_POOL} image1
 
 wait_for_image_replay_started ${CLUSTER1} ${PARENT_POOL} image2
 write_image ${CLUSTER2} ${PARENT_POOL} image2 100
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${PARENT_POOL} image2
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${PARENT_POOL} ${PARENT_POOL} image2
 wait_for_replaying_status_in_pool_dir ${CLUSTER1} ${PARENT_POOL} image2
 
 testlog "TEST: pool replayer and callout cleanup when peer is updated"
index 1e43712a6315244f0d0f63025f3352385ec76465..e5a086b82ab8652aa227a2d609e54ed8be5eaa4e 100755 (executable)
@@ -71,7 +71,7 @@ test_replay()
        wait_for_image_replay_started ${CLUSTER1}:${LEADER} ${POOL} ${image}
        write_image ${CLUSTER2} ${POOL} ${image} 100
        wait_for_replay_complete ${CLUSTER1}:${LEADER} ${CLUSTER2} ${POOL} \
-                                ${image}
+                                ${POOL} ${image}
        wait_for_status_in_pool_dir ${CLUSTER1} ${POOL} ${image} 'up+replaying' \
                                     'primary_position' \
                                     "${MIRROR_USER_ID_PREFIX}${LEADER} on $(hostname -s)"
@@ -79,7 +79,7 @@ test_replay()
            wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} \
                                        'down+unknown'
        fi
-       compare_images ${POOL} ${image}
+       compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
     done
 }
 
index 1c3062891768da4971a40485ceec2fafaad82735..1b1436db74d7022cd2daec4b521d007520d1bfff 100755 (executable)
@@ -743,17 +743,18 @@ wait_for_journal_replay_complete()
 {
     local local_cluster=$1
     local cluster=$2
-    local pool=$3
-    local image=$4
+    local local_pool=$3
+    local remote_pool=$4
+    local image=$5
     local s master_pos mirror_pos last_mirror_pos
     local master_tag master_entry mirror_tag mirror_entry
 
     while true; do
         for s in 0.2 0.4 0.8 1.6 2 2 4 4 8 8 16 16 32 32; do
             sleep ${s}
-            flush "${local_cluster}" "${pool}" "${image}"
-            master_pos=$(get_master_journal_position "${cluster}" "${pool}" "${image}")
-            mirror_pos=$(get_mirror_journal_position "${cluster}" "${pool}" "${image}")
+            flush "${local_cluster}" "${local_pool}" "${image}"
+            master_pos=$(get_master_journal_position "${cluster}" "${remote_pool}" "${image}")
+            mirror_pos=$(get_mirror_journal_position "${cluster}" "${remote_pool}" "${image}")
             test -n "${master_pos}" -a "${master_pos}" = "${mirror_pos}" && return 0
             test "${mirror_pos}" != "${last_mirror_pos}" && break
         done
@@ -796,21 +797,22 @@ wait_for_snapshot_sync_complete()
 {
     local local_cluster=$1
     local cluster=$2
-    local pool=$3
-    local image=$4
+    local local_pool=$3
+    local remote_pool=$4
+    local image=$5
 
-    local status_log=${TEMPDIR}/$(mkfname ${cluster}-${pool}-${image}.status)
-    local local_status_log=${TEMPDIR}/$(mkfname ${local_cluster}-${pool}-${image}.status)
+    local status_log=${TEMPDIR}/$(mkfname ${cluster}-${remote_pool}-${image}.status)
+    local local_status_log=${TEMPDIR}/$(mkfname ${local_cluster}-${local_pool}-${image}.status)
 
-    mirror_image_snapshot "${cluster}" "${pool}" "${image}"
-    get_newest_mirror_snapshot "${cluster}" "${pool}" "${image}" "${status_log}"
+    mirror_image_snapshot "${cluster}" "${remote_pool}" "${image}"
+    get_newest_mirror_snapshot "${cluster}" "${remote_pool}" "${image}" "${status_log}"
     local snapshot_id=$(xmlstarlet sel -t -v "//snapshot/id" < ${status_log})
 
     while true; do
         for s in 0.2 0.4 0.8 1.6 2 2 4 4 8 8 16 16 32 32; do
             sleep ${s}
 
-            get_newest_mirror_snapshot "${local_cluster}" "${pool}" "${image}" "${local_status_log}"
+            get_newest_mirror_snapshot "${local_cluster}" "${local_pool}" "${image}" "${local_status_log}"
             local primary_snapshot_id=$(xmlstarlet sel -t -v "//snapshot/namespace/primary_snap_id" < ${local_status_log})
 
             test "${snapshot_id}" = "${primary_snapshot_id}" && return 0
@@ -825,13 +827,14 @@ wait_for_replay_complete()
 {
     local local_cluster=$1
     local cluster=$2
-    local pool=$3
-    local image=$4
+    local local_pool=$3
+    local remote_pool=$4
+    local image=$5
 
     if [ "${RBD_MIRROR_MODE}" = "journal" ]; then
-        wait_for_journal_replay_complete ${local_cluster} ${cluster} ${pool} ${image}
+        wait_for_journal_replay_complete ${local_cluster} ${cluster} ${local_pool} ${remote_pool} ${image}
     elif [ "${RBD_MIRROR_MODE}" = "snapshot" ]; then
-        wait_for_snapshot_sync_complete ${local_cluster} ${cluster} ${pool} ${image}
+        wait_for_snapshot_sync_complete ${local_cluster} ${cluster} ${local_pool} ${remote_pool} ${image}
     else
         return 1
     fi
@@ -1298,16 +1301,19 @@ show_diff()
 
 compare_images()
 {
-    local pool=$1
-    local image=$2
     local ret=0
+    local local_cluster=$1
+    local cluster=$2
+    local local_pool=$3
+    local remote_pool=$4
+    local image=$5
 
-    local rmt_export=${TEMPDIR}/$(mkfname ${CLUSTER2}-${pool}-${image}.export)
-    local loc_export=${TEMPDIR}/$(mkfname ${CLUSTER1}-${pool}-${image}.export)
+    local rmt_export=${TEMPDIR}/$(mkfname ${cluster}-${remote_pool}-${image}.export)
+    local loc_export=${TEMPDIR}/$(mkfname ${local_cluster}-${local_pool}-${image}.export)
 
     rm -f ${rmt_export} ${loc_export}
-    rbd --cluster ${CLUSTER2} export ${pool}/${image} ${rmt_export}
-    rbd --cluster ${CLUSTER1} export ${pool}/${image} ${loc_export}
+    rbd --cluster ${cluster} export ${remote_pool}/${image} ${rmt_export}
+    rbd --cluster ${local_cluster} export ${local_pool}/${image} ${loc_export}
     if ! cmp ${rmt_export} ${loc_export}
     then
         show_diff ${rmt_export} ${loc_export}
index baf0c9f1a8f8fa98a2604d290a2c316421ab0d46..b0a85e8a48a5547a81692981d0cd39a4ddd5f2c6 100755 (executable)
@@ -111,7 +111,7 @@ do
   snap_name="snap${i}"
   create_snap ${CLUSTER2} ${POOL} ${image} ${snap_name}
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   wait_for_snap_present ${CLUSTER1} ${POOL} ${image} ${snap_name}
 
   if [ -n "${clean_snap_name}" ]; then
@@ -124,7 +124,7 @@ do
 done
 
 wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
 wait_for_snap_present ${CLUSTER1} ${POOL} ${image} ${clean_snap_name}
 
 for i in `seq 1 10`
@@ -173,7 +173,7 @@ do
   image="image_${i}"
   create_snap ${CLUSTER2} ${POOL} ${image} ${snap_name}
   wait_for_image_replay_started ${CLUSTER1} ${POOL} ${image}
-  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${image}
+  wait_for_replay_complete ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
   wait_for_snap_present ${CLUSTER1} ${POOL} ${image} ${snap_name}
   compare_image_snaps ${POOL} ${image} ${snap_name}
 done
index b84630e14860bc761b4cc2329eddc04c28a7f1f3..d0d6bd118404270f207b43c502cc6c591e09d89e 100644 (file)
@@ -4624,6 +4624,7 @@ static const std::string STATUS_GLOBAL_KEY_PREFIX("status_global_");
 static const std::string REMOTE_STATUS_GLOBAL_KEY_PREFIX("remote_status_global_");
 static const std::string INSTANCE_KEY_PREFIX("instance_");
 static const std::string MIRROR_IMAGE_MAP_KEY_PREFIX("image_map_");
+static const std::string REMOTE_NAMESPACE("remote_namespace");
 
 std::string peer_key(const std::string &uuid) {
   return PEER_KEY_PREFIX + uuid;
@@ -5920,6 +5921,56 @@ int mirror_mode_set(cls_method_context_t hctx, bufferlist *in,
     if (r < 0) {
       return r;
     }
+
+    r = remove_key(hctx, mirror::REMOTE_NAMESPACE);
+    if (r < 0) {
+      return r;
+    }
+  }
+  return 0;
+}
+
+int mirror_remote_namespace_get(cls_method_context_t hctx, bufferlist *in,
+                                bufferlist *out) {
+  std::string mirror_ns_decode;
+  int r = read_key(hctx, mirror::REMOTE_NAMESPACE, &mirror_ns_decode);
+  if (r < 0) {
+    CLS_ERR("error getting mirror remote namespace: %s",
+            cpp_strerror(r).c_str());
+    return r;
+  }
+
+  encode(mirror_ns_decode, *out);
+  return 0;
+}
+
+int mirror_remote_namespace_set(cls_method_context_t hctx, bufferlist *in,
+                                bufferlist *out) {
+  std::string mirror_namespace;
+  try {
+    auto bl_it = in->cbegin();
+    decode(mirror_namespace, bl_it);
+  } catch (const ceph::buffer::error &err) {
+    return -EINVAL;
+  }
+
+  uint32_t mirror_mode;
+  int r = read_key(hctx, mirror::MODE, &mirror_mode);
+  if (r < 0 && r != -ENOENT) {
+    return r;
+  } else if (r == 0 && mirror_mode != cls::rbd::MIRROR_MODE_DISABLED) {
+    CLS_ERR("cannot set mirror remote namespace while mirroring enabled");
+    return -EINVAL;
+  }
+
+  bufferlist bl;
+  encode(mirror_namespace, bl);
+
+  r = cls_cxx_map_set_val(hctx, mirror::REMOTE_NAMESPACE, &bl);
+  if (r < 0) {
+    CLS_ERR("error setting mirror remote namespace: %s",
+            cpp_strerror(r).c_str());
+    return r;
   }
   return 0;
 }
@@ -8278,6 +8329,8 @@ CLS_INIT(rbd)
   cls_method_handle_t h_mirror_uuid_set;
   cls_method_handle_t h_mirror_mode_get;
   cls_method_handle_t h_mirror_mode_set;
+  cls_method_handle_t h_mirror_remote_namespace_get;
+  cls_method_handle_t h_mirror_remote_namespace_set;
   cls_method_handle_t h_mirror_peer_ping;
   cls_method_handle_t h_mirror_peer_list;
   cls_method_handle_t h_mirror_peer_add;
@@ -8575,6 +8628,13 @@ CLS_INIT(rbd)
   cls_register_cxx_method(h_class, "mirror_mode_set",
                           CLS_METHOD_RD | CLS_METHOD_WR,
                           mirror_mode_set, &h_mirror_mode_set);
+  cls_register_cxx_method(h_class, "mirror_remote_namespace_get",
+                          CLS_METHOD_RD, mirror_remote_namespace_get,
+                          &h_mirror_remote_namespace_get);
+  cls_register_cxx_method(h_class, "mirror_remote_namespace_set",
+                          CLS_METHOD_RD | CLS_METHOD_WR,
+                          mirror_remote_namespace_set,
+                          &h_mirror_remote_namespace_set);
   cls_register_cxx_method(h_class, "mirror_peer_ping",
                           CLS_METHOD_RD | CLS_METHOD_WR,
                           mirror_peer_ping, &h_mirror_peer_ping);
index ad480c47d5c44613d5f05236079573b9809bd5ac..9dd0c0ece93555475dd70dbff94b63357c17ce04 100644 (file)
@@ -1882,6 +1882,40 @@ int mirror_mode_set(librados::IoCtx *ioctx,
   return 0;
 }
 
+int mirror_remote_namespace_get(librados::IoCtx *ioctx,
+                               std::string *mirror_namespace) {
+  bufferlist in_bl;
+  bufferlist out_bl;
+
+  int r = ioctx->exec(RBD_MIRRORING, "rbd", "mirror_remote_namespace_get",
+                      in_bl, out_bl);
+  if (r < 0) {
+    return r;
+  }
+
+  auto it = out_bl.cbegin();
+  try {
+    decode(*mirror_namespace, it);
+  } catch (const ceph::buffer::error &err) {
+    return -EBADMSG;
+  }
+  return 0;
+}
+
+int mirror_remote_namespace_set(librados::IoCtx *ioctx,
+                                const std::string &mirror_namespace) {
+  bufferlist in_bl;
+  encode(mirror_namespace, in_bl);
+
+  bufferlist out_bl;
+  int r = ioctx->exec(RBD_MIRRORING, "rbd", "mirror_remote_namespace_set",
+                      in_bl, out_bl);
+  if (r < 0) {
+    return r;
+  }
+  return 0;
+}
+
 void mirror_peer_list_start(librados::ObjectReadOperation *op) {
   bufferlist bl;
   op->exec("rbd", "mirror_peer_list", bl);
index 4005c51836c73a039ad3fd57882ea6867f337265..5893eaf859de6130f73f46acf012386fa5bd9b41 100644 (file)
@@ -389,6 +389,11 @@ int mirror_mode_get(librados::IoCtx *ioctx,
 int mirror_mode_set(librados::IoCtx *ioctx,
                     cls::rbd::MirrorMode mirror_mode);
 
+int mirror_remote_namespace_get(librados::IoCtx *ioctx,
+                               std::string *mirror_namespace);
+int mirror_remote_namespace_set(librados::IoCtx *ioctx,
+                               const std::string &mirror_namespace);
+
 int mirror_peer_ping(librados::IoCtx *ioctx,
                      const std::string& site_name,
                      const std::string& fsid);
index f9af9262b2aa3bdcf09e183012de62caf8872939..7144e2038c1ca3501144ae4dae6c03015dbb56ff 100644 (file)
@@ -577,6 +577,16 @@ CEPH_RBD_API int rbd_mirror_mode_get(rados_ioctx_t io_ctx,
                                      rbd_mirror_mode_t *mirror_mode);
 CEPH_RBD_API int rbd_mirror_mode_set(rados_ioctx_t io_ctx,
                                      rbd_mirror_mode_t mirror_mode);
+CEPH_RBD_API int rbd_mirror_remote_namespace_get(rados_ioctx_t io_ctx,
+                                                 char *remote_namespace,
+                                                size_t *max_len);
+/**
+ * The value can be set only if mirroring on io_ctx is disabled. The previously
+ * set value will be automatically reset to io_ctx's namespace when mirroring on
+ * io_ctx is disabled.
+ */
+CEPH_RBD_API int rbd_mirror_remote_namespace_set(rados_ioctx_t io_ctx,
+                                                 const char *remote_namespace);
 
 CEPH_RBD_API int rbd_mirror_uuid_get(rados_ioctx_t io_ctx,
                                      char *uuid, size_t *max_len);
index 50a6c623d3a00c7e6e21175e28707e3b20c5561e..5d64943fe56e5cb114df81648c478836a0fecf3c 100644 (file)
@@ -357,6 +357,16 @@ public:
   int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode);
   int mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode);
 
+  int mirror_remote_namespace_get(IoCtx& io_ctx,
+                                  std::string* remote_namespace);
+
+  /**
+   * The value can be set only if mirroring on io_ctx is disabled. The
+   * previously set value will be automatically reset to io_ctx's namespace when
+   * mirroring on io_ctx is disabled.
+   */
+  int mirror_remote_namespace_set(IoCtx& io_ctx,
+                                  const std::string& remote_namespace);
   int mirror_uuid_get(IoCtx& io_ctx, std::string* mirror_uuid);
 
   int mirror_peer_bootstrap_create(IoCtx& io_ctx, std::string* token);
index 2cfad0d32753220c276dba1a1ecec72d99a811c8..06a5e836fafc7b672d1332edf9ebbb9718895601 100644 (file)
@@ -1115,9 +1115,8 @@ int Mirror<I>::mode_set(librados::IoCtx& io_ctx,
                << dendl;
     return r;
   }
-
   if (current_mirror_mode == next_mirror_mode) {
-    return 0;
+    return 0; // Nothing more to be done
   } else if (current_mirror_mode == cls::rbd::MIRROR_MODE_DISABLED) {
     uuid_d uuid_gen;
     uuid_gen.generate_random();
@@ -1271,6 +1270,55 @@ int Mirror<I>::mode_set(librados::IoCtx& io_ctx,
   return 0;
 }
 
+template <typename I>
+int Mirror<I>::remote_namespace_get(librados::IoCtx& io_ctx,
+                                    std::string* remote_namespace) {
+
+  CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+  ldout(cct, 20) << dendl;
+
+  int r = cls_client::mirror_remote_namespace_get(&io_ctx, remote_namespace);
+  if (r < 0) {
+    if (r != -ENOENT && r != -EOPNOTSUPP) {
+      lderr(cct) << "failed to retrieve remote mirror namespace: "
+                 << cpp_strerror(r) << dendl;
+      return r;
+    }
+    *remote_namespace = io_ctx.get_namespace();
+  }
+  return 0;
+}
+
+
+template <typename I>
+int Mirror<I>::remote_namespace_set(librados::IoCtx& io_ctx,
+                                    const std::string& remote_namespace) {
+  CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+  ldout(cct, 20) << dendl;
+  
+  std::string local_namespace = io_ctx.get_namespace();
+
+  if (local_namespace.empty() && !remote_namespace.empty()) {
+    lderr(cct) << "cannot mirror the default namespace to a "
+               << "non-default namespace." << dendl;
+    return -EINVAL;
+  }
+
+  if (!local_namespace.empty() && remote_namespace.empty()) {
+    lderr(cct) << "cannot mirror a non-default namespace to the default "
+               << "namespace." << dendl;
+    return -EINVAL;
+  }
+
+  int r = cls_client::mirror_remote_namespace_set(&io_ctx, remote_namespace);
+  if (r < 0) {
+    lderr(cct) << "failed to set remote mirror namespace: "
+               << cpp_strerror(r) << dendl;
+    return r;
+  } 
+  return 0;
+}
+
 template <typename I>
 int Mirror<I>::uuid_get(librados::IoCtx& io_ctx, std::string* mirror_uuid) {
   CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
index b3a552b13b7eee2f0495fce390e37f1816d59fde..6e84247b67846ad68e9f8d983ee57d12bdb6fd37 100644 (file)
@@ -31,6 +31,11 @@ struct Mirror {
   static int mode_get(librados::IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode);
   static int mode_set(librados::IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode);
 
+  static int remote_namespace_get(librados::IoCtx& io_ctx,
+                                  std::string* remote_namespace);
+  static int remote_namespace_set(librados::IoCtx& io_ctx,
+                                  const std::string& remote_namespace);
+
   static int uuid_get(librados::IoCtx& io_ctx, std::string* mirror_uuid);
   static void uuid_get(librados::IoCtx& io_ctx, std::string* mirror_uuid,
                        Context* on_finish);
index ed8ec9e913057703a769cf88406b863b9daf60d9..8e2182dcd0187c5fe3f4d5e855f44867f2626097 100644 (file)
@@ -1101,6 +1101,18 @@ namespace librbd {
     return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
   }
 
+  int RBD::mirror_remote_namespace_get(IoCtx& io_ctx,
+                                       std::string* remote_namespace) {
+    return librbd::api::Mirror<>::remote_namespace_get(io_ctx,
+                                                       remote_namespace);
+  }
+
+  int RBD::mirror_remote_namespace_set(IoCtx& io_ctx,
+                                       const std::string& remote_namespace) {
+    return librbd::api::Mirror<>::remote_namespace_set(io_ctx,
+                                                       remote_namespace);
+  }
+
   int RBD::mirror_uuid_get(IoCtx& io_ctx, std::string* mirror_uuid) {
     return librbd::api::Mirror<>::uuid_get(io_ctx, mirror_uuid);
   }
@@ -3395,6 +3407,37 @@ extern "C" int rbd_mirror_mode_set(rados_ioctx_t p,
   return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
 }
 
+extern "C" int rbd_mirror_remote_namespace_get(rados_ioctx_t p,
+                                               char *remote_namespace,
+                                               size_t *max_len) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+
+  std::string remote_namespace_str;
+  int r = librbd::api::Mirror<>::remote_namespace_get(io_ctx,
+                                                      &remote_namespace_str);
+  if (r < 0) {
+    return r;
+  }
+
+  auto total_len = remote_namespace_str.size() + 1;
+  if (*max_len < total_len) {
+    *max_len = total_len;
+    return -ERANGE;
+  }
+  *max_len = total_len;
+
+  strcpy(remote_namespace, remote_namespace_str.c_str());
+  return 0;
+}
+
+extern "C" int rbd_mirror_remote_namespace_set(rados_ioctx_t p,
+                                               const char *remote_namespace) {
+  librados::IoCtx io_ctx;
+  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+  return librbd::api::Mirror<>::remote_namespace_set(io_ctx, remote_namespace);
+}
+
 extern "C" int rbd_mirror_uuid_get(rados_ioctx_t p,
                                    char *mirror_uuid, size_t *max_len) {
   librados::IoCtx io_ctx;
index 3a960a2a885eb2971c521ea14f0d7c155cb631a6..2c2dd42fd78e2d36f89794448b25317184f00e28 100644 (file)
@@ -394,6 +394,12 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
     int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
 
+    int rbd_mirror_remote_namespace_get(rados_ioctx_t io_ctx,
+                                        char *remote_namespace,
+                                        size_t *max_len)
+    int rbd_mirror_remote_namespace_set(rados_ioctx_t io_ctx,
+                                        const char *remote_namespace)
+
     int rbd_mirror_uuid_get(rados_ioctx_t io_ctx, char *mirror_uuid,
                             size_t *max_len)
 
index 40280dc9c0d9c3c921c97b9ff76a020e91320e8e..53a161d9a3bfccfd071ded59b011fae7cfe1821b 100644 (file)
@@ -437,6 +437,14 @@ cdef nogil:
     int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode):
         pass
 
+    int rbd_mirror_remote_namespace_get(rados_ioctx_t io_ctx,
+                                        char *remote_namespace,
+                                        size_t *max_len):
+        pass
+    int rbd_mirror_remote_namespace_set(rados_ioctx_t io_ctx,
+                                        const char *remote_namespace):
+        pass
+
     int rbd_mirror_uuid_get(rados_ioctx_t io_ctx, char *mirror_uuid,
                             size_t *max_len):
         pass
index 5290e48832d14d8177e49bf9ba28ceb9577521bb..66604db1ffba7899c4f705577233f2e7798152a5 100644 (file)
@@ -1330,6 +1330,52 @@ class RBD(object):
         if ret != 0:
             raise make_ex(ret, 'error setting mirror mode')
 
+    def mirror_remote_namespace_get(self, ioctx):
+        """
+        Get mirror remote namespace
+
+        :param ioctx: determines which RADOS pool is read
+        :type ioctx: :class:`rados.Ioctx`
+        :returns: str - mirror remote namespace
+        """
+        cdef:
+            rados_ioctx_t _ioctx = convert_ioctx(ioctx)
+            char *_remote_namespace = NULL
+            size_t _max_size = 512
+        try:
+            while True:
+                _remote_namespace = <char *>realloc_chk(_remote_namespace,
+                                                        _max_size)
+                with nogil:
+                    ret = rbd_mirror_remote_namespace_get(_ioctx,
+                                                          _remote_namespace,
+                                                          &_max_size)
+                if ret >= 0:
+                    break
+                elif ret != -errno.ERANGE:
+                    raise make_ex(ret, 'error retrieving remote namespace')
+            return decode_cstr(_remote_namespace)
+        finally:
+            free(_remote_namespace)
+
+    def mirror_remote_namespace_set(self, ioctx, remote_namespace):
+        """
+        Set mirror remote namespace
+
+        :param ioctx: determines which RADOS pool is written
+        :type ioctx: :class:`rados.Ioctx`
+        :param remote_namespace: the remote cluster namespace to mirror to
+        :type str:
+        """
+        remote_namespace = cstr(remote_namespace, 'remote_namespace')
+        cdef:
+            rados_ioctx_t _ioctx = convert_ioctx(ioctx)
+            char *_remote_namespace = remote_namespace
+        with nogil:
+            ret = rbd_mirror_remote_namespace_set(_ioctx, _remote_namespace)
+        if ret != 0:
+            raise make_ex(ret, 'error setting remote namespace')
+
     def mirror_uuid_get(self, ioctx):
         """
         Get pool mirror uuid
index ff25b5973a400db01efce719b6383e208fb3467a..cd25e7428e21d1abbd9f73f6ff12a3db8ad35903 100644 (file)
   rbd help mirror pool enable
   usage: rbd mirror pool enable [--pool <pool>] [--namespace <namespace>] 
                                 [--site-name <site-name>] 
+                                [--remote-namespace <remote-namespace>] 
                                 <pool-spec> <mode> 
   
   Enable RBD mirroring in a pool or namespace.
   
   Positional arguments
-    <pool-spec>          pool specification
-                         (example: <pool-name>[/<namespace>]
-    <mode>               mirror mode [image or pool]
+    <pool-spec>            pool specification
+                           (example: <pool-name>[/<namespace>]
+    <mode>                 mirror mode [image or pool]
   
   Optional arguments
-    -p [ --pool ] arg    pool name
-    --namespace arg      namespace name
-    --site-name arg      local site name
+    -p [ --pool ] arg      pool name
+    --namespace arg        namespace name
+    --site-name arg        local site name
+    --remote-namespace arg remote namespace name
   
   rbd help mirror pool info
   usage: rbd mirror pool info [--pool <pool>] [--namespace <namespace>] 
     --image arg          image name
   
 
+
index 9093b5355d5114e21da70114e5cd8a51fa154998..7eb03cc42f5422c32ace0d0e808bd26daf7fb966 100644 (file)
@@ -1606,7 +1606,9 @@ TEST_F(TestClsRbd, mirror) {
   ASSERT_EQ(-ENOENT, mirror_peer_list(&ioctx, &peers));
 
   std::string uuid;
+  std::string remote_ns;
   ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
+  ASSERT_EQ(-ENOENT, mirror_remote_namespace_get(&ioctx, &remote_ns));
   ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_RX,
                                               "siteA", "client",
                                               "mirror uuid"}));
@@ -1622,11 +1624,16 @@ TEST_F(TestClsRbd, mirror) {
   ASSERT_EQ(0, mirror_uuid_get(&ioctx, &uuid));
   ASSERT_EQ("mirror-uuid", uuid);
 
+  ASSERT_EQ(0, mirror_remote_namespace_set(&ioctx, "remote-ns"));
+  ASSERT_EQ(0, mirror_remote_namespace_get(&ioctx, &remote_ns));
+  ASSERT_EQ("remote-ns", remote_ns);
+
   ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_IMAGE));
   ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
   ASSERT_EQ(cls::rbd::MIRROR_MODE_IMAGE, mirror_mode);
 
   ASSERT_EQ(-EINVAL, mirror_uuid_set(&ioctx, "new-mirror-uuid"));
+  ASSERT_EQ(-EINVAL, mirror_remote_namespace_set(&ioctx, "new-remote-ns"));
 
   ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_POOL));
   ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
@@ -1726,6 +1733,7 @@ TEST_F(TestClsRbd, mirror) {
   ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
   ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED, mirror_mode);
   ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
+  ASSERT_EQ(-ENOENT, mirror_remote_namespace_get(&ioctx, &remote_ns));
 }
 
 TEST_F(TestClsRbd, mirror_image) {
index 9e307cbb9bf1ed0c339a53e22ee145534a0b4eba..5f35521d6f44f142504aa27ba540e02e5ff5222a 100644 (file)
@@ -2391,6 +2391,27 @@ class TestMirroring(object):
         self.rbd.mirror_site_name_set(rados, "")
         eq(rados.get_fsid(), self.rbd.mirror_site_name_get(rados))
 
+    def test_mirror_remote_namespace(self):
+        remote_namespace = "remote-ns"
+        # cannot set remote namespace for the default namespace
+        assert_raises(InvalidArgument, self.rbd.mirror_remote_namespace_set,
+                      ioctx, remote_namespace)
+        eq("", self.rbd.mirror_remote_namespace_get(ioctx))
+        self.rbd.namespace_create(ioctx, "ns1")
+        ioctx.set_namespace("ns1")
+        self.rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_IMAGE)
+        # cannot set remote namespace while mirroring enabled
+        assert_raises(InvalidArgument, self.rbd.mirror_remote_namespace_set,
+                      ioctx, remote_namespace)
+        self.rbd.mirror_mode_set(ioctx, RBD_MIRROR_MODE_DISABLED)
+        # cannot set remote namespace to the default namespace
+        assert_raises(InvalidArgument, self.rbd.mirror_remote_namespace_set,
+                      ioctx, "")
+        self.rbd.mirror_remote_namespace_set(ioctx, remote_namespace)
+        eq(remote_namespace, self.rbd.mirror_remote_namespace_get(ioctx))
+        ioctx.set_namespace("")
+        self.rbd.namespace_remove(ioctx, "ns1")
+
     def test_mirror_peer_bootstrap(self):
         eq([], list(self.rbd.mirror_peer_list(ioctx)))
 
index ece1a339611559754ba8cb6e5fdbba1c5022f95b..52aefa90a8b7b2c25216d2efd1eb22405c91485d 100644 (file)
@@ -409,7 +409,7 @@ TEST_F(TestMockNamespaceReplayer, Init_LocalMirrorStatusUpdaterError) {
   expect_mirror_status_updater_init(*mock_local_mirror_status_updater, -EINVAL);
 
   MockNamespaceReplayer namespace_replayer(
-      {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
+      {}, {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "local peer uuid", {"remote mirror uuid", ""}, m_mock_threads,
       nullptr, nullptr, nullptr, nullptr, nullptr);
 
@@ -432,7 +432,7 @@ TEST_F(TestMockNamespaceReplayer, Init_RemoteMirrorStatusUpdaterError) {
   expect_mirror_status_updater_shut_down(*mock_local_mirror_status_updater);
 
   MockNamespaceReplayer namespace_replayer(
-      {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
+      {}, {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "local peer uuid", {"remote mirror uuid", ""}, m_mock_threads,
       nullptr, nullptr, nullptr, nullptr, nullptr);
 
@@ -458,7 +458,7 @@ TEST_F(TestMockNamespaceReplayer, Init_InstanceReplayerError) {
   expect_mirror_status_updater_shut_down(*mock_local_mirror_status_updater);
 
   MockNamespaceReplayer namespace_replayer(
-      {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
+      {}, {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "local peer uuid", {"remote mirror uuid", ""}, m_mock_threads,
       nullptr, nullptr, nullptr, nullptr, nullptr);
 
@@ -489,7 +489,7 @@ TEST_F(TestMockNamespaceReplayer, Init_InstanceWatcherError) {
   expect_mirror_status_updater_shut_down(*mock_local_mirror_status_updater);
 
   MockNamespaceReplayer namespace_replayer(
-      {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
+      {}, {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "local peer uuid", {"remote mirror uuid", ""}, m_mock_threads,
       nullptr, nullptr, nullptr, nullptr, nullptr);
 
@@ -517,7 +517,7 @@ TEST_F(TestMockNamespaceReplayer, Init) {
 
   MockServiceDaemon mock_service_daemon;
   MockNamespaceReplayer namespace_replayer(
-      {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
+      {}, {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "local peer uuid", {"remote mirror uuid", ""}, m_mock_threads,
       nullptr, nullptr, &mock_service_daemon, nullptr, nullptr);
 
@@ -557,7 +557,7 @@ TEST_F(TestMockNamespaceReplayer, AcquireLeader) {
 
   MockServiceDaemon mock_service_daemon;
   MockNamespaceReplayer namespace_replayer(
-      {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
+      {}, {}, m_local_io_ctx, m_remote_io_ctx, "local mirror uuid",
       "local peer uuid", {"remote mirror uuid", ""}, m_mock_threads,
       nullptr, nullptr, &mock_service_daemon, nullptr, nullptr);
 
index 69fe799314810327ae010cc3ad38bd9fede606f2..ec5d40f8705d30a634d015163912d0ae5f82bc53 100644 (file)
@@ -129,7 +129,8 @@ struct NamespaceReplayer<librbd::MockTestImageCtx> {
   static std::map<std::string, NamespaceReplayer *> s_instances;
 
   static NamespaceReplayer *create(
-      const std::string &name,
+      const std::string &local_name,
+      const std::string &remote_name,
       librados::IoCtx &local_ioctx,
       librados::IoCtx &remote_ioctx,
       const std::string &local_mirror_uuid,
@@ -141,14 +142,15 @@ struct NamespaceReplayer<librbd::MockTestImageCtx> {
       ServiceDaemon<librbd::MockTestImageCtx> *service_daemon,
       journal::CacheManagerHandler *cache_manager_handler,
       PoolMetaCache* pool_meta_cache) {
-    ceph_assert(s_instances.count(name));
-    auto namespace_replayer = s_instances[name];
-    s_instances.erase(name);
+    ceph_assert(s_instances.count(local_name));
+    auto namespace_replayer = s_instances[local_name];
+    s_instances.erase(local_name);
     return namespace_replayer;
   }
 
   MOCK_METHOD0(is_blocklisted, bool());
   MOCK_METHOD0(get_instance_id, std::string());
+  MOCK_METHOD0(get_remote_namespace, std::string());
 
   MOCK_METHOD1(init, void(Context*));
   MOCK_METHOD1(shut_down, void(Context*));
@@ -363,6 +365,18 @@ public:
           Return(0)));
   }
 
+  void expect_mirror_remote_namespace_get(
+      librados::MockTestMemIoCtxImpl *io_ctx_impl,
+      const std::string &remote_namespace, int r) {
+    EXPECT_CALL(*io_ctx_impl,
+                exec(RBD_MIRRORING, _, StrEq("rbd"),
+                     StrEq("mirror_remote_namespace_get"), _, _, _, _))
+      .WillRepeatedly(DoAll(WithArg<5>(Invoke([remote_namespace](bufferlist *bl) {
+                encode(remote_namespace, *bl);
+              })),
+          Return(r)));
+  }
+
   void expect_clone(librados::MockTestMemIoCtxImpl* mock_io_ctx) {
     EXPECT_CALL(*mock_io_ctx, clone())
       .WillRepeatedly(Invoke([mock_io_ctx]() {
@@ -510,6 +524,13 @@ public:
     EXPECT_CALL(mock_namespace_replayer, handle_instances_removed(_));
   }
 
+  void expect_namespace_replayer_get_remote_namespace(
+      MockNamespaceReplayer &mock_namespace_replayer,
+      const std::string& remote_namespace) {
+    EXPECT_CALL(mock_namespace_replayer, get_remote_namespace())
+      .WillRepeatedly(Return(remote_namespace));
+  }
+
   void expect_service_daemon_add_namespace(
       MockServiceDaemon &mock_service_daemon,
       const std::string& namespace_name) {
@@ -714,10 +735,14 @@ TEST_F(TestMockPoolReplayer, Namespaces) {
   auto mock_ns1_namespace_replayer = new MockNamespaceReplayer("ns1");
   expect_namespace_replayer_is_blocklisted(*mock_ns1_namespace_replayer,
                                            false);
+  expect_namespace_replayer_get_remote_namespace(*mock_ns1_namespace_replayer,
+                                                 "ns1");
 
   auto mock_ns2_namespace_replayer = new MockNamespaceReplayer("ns2");
   expect_namespace_replayer_is_blocklisted(*mock_ns2_namespace_replayer,
                                            false);
+  expect_namespace_replayer_get_remote_namespace(*mock_ns2_namespace_replayer,
+                                                 "ns2");
 
   MockThreads mock_threads(m_threads);
   expect_work_queue(mock_threads);
@@ -737,6 +762,7 @@ TEST_F(TestMockPoolReplayer, Namespaces) {
 
   expect_clone(mock_local_io_ctx);
   expect_mirror_mode_get(mock_local_io_ctx);
+  expect_mirror_remote_namespace_get(mock_local_io_ctx, "", -ENOENT);
 
   InSequence seq;
 
@@ -856,6 +882,7 @@ TEST_F(TestMockPoolReplayer, NamespacesError) {
 
   expect_clone(mock_local_io_ctx);
   expect_mirror_mode_get(mock_local_io_ctx);
+  expect_mirror_remote_namespace_get(mock_local_io_ctx, "", -ENOENT);
 
   InSequence seq;
 
index a7877870a04aee47c7a5451f7e01a4cee7b14e09..88e578cba9196cb7d6d568d6b1eefda9d989e48f 100644 (file)
@@ -41,6 +41,7 @@ namespace po = boost::program_options;
 
 static const std::string ALL_NAME("all");
 static const std::string SITE_NAME("site-name");
+static const std::string REMOTE_NAMESPACE_NAME("remote-namespace");
 
 namespace {
 
@@ -1242,6 +1243,10 @@ void get_enable_arguments(po::options_description *positional,
   positional->add_options()
     ("mode", "mirror mode [image or pool]");
   add_site_name_optional(options);
+
+  options->add_options()
+    (REMOTE_NAMESPACE_NAME.c_str(), po::value<std::string>(),
+     "remote namespace name");
 }
 
 int execute_enable_disable(librados::IoCtx& io_ctx,
@@ -1310,6 +1315,7 @@ int execute_enable(const po::variables_map &vm,
                    const std::vector<std::string> &ceph_global_init_args) {
   std::string pool_name;
   std::string namespace_name;
+  std::string remote_namespace;
   size_t arg_index = 0;
   int r = utils::get_pool_and_namespace_names(vm, true, &pool_name,
                                               &namespace_name, &arg_index);
@@ -1336,15 +1342,36 @@ int execute_enable(const po::variables_map &vm,
     return r;
   }
 
+  if (vm.count(REMOTE_NAMESPACE_NAME)) {
+    remote_namespace = vm[REMOTE_NAMESPACE_NAME].as<std::string>();
+  } else {
+    remote_namespace = namespace_name;
+  }
+
+  std::string original_remote_namespace;
+  librbd::RBD rbd;
+  r = rbd.mirror_remote_namespace_get(io_ctx, &original_remote_namespace);
+  if (r < 0) {
+    std::cerr << "rbd: failed to get the current remote namespace."
+              << std::endl;
+    return r;
+  }
+
+  if (original_remote_namespace != remote_namespace) {
+    r = rbd.mirror_remote_namespace_set(io_ctx, remote_namespace);
+    if (r < 0) {
+      std::cerr << "rbd: failed to set the remote namespace."
+                << std::endl;
+      return r;
+    }
+  }
+
   bool updated = false;
   if (vm.count(SITE_NAME)) {
-    librbd::RBD rbd;
-
     auto site_name = vm[SITE_NAME].as<std::string>();
     std::string original_site_name;
     r = rbd.mirror_site_name_get(rados, &original_site_name);
     updated = (r >= 0 && site_name != original_site_name);
-
     r = set_site_name(rados, site_name);
     if (r < 0) {
       return r;
@@ -1366,6 +1393,8 @@ int execute_info(const po::variables_map &vm,
                  const std::vector<std::string> &ceph_global_init_args) {
   std::string pool_name;
   std::string namespace_name;
+  std::string remote_namespace;
+  std::string mirror_uuid;
   size_t arg_index = 0;
   int r = utils::get_pool_and_namespace_names(vm, false, &pool_name,
                                               &namespace_name, &arg_index);
@@ -1407,6 +1436,13 @@ int execute_info(const po::variables_map &vm,
     }
   }
 
+  if (mirror_mode != RBD_MIRROR_MODE_DISABLED) {
+    r = rbd.mirror_remote_namespace_get(io_ctx, &remote_namespace);
+    if (r < 0) {
+      return r;
+    }
+  }
+
   std::string mirror_mode_desc;
   switch (mirror_mode) {
   case RBD_MIRROR_MODE_DISABLED:
@@ -1430,18 +1466,26 @@ int execute_info(const po::variables_map &vm,
     std::cout << "Mode: " << mirror_mode_desc << std::endl;
   }
 
-  if (mirror_mode != RBD_MIRROR_MODE_DISABLED && namespace_name.empty()) {
+  if (mirror_mode != RBD_MIRROR_MODE_DISABLED) {
+    if (namespace_name.empty()) {
+      if (formatter != nullptr) {
+        formatter->dump_string("site_name", site_name);
+      } else {
+       std::cout << "Site Name: " << site_name << std::endl;
+      }
+    }
     if (formatter != nullptr) {
-      formatter->dump_string("site_name", site_name);
+      formatter->dump_string("remote_namespace", remote_namespace);
     } else {
-      std::cout << "Site Name: " << site_name << std::endl
-                << std::endl;
+      std::cout << "Remote Namespace: " << remote_namespace << std::endl
+               << std::endl;
     }
-
-    r = format_mirror_peers(io_ctx, formatter, mirror_peers,
-                            vm[ALL_NAME].as<bool>());
-    if (r < 0) {
-      return r;
+    if (namespace_name.empty()) {
+      r = format_mirror_peers(io_ctx, formatter, mirror_peers,
+                              vm[ALL_NAME].as<bool>());
+      if (r < 0) {
+       return r;
+      }
     }
   }
   if (formatter != nullptr) {
index d305d8472151a1ccbe638936b081ca49c37cd1cb..3f558e8ddba580beab8f3909a19a966e7eb5e659 100644 (file)
@@ -36,7 +36,8 @@ const std::string SERVICE_DAEMON_REMOTE_COUNT_KEY("image_remote_count");
 
 template <typename I>
 NamespaceReplayer<I>::NamespaceReplayer(
-    const std::string &name,
+    const std::string &local_name,
+    const std::string &remote_name,
     librados::IoCtx &local_io_ctx, librados::IoCtx &remote_io_ctx,
     const std::string &local_mirror_uuid,
     const std::string& local_mirror_peer_uuid,
@@ -47,7 +48,8 @@ NamespaceReplayer<I>::NamespaceReplayer(
     ServiceDaemon<I> *service_daemon,
     journal::CacheManagerHandler *cache_manager_handler,
     PoolMetaCache* pool_meta_cache) :
-  m_namespace_name(name),
+  m_local_namespace_name(local_name),
+  m_remote_namespace_name(remote_name),
   m_local_mirror_uuid(local_mirror_uuid),
   m_local_mirror_peer_uuid(local_mirror_peer_uuid),
   m_remote_pool_meta(remote_pool_meta),
@@ -57,16 +59,19 @@ NamespaceReplayer<I>::NamespaceReplayer(
   m_cache_manager_handler(cache_manager_handler),
   m_pool_meta_cache(pool_meta_cache),
   m_lock(ceph::make_mutex(librbd::util::unique_lock_name(
-      "rbd::mirror::NamespaceReplayer " + name, this))),
+      "rbd::mirror::NamespaceReplayer " + local_name, this))),
   m_local_pool_watcher_listener(this, true),
   m_remote_pool_watcher_listener(this, false),
   m_image_map_listener(this) {
-  dout(10) << name << dendl;
+  dout(10) << "local_name=" << local_name
+           << ", remote_name="  << remote_name
+           << ", local_mirror_uuid=" << m_local_mirror_uuid
+           << dendl;
 
   m_local_io_ctx.dup(local_io_ctx);
-  m_local_io_ctx.set_namespace(name);
+  m_local_io_ctx.set_namespace(local_name);
   m_remote_io_ctx.dup(remote_io_ctx);
-  m_remote_io_ctx.set_namespace(name);
+  m_remote_io_ctx.set_namespace(remote_name);
 }
 
 template <typename I>
@@ -856,6 +861,16 @@ void NamespaceReplayer<I>::handle_remove_image(const std::string &mirror_uuid,
                                                 mirror_uuid, on_finish);
 }
 
+template <typename I>
+std::string NamespaceReplayer<I>::get_local_namespace() {
+  return m_local_namespace_name;
+}
+
+template <typename I>
+std::string NamespaceReplayer<I>::get_remote_namespace() {
+  return m_remote_namespace_name;
+}
+
 } // namespace mirror
 } // namespace rbd
 
index e304b8253f850b36d5e05184f33a8ece9101730a..25b3369de787dae2b31265da93ddaa87239c3055 100644 (file)
@@ -43,7 +43,8 @@ template <typename ImageCtxT = librbd::ImageCtx>
 class NamespaceReplayer {
 public:
   static NamespaceReplayer *create(
-      const std::string &name,
+      const std::string &local_name,
+      const std::string &remote_name,
       librados::IoCtx &local_ioctx,
       librados::IoCtx &remote_ioctx,
       const std::string &local_mirror_uuid,
@@ -55,7 +56,7 @@ public:
       ServiceDaemon<ImageCtxT> *service_daemon,
       journal::CacheManagerHandler *cache_manager_handler,
       PoolMetaCache* pool_meta_cache) {
-    return new NamespaceReplayer(name, local_ioctx, remote_ioctx,
+    return new NamespaceReplayer(local_name, remote_name, local_ioctx, remote_ioctx,
                                  local_mirror_uuid, local_mirror_peer_uuid,
                                  remote_pool_meta, threads,
                                  image_sync_throttler, image_deletion_throttler,
@@ -63,7 +64,8 @@ public:
                                  pool_meta_cache);
   }
 
-  NamespaceReplayer(const std::string &name,
+  NamespaceReplayer(const std::string &local_name,
+                    const std::string &remote_name,
                     librados::IoCtx &local_ioctx,
                     librados::IoCtx &remote_ioctx,
                     const std::string &local_mirror_uuid,
@@ -95,6 +97,9 @@ public:
   void restart();
   void flush();
 
+  std::string get_local_namespace();
+  std::string get_remote_namespace();
+
 private:
   /**
    * @verbatim
@@ -264,7 +269,8 @@ private:
                            const std::string &instance_id,
                            Context* on_finish);
 
-  std::string m_namespace_name;
+  std::string m_local_namespace_name;
+  std::string m_remote_namespace_name;
   librados::IoCtx m_local_io_ctx;
   librados::IoCtx m_remote_io_ctx;
   std::string m_local_mirror_uuid;
index dcbedc67e42350107e61c84d6cd6739a446ace8d..2efb8bae38b4e640695b76e0fc02abca3d81502b 100644 (file)
@@ -369,7 +369,7 @@ void PoolReplayer<I>::init(const std::string& site_name) {
     m_local_io_ctx.get_id(), {m_local_mirror_uuid});
 
   m_default_namespace_replayer.reset(NamespaceReplayer<I>::create(
-      "", m_local_io_ctx, m_remote_io_ctx, m_local_mirror_uuid, m_peer.uuid,
+      "", "", m_local_io_ctx, m_remote_io_ctx, m_local_mirror_uuid, m_peer.uuid,
       m_remote_pool_meta, m_threads, m_image_sync_throttler.get(),
       m_image_deletion_throttler.get(), m_service_daemon,
       m_cache_manager_handler, m_pool_meta_cache));
@@ -638,7 +638,7 @@ void PoolReplayer<I>::update_namespace_replayers() {
 
   ceph_assert(ceph_mutex_is_locked(m_lock));
 
-  std::set<std::string> mirroring_namespaces;
+  std::map<std::string, std::string> mirroring_namespaces;
   if (!m_stopping) {
     int r = list_mirroring_namespaces(&mirroring_namespaces);
     if (r < 0) {
@@ -652,7 +652,8 @@ void PoolReplayer<I>::update_namespace_replayers() {
   for (auto it = m_namespace_replayers.begin();
        it != m_namespace_replayers.end(); ) {
     auto iter = mirroring_namespaces.find(it->first);
-    if (iter == mirroring_namespaces.end()) {
+    if (iter == mirroring_namespaces.end() ||
+        it->second->get_remote_namespace() != iter->second) {
       auto namespace_replayer = it->second;
       auto on_shut_down = new LambdaContext(
         [namespace_replayer, ctx=gather_ctx->new_sub()](int r) {
@@ -668,24 +669,24 @@ void PoolReplayer<I>::update_namespace_replayers() {
     }
   }
 
-  for (auto &name : mirroring_namespaces) {
+  for (auto &names : mirroring_namespaces) {
     auto namespace_replayer = NamespaceReplayer<I>::create(
-        name, m_local_io_ctx, m_remote_io_ctx, m_local_mirror_uuid, m_peer.uuid,
-        m_remote_pool_meta, m_threads, m_image_sync_throttler.get(),
-        m_image_deletion_throttler.get(), m_service_daemon,
-        m_cache_manager_handler, m_pool_meta_cache);
+        names.first, names.second, m_local_io_ctx, m_remote_io_ctx,
+        m_local_mirror_uuid, m_peer.uuid, m_remote_pool_meta, m_threads,
+        m_image_sync_throttler.get(), m_image_deletion_throttler.get(),
+        m_service_daemon, m_cache_manager_handler, m_pool_meta_cache);
     auto on_init = new LambdaContext(
-        [this, namespace_replayer, name, &mirroring_namespaces,
+        [this, namespace_replayer, names, &mirroring_namespaces,
          ctx=gather_ctx->new_sub()](int r) {
           std::lock_guard locker{m_lock};
           if (r < 0) {
             derr << "failed to initialize namespace replayer for namespace "
-                 << name << ": " << cpp_strerror(r) << dendl;
+                 << names.first << ": " << cpp_strerror(r) << dendl;
             delete namespace_replayer;
-            mirroring_namespaces.erase(name);
+            mirroring_namespaces.erase(names.first);
           } else {
-            m_namespace_replayers[name] = namespace_replayer;
-            m_service_daemon->add_namespace(m_local_pool_id, name);
+            m_namespace_replayers[names.first] = namespace_replayer;
+            m_service_daemon->add_namespace(m_local_pool_id, names.first);
           }
           ctx->complete(r);
         });
@@ -702,8 +703,8 @@ void PoolReplayer<I>::update_namespace_replayers() {
     C_SaferCond acquire_cond;
     auto acquire_gather_ctx = new C_Gather(cct, &acquire_cond);
 
-    for (auto &name : mirroring_namespaces) {
-      namespace_replayer_acquire_leader(name, acquire_gather_ctx->new_sub());
+    for (auto &names : mirroring_namespaces) {
+      namespace_replayer_acquire_leader(names.first, acquire_gather_ctx->new_sub());
     }
     acquire_gather_ctx->activate();
 
@@ -714,8 +715,8 @@ void PoolReplayer<I>::update_namespace_replayers() {
     std::vector<std::string> instance_ids;
     m_leader_watcher->list_instances(&instance_ids);
 
-    for (auto &name : mirroring_namespaces) {
-      auto it = m_namespace_replayers.find(name);
+    for (auto &names : mirroring_namespaces) {
+      auto it = m_namespace_replayers.find(names.first);
       if (it == m_namespace_replayers.end()) {
         // acquire leader for this namespace replayer failed
         continue;
@@ -725,8 +726,8 @@ void PoolReplayer<I>::update_namespace_replayers() {
   } else {
     std::string leader_instance_id;
     if (m_leader_watcher->get_leader_instance_id(&leader_instance_id)) {
-      for (auto &name : mirroring_namespaces) {
-        m_namespace_replayers[name]->handle_update_leader(leader_instance_id);
+      for (auto &names : mirroring_namespaces) {
+        m_namespace_replayers[names.first]->handle_update_leader(leader_instance_id);
       }
     }
   }
@@ -734,7 +735,7 @@ void PoolReplayer<I>::update_namespace_replayers() {
 
 template <typename I>
 int PoolReplayer<I>::list_mirroring_namespaces(
-    std::set<std::string> *namespaces) {
+    std::map<std::string, std::string> *namespaces) {
   dout(20) << dendl;
   ceph_assert(ceph_mutex_is_locked(m_lock));
 
@@ -751,6 +752,7 @@ int PoolReplayer<I>::list_mirroring_namespaces(
     ns_ioctx.dup(m_local_io_ctx);
     ns_ioctx.set_namespace(name);
 
+    std::string remote_namespace;
     cls::rbd::MirrorMode mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
     int r = librbd::cls_client::mirror_mode_get(&ns_ioctx, &mirror_mode);
     if (r < 0 && r != -ENOENT) {
@@ -763,8 +765,21 @@ int PoolReplayer<I>::list_mirroring_namespaces(
       dout(10) << "mirroring is disabled for namespace " << name << dendl;
       continue;
     }
-
-    namespaces->insert(name);
+    r = librbd::cls_client::mirror_remote_namespace_get(&ns_ioctx,
+                                                        &remote_namespace);
+    if (r < 0) { 
+      if (r != -ENOENT && r != -EOPNOTSUPP) {
+       derr << "failed to get remote mirror namespace: " << cpp_strerror(r)
+            << dendl;
+       continue;
+      } else {
+        remote_namespace = name;
+      }
+    }
+    dout(10) << " local namespace=" << name << ", remote namespace="
+             << remote_namespace << dendl;
+    namespaces->insert(std::make_pair(name, remote_namespace));
   }
 
   return 0;
index e0fd753778d92c449cab3afd3f58aa95f1e9843a..4635f1ae6bac27d93c856d9fefec065139f0b174 100644 (file)
@@ -107,7 +107,7 @@ private:
                  bool strip_cluster_overrides);
 
   void update_namespace_replayers();
-  int list_mirroring_namespaces(std::set<std::string> *namespaces);
+  int list_mirroring_namespaces(std::map<std::string, std::string> *namespaces);
 
   void namespace_replayer_acquire_leader(const std::string &name,
                                          Context *on_finish);