#!/usr/bin/env bash # group: rw # # Live snapshot tests # # This tests live snapshots of images on a running QEMU instance, using # QMP commands. Both single disk snapshots, and transactional group # snapshots are performed. # # Copyright (C) 2014 Red Hat, Inc. # Copyright (C) 2015 Igalia, S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # creator owner=jcody@redhat.com seq=`basename $0` echo "QA output created by $seq" status=1 # failure is the default! snapshot_virt0="snapshot-v0.qcow2" snapshot_virt1="snapshot-v1.qcow2" SNAPSHOTS=10 _cleanup() { _cleanup_qemu _cleanup_test_img for i in $(seq 1 ${SNAPSHOTS}) do _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt0}" _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt1}" done for img in "${TEST_IMG}".{1,2,base} do _rm_test_img "$img" done } trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks . ./common.rc . ./common.filter . ./common.qemu _supported_fmt qcow2 _supported_proto file # ${1}: unique identifier for the snapshot filename create_single_snapshot() { cmd="{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'snapshot-file':'${TEST_DIR}/${1}-${snapshot_virt0}', 'format': 'qcow2' } }" _send_qemu_cmd $h "${cmd}" "return" } # ${1}: unique identifier for the snapshot filename create_group_snapshot() { cmd="{ 'execute': 'transaction', 'arguments': {'actions': [ { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio0', 'snapshot-file': '${TEST_DIR}/${1}-${snapshot_virt0}' } }, { 'type': 'blockdev-snapshot-sync', 'data' : { 'device': 'virtio1', 'snapshot-file': '${TEST_DIR}/${1}-${snapshot_virt1}' } } ] } }" _send_qemu_cmd $h "${cmd}" "return" } # ${1}: unique identifier for the snapshot filename # ${2}: extra_params to the blockdev-add command # ${3}: filename do_blockdev_add() { cmd="{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'qcow2', 'node-name': 'snap_${1}', ${2} 'file': { 'driver': 'file', 'filename': '${3}', 'node-name': 'file_${1}' } } }" _send_qemu_cmd $h "${cmd}" "return" } # ${1}: unique identifier for the snapshot filename add_snapshot_image() { base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}" snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}" TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" -F $IMGFMT "$size" do_blockdev_add "$1" "'backing': null, " "${snapshot_file}" } # ${1}: unique identifier for the snapshot filename # ${2}: expected response, defaults to 'return' blockdev_snapshot() { cmd="{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_${1}' } }" _send_qemu_cmd $h "${cmd}" "${2:-return}" } size=128M TEST_IMG="$TEST_IMG.1" _make_test_img $size TEST_IMG="$TEST_IMG.2" _make_test_img $size echo echo === Running QEMU === echo qemu_comm_method="qmp" _launch_qemu -drive file="${TEST_IMG}.1",if=virtio -drive file="${TEST_IMG}.2",if=virtio h=$QEMU_HANDLE echo echo === Sending capabilities === echo _send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" # Tests for the blockdev-snapshot-sync command echo echo === Create a single snapshot on virtio0 === echo create_single_snapshot 1 echo echo === Invalid command - missing device and nodename === echo _send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'snapshot-file':'${TEST_DIR}/1-${snapshot_virt0}', 'format': 'qcow2' } }" "error" echo echo === Invalid command - missing snapshot-file === echo _send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', 'arguments': { 'device': 'virtio0', 'format': 'qcow2' } }" "error" echo echo echo === Create several transactional group snapshots === echo for i in $(seq 2 ${SNAPSHOTS}) do create_group_snapshot ${i} done # Tests for the blockdev-snapshot command echo echo === Create a couple of snapshots using blockdev-snapshot === echo SNAPSHOTS=$((${SNAPSHOTS}+1)) add_snapshot_image ${SNAPSHOTS} blockdev_snapshot ${SNAPSHOTS} SNAPSHOTS=$((${SNAPSHOTS}+1)) add_snapshot_image ${SNAPSHOTS} blockdev_snapshot ${SNAPSHOTS} echo echo === Invalid command - cannot create a snapshot using a file BDS === echo _send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot', 'arguments': { 'node':'virtio0', 'overlay':'file_${SNAPSHOTS}' } }" "error" echo echo === Invalid command - snapshot node used as active layer === echo blockdev_snapshot ${SNAPSHOTS} error _send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot', 'arguments': { 'node':'virtio0', 'overlay':'virtio0' } }" "error" _send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot', 'arguments': { 'node':'virtio0', 'overlay':'virtio1' } }" "error" echo echo === Invalid command - snapshot node used as backing hd === echo blockdev_snapshot $((${SNAPSHOTS}-1)) error echo echo === Invalid command - snapshot node has a backing image === echo SNAPSHOTS=$((${SNAPSHOTS}+1)) TEST_IMG="$TEST_IMG.base" _make_test_img "$size" _make_test_img -b "${TEST_IMG}.base" -F $IMGFMT "$size" do_blockdev_add ${SNAPSHOTS} "" "${TEST_IMG}" blockdev_snapshot ${SNAPSHOTS} error echo echo === Invalid command - The node does not exist === echo blockdev_snapshot $((${SNAPSHOTS}+1)) error _send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot', 'arguments': { 'node':'nodevice', 'overlay':'snap_${SNAPSHOTS}' } }" "error" # success, all done echo "*** done" rm -f $seq.full status=0