mirror of
https://github.com/ceph/ceph
synced 2025-04-01 14:51:13 +00:00
rbd-mirror: allow mirroring to a different namespace
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>
This commit is contained in:
parent
a71318b738
commit
3fdbc160bb
@ -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*
|
||||
|
@ -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}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1832,19 +1832,21 @@
|
||||
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>]
|
||||
@ -2712,3 +2714,4 @@
|
||||
--image arg image name
|
||||
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)))
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 (formatter != nullptr) {
|
||||
formatter->dump_string("site_name", site_name);
|
||||
} else {
|
||||
std::cout << "Site Name: " << site_name << std::endl
|
||||
<< std::endl;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
r = format_mirror_peers(io_ctx, formatter, mirror_peers,
|
||||
vm[ALL_NAME].as<bool>());
|
||||
if (r < 0) {
|
||||
return r;
|
||||
if (formatter != nullptr) {
|
||||
formatter->dump_string("remote_namespace", remote_namespace);
|
||||
} else {
|
||||
std::cout << "Remote Namespace: " << remote_namespace << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user