: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.
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*
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"
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"
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"
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}
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}
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}
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
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}
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
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'
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"
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"
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"
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
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}
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}
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"
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"
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"
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
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})"
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
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}
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"
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"
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)"
wait_for_status_in_pool_dir ${CLUSTER2} ${POOL} ${image} \
'down+unknown'
fi
- compare_images ${POOL} ${image}
+ compare_images ${CLUSTER1} ${CLUSTER2} ${POOL} ${POOL} ${image}
done
}
{
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
{
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
{
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
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}
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
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`
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
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;
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;
}
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;
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);
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);
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);
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);
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);
<< 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();
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());
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);
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);
}
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;
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)
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
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
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
+
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"}));
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));
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) {
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)))
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);
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);
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);
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);
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);
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);
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,
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*));
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]() {
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) {
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);
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;
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;
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 {
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,
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);
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;
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);
}
}
+ 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:
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) {
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,
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),
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>
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
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,
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,
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,
void restart();
void flush();
+ std::string get_local_namespace();
+ std::string get_remote_namespace();
+
private:
/**
* @verbatim
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;
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));
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) {
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) {
}
}
- 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);
});
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();
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;
} 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);
}
}
}
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));
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) {
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;
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);