diff options
Diffstat (limited to 'qa/workunits/rbd/cli_migration.sh')
-rwxr-xr-x | qa/workunits/rbd/cli_migration.sh | 340 |
1 files changed, 307 insertions, 33 deletions
diff --git a/qa/workunits/rbd/cli_migration.sh b/qa/workunits/rbd/cli_migration.sh index be8e031fd1b..3af19420957 100755 --- a/qa/workunits/rbd/cli_migration.sh +++ b/qa/workunits/rbd/cli_migration.sh @@ -1,17 +1,20 @@ #!/usr/bin/env bash set -ex -. $(dirname $0)/../../standalone/ceph-helpers.sh - TEMPDIR= IMAGE1=image1 IMAGE2=image2 IMAGE3=image3 -IMAGES="${IMAGE1} ${IMAGE2} ${IMAGE3}" +NAMESPACE1=namespace1 +NAMESPACE2=namespace2 +NAMESPACES="${NAMESPACE1} ${NAMESPACE2}" +IMAGES="${IMAGE1} ${IMAGE2} ${IMAGE3} rbd/${NAMESPACE1}/${IMAGE1} rbd/${NAMESPACE2}/${IMAGE2}" cleanup() { + kill_nbd_server cleanup_tempdir remove_images + remove_namespaces } setup_tempdir() { @@ -22,10 +25,17 @@ cleanup_tempdir() { rm -rf ${TEMPDIR} } +expect_false() { + if "$@"; then return 1; else return 0; fi +} + create_base_image() { local image=$1 - rbd create --size 1G ${image} + # size is not a multiple of object size to trigger an edge case in + # list-snaps + rbd create --size 1025M ${image} + rbd bench --io-type write --io-pattern rand --io-size=4K --io-total 256M ${image} rbd snap create ${image}@1 rbd bench --io-type write --io-pattern rand --io-size=4K --io-total 64M ${image} @@ -36,8 +46,11 @@ create_base_image() { export_raw_image() { local image=$1 - rm -rf "${TEMPDIR}/${image}" - rbd export ${image} "${TEMPDIR}/${image}" + # Replace slashes (/) with underscores (_) for namespace images + local export_image="${image//\//_}" + + rm -rf "${TEMPDIR}/${export_image}" + rbd export "${image}" "${TEMPDIR}/${export_image}" } export_base_image() { @@ -63,6 +76,17 @@ remove_images() { done } +remove_namespaces() { + for namespace in ${NAMESPACES} + do + rbd namespace remove rbd/${namespace} || true + done +} + +kill_nbd_server() { + pkill -9 qemu-nbd || true +} + show_diff() { local file1=$1 @@ -80,6 +104,11 @@ compare_images() { local ret=0 export_raw_image ${dst_image} + + # Replace slashes (/) with underscores (_) for namespace images + src_image="${src_image//\//_}" + dst_image="${dst_image//\//_}" + if ! cmp "${TEMPDIR}/${src_image}" "${TEMPDIR}/${dst_image}" then show_diff "${TEMPDIR}/${src_image}" "${TEMPDIR}/${dst_image}" @@ -89,18 +118,26 @@ compare_images() { } test_import_native_format() { - local base_image=$1 - local dest_image=$2 + local base_image_spec=$1 + local dest_image_spec=$2 + + # if base image is from namespace + local base_namespace="" + local base_image=${base_image_spec} + if [[ "${base_image_spec}" == rbd/*/* ]]; then + base_namespace=$(basename "$(dirname "${base_image_spec}")") + base_image=$(basename "${base_image_spec}") + fi - rbd migration prepare --import-only "rbd/${base_image}@2" ${dest_image} - rbd migration abort ${dest_image} + rbd migration prepare --import-only "${base_image_spec}@2" ${dest_image_spec} + rbd migration abort ${dest_image_spec} local pool_id=$(ceph osd pool ls detail --format xml | xmlstarlet sel -t -v "//pools/pool[pool_name='rbd']/pool_id") cat > ${TEMPDIR}/spec.json <<EOF { "type": "native", "pool_id": ${pool_id}, - "pool_namespace": "", + "pool_namespace": "${base_namespace}", "image_name": "${base_image}", "snap_name": "2" } @@ -108,37 +145,85 @@ EOF cat ${TEMPDIR}/spec.json rbd migration prepare --import-only \ - --source-spec-path ${TEMPDIR}/spec.json ${dest_image} + --source-spec-path ${TEMPDIR}/spec.json ${dest_image_spec} - compare_images "${base_image}@1" "${dest_image}@1" - compare_images "${base_image}@2" "${dest_image}@2" + compare_images "${base_image_spec}@1" "${dest_image_spec}@1" + compare_images "${base_image_spec}@2" "${dest_image_spec}@2" - rbd migration abort ${dest_image} + rbd migration abort ${dest_image_spec} rbd migration prepare --import-only \ - --source-spec-path ${TEMPDIR}/spec.json ${dest_image} - rbd migration execute ${dest_image} - - compare_images "${base_image}@1" "${dest_image}@1" - compare_images "${base_image}@2" "${dest_image}@2" + --source-spec-path ${TEMPDIR}/spec.json ${dest_image_spec} + rbd migration execute ${dest_image_spec} + + compare_images "${base_image_spec}@1" "${dest_image_spec}@1" + compare_images "${base_image_spec}@2" "${dest_image_spec}@2" + + rbd migration abort ${dest_image_spec} + + # no snap name or snap id + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\"}" \ + ${dest_image_spec} + + # invalid source spec JSON + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_name\": non-existing}" \ + ${dest_image_spec} + + # non-existing snap name + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_name\": \"non-existing\"}" \ + ${dest_image_spec} + + # invalid snap name + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_name\": 123456}" \ + ${dest_image_spec} + + # non-existing snap id passed as int + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_id\": 123456}" \ + ${dest_image_spec} + + # non-existing snap id passed as string + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_id\": \"123456\"}" \ + ${dest_image_spec} + + # invalid snap id + expect_false rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_id\": \"foobar\"}" \ + ${dest_image_spec} + + # snap id passed as int + local snap_id=$(rbd snap ls ${base_image_spec} --format xml | xmlstarlet sel -t -v "//snapshots/snapshot[name='2']/id") + rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_id\": ${snap_id}}" \ + ${dest_image_spec} + rbd migration abort ${dest_image_spec} - rbd migration abort ${dest_image} + # snap id passed as string + rbd migration prepare --import-only \ + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_id\": \"${snap_id}\"}" \ + ${dest_image_spec} + rbd migration abort ${dest_image_spec} rbd migration prepare --import-only \ - --source-spec "{\"type\": \"native\", \"pool_id\": "${pool_id}", \"image_name\": \"${base_image}\", \"snap_name\": \"2\"}" \ - ${dest_image} - rbd migration abort ${dest_image} + --source-spec "{\"type\": \"native\", \"pool_id\": ${pool_id}, \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_name\": \"2\"}" \ + ${dest_image_spec} + rbd migration abort ${dest_image_spec} rbd migration prepare --import-only \ - --source-spec "{\"type\": \"native\", \"pool_name\": \"rbd\", \"image_name\": \"${base_image}\", \"snap_name\": \"2\"}" \ - ${dest_image} - rbd migration execute ${dest_image} - rbd migration commit ${dest_image} + --source-spec "{\"type\": \"native\", \"pool_name\": \"rbd\", \"pool_namespace\": \"${base_namespace}\", \"image_name\": \"${base_image}\", \"snap_name\": \"2\"}" \ + ${dest_image_spec} + rbd migration execute ${dest_image_spec} + rbd migration commit ${dest_image_spec} - compare_images "${base_image}@1" "${dest_image}@1" - compare_images "${base_image}@2" "${dest_image}@2" + compare_images "${base_image_spec}@1" "${dest_image_spec}@1" + compare_images "${base_image_spec}@2" "${dest_image_spec}@2" - remove_image "${dest_image}" + remove_image "${dest_image_spec}" } test_import_qcow_format() { @@ -279,12 +364,12 @@ EOF cat ${TEMPDIR}/spec.json cat ${TEMPDIR}/spec.json | rbd migration prepare --import-only \ - --source-spec-path - ${dest_image} + --source-spec-path - ${dest_image} compare_images ${base_image} ${dest_image} rbd migration abort ${dest_image} rbd migration prepare --import-only \ - --source-spec-path ${TEMPDIR}/spec.json ${dest_image} + --source-spec-path ${TEMPDIR}/spec.json ${dest_image} rbd migration execute ${dest_image} rbd migration commit ${dest_image} @@ -340,6 +425,177 @@ EOF remove_image "${dest_image}" } +test_import_nbd_stream_qcow2() { + local base_image=$1 + local dest_image=$2 + + qemu-nbd -f qcow2 --read-only --shared 10 --persistent --fork \ + ${TEMPDIR}/${base_image}.qcow2 + + cat > ${TEMPDIR}/spec.json <<EOF +{ + "type": "raw", + "stream": { + "type": "nbd", + "uri": "nbd://localhost" + } +} +EOF + cat ${TEMPDIR}/spec.json + + cat ${TEMPDIR}/spec.json | rbd migration prepare --import-only \ + --source-spec-path - ${dest_image} + compare_images ${base_image} ${dest_image} + rbd migration abort ${dest_image} + + rbd migration prepare --import-only \ + --source-spec-path ${TEMPDIR}/spec.json ${dest_image} + compare_images ${base_image} ${dest_image} + rbd migration execute ${dest_image} + compare_images ${base_image} ${dest_image} + rbd migration commit ${dest_image} + compare_images ${base_image} ${dest_image} + remove_image "${dest_image}" + + # shortest possible URI + rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd://"}}' \ + ${dest_image} + rbd migration abort ${dest_image} + + # non-existing export name + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd:///myexport"}}' \ + ${dest_image} + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd://localhost/myexport"}}' \ + ${dest_image} + + kill_nbd_server + qemu-nbd --export-name myexport -f qcow2 --read-only --shared 10 --persistent --fork \ + ${TEMPDIR}/${base_image}.qcow2 + + rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd:///myexport"}}' \ + ${dest_image} + rbd migration abort ${dest_image} + + rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd://localhost/myexport"}}' \ + ${dest_image} + rbd migration abort ${dest_image} + + kill_nbd_server + + # server not running + expect_false rbd migration prepare --import-only \ + --source-spec-path ${TEMPDIR}/spec.json ${dest_image} + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd://"}}' \ + ${dest_image} + + # no URI + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd"}}' \ + ${dest_image} + + # invalid URI + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": 123456}}' \ + ${dest_image} + + # libnbd - nbd_get_errno() returns an error + # nbd_connect_uri: unknown URI scheme: NULL: Invalid argument (errno = 22) + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": ""}}' \ + ${dest_image} + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "foo.example.com"}}' \ + ${dest_image} + + # libnbd - nbd_get_errno() returns 0, EIO fallback + # nbd_connect_uri: getaddrinfo: foo.example.com:10809: Name or service not known (errno = 0) + expect_false rbd migration prepare --import-only \ + --source-spec '{"type": "raw", "stream": {"type": "nbd", "uri": "nbd://foo.example.com"}}' \ + ${dest_image} +} + +test_import_nbd_stream_raw() { + local base_image=$1 + local dest_image=$2 + + qemu-nbd -f raw --read-only --shared 10 --persistent --fork \ + --socket ${TEMPDIR}/qemu-nbd-${base_image} ${TEMPDIR}/${base_image} + qemu-nbd -f raw --read-only --shared 10 --persistent --fork \ + --socket ${TEMPDIR}/qemu-nbd-${base_image}@1 ${TEMPDIR}/${base_image}@1 + qemu-nbd -f raw --read-only --shared 10 --persistent --fork \ + --socket ${TEMPDIR}/qemu-nbd-${base_image}@2 ${TEMPDIR}/${base_image}@2 + + cat > ${TEMPDIR}/spec.json <<EOF +{ + "type": "raw", + "stream": { + "type": "nbd", + "uri": "nbd+unix:///?socket=${TEMPDIR}/qemu-nbd-${base_image}" + }, + "snapshots": [{ + "type": "raw", + "name": "snap1", + "stream": { + "type": "nbd", + "uri": "nbd+unix:///?socket=${TEMPDIR}/qemu-nbd-${base_image}@1" + } + }, { + "type": "raw", + "name": "snap2", + "stream": { + "type": "nbd", + "uri": "nbd+unix:///?socket=${TEMPDIR}/qemu-nbd-${base_image}@2" + } + }] +} +EOF + cat ${TEMPDIR}/spec.json + + rbd migration prepare --import-only \ + --source-spec-path ${TEMPDIR}/spec.json ${dest_image} + + rbd snap create ${dest_image}@head + rbd bench --io-type write --io-pattern rand --io-size 32K --io-total 4M ${dest_image} + + compare_images "${base_image}@1" "${dest_image}@snap1" + compare_images "${base_image}@2" "${dest_image}@snap2" + compare_images "${base_image}" "${dest_image}@head" + + rbd migration abort ${dest_image} + + cat ${TEMPDIR}/spec.json | rbd migration prepare --import-only \ + --source-spec-path - ${dest_image} + + rbd snap create ${dest_image}@head + rbd bench --io-type write --io-pattern rand --io-size 64K --io-total 8M ${dest_image} + + compare_images "${base_image}@1" "${dest_image}@snap1" + compare_images "${base_image}@2" "${dest_image}@snap2" + compare_images "${base_image}" "${dest_image}@head" + + rbd migration execute ${dest_image} + + compare_images "${base_image}@1" "${dest_image}@snap1" + compare_images "${base_image}@2" "${dest_image}@snap2" + compare_images "${base_image}" "${dest_image}@head" + + rbd migration commit ${dest_image} + + compare_images "${base_image}@1" "${dest_image}@snap1" + compare_images "${base_image}@2" "${dest_image}@snap2" + compare_images "${base_image}" "${dest_image}@head" + + remove_image "${dest_image}" + + kill_nbd_server +} + # make sure rbd pool is EMPTY.. this is a test script!! rbd ls 2>&1 | wc -l | grep -v '^0$' && echo "nonempty rbd pool, aborting! run this script on an empty test cluster only." && exit 1 @@ -351,7 +607,25 @@ export_base_image ${IMAGE1} test_import_native_format ${IMAGE1} ${IMAGE2} test_import_qcow_format ${IMAGE1} ${IMAGE2} + test_import_qcow2_format ${IMAGE2} ${IMAGE3} +test_import_nbd_stream_qcow2 ${IMAGE2} ${IMAGE3} + test_import_raw_format ${IMAGE1} ${IMAGE2} +test_import_nbd_stream_raw ${IMAGE1} ${IMAGE2} + +rbd namespace create rbd/${NAMESPACE1} +rbd namespace create rbd/${NAMESPACE2} +create_base_image rbd/${NAMESPACE1}/${IMAGE1} +export_base_image rbd/${NAMESPACE1}/${IMAGE1} + +# Migration from namespace to namespace +test_import_native_format rbd/${NAMESPACE1}/${IMAGE1} rbd/${NAMESPACE2}/${IMAGE2} + +# Migration from namespace to non-namespace +test_import_native_format rbd/${NAMESPACE1}/${IMAGE1} ${IMAGE2} + +# Migration from non-namespace to namespace +test_import_native_format ${IMAGE1} rbd/${NAMESPACE2}/${IMAGE2} echo OK |