qemu-patch-raspberry4/tests/qemu-iotests/055
Stefan Hajnoczi b53169eae0 blockdev: add sync mode to drive-backup QMP command
The drive-backup command is similar to the drive-mirror command, except
no guest data written after the command executes gets copied.  Add a
sync mode argument which determines whether the entire disk is copied,
just allocated clusters, or only clusters being written to by the guest.

Currently only sync mode 'full' is supported - it copies the entire disk.
For read-only point-in-time snapshots we may only need sync mode 'none'
since the target can be a qcow2 file using the guest's disk as its
backing file (no need to copy the entire disk).  Finally, sync mode
'top' is useful if we wish to preserve the backing chain.

Note that this patch just adds the sync mode argument to drive-backup.
It does not implement sync modes 'top' or 'none'.  This patch is
necessary so we can add a drive-backup HMP command that behaves like the
existing drive-mirror HMP command and takes a sync mode.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2013-07-15 09:49:00 +02:00

289 lines
9.9 KiB
Python
Executable file

#!/usr/bin/env python
#
# Tests for drive-backup
#
# Copyright (C) 2013 Red Hat, Inc.
#
# Based on 041.
#
# 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/>.
#
import time
import os
import iotests
from iotests import qemu_img, qemu_io
test_img = os.path.join(iotests.test_dir, 'test.img')
target_img = os.path.join(iotests.test_dir, 'target.img')
class TestSingleDrive(iotests.QMPTestCase):
image_len = 64 * 1024 * 1024 # MB
def setUp(self):
# Write data to the image so we can compare later
qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
qemu_io('-c', 'write -P0x5d 0 64k', test_img)
qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
def tearDown(self):
self.vm.shutdown()
os.remove(test_img)
try:
os.remove(target_img)
except OSError:
pass
def test_cancel(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
event = self.cancel_and_wait()
self.assert_qmp(event, 'data/type', 'backup')
def test_pause(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-pause', device='drive0')
self.assert_qmp(result, 'return', {})
time.sleep(1)
result = self.vm.qmp('query-block-jobs')
offset = self.dictpath(result, 'return[0]/offset')
time.sleep(1)
result = self.vm.qmp('query-block-jobs')
self.assert_qmp(result, 'return[0]/offset', offset)
result = self.vm.qmp('block-job-resume', device='drive0')
self.assert_qmp(result, 'return', {})
self.wait_until_completed()
self.vm.shutdown()
self.assertTrue(iotests.compare_images(test_img, target_img),
'target image does not match source after backup')
def test_medium_not_found(self):
result = self.vm.qmp('drive-backup', device='ide1-cd0',
target=target_img, sync='full')
self.assert_qmp(result, 'error/class', 'GenericError')
def test_image_not_found(self):
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full', mode='existing')
self.assert_qmp(result, 'error/class', 'GenericError')
def test_device_not_found(self):
result = self.vm.qmp('drive-backup', device='nonexistent',
target=target_img, sync='full')
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
class TestSetSpeed(iotests.QMPTestCase):
image_len = 80 * 1024 * 1024 # MB
def setUp(self):
qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len))
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
def tearDown(self):
self.vm.shutdown()
os.remove(test_img)
os.remove(target_img)
def test_set_speed(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
# Default speed is 0
result = self.vm.qmp('query-block-jobs')
self.assert_qmp(result, 'return[0]/device', 'drive0')
self.assert_qmp(result, 'return[0]/speed', 0)
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
self.assert_qmp(result, 'return', {})
# Ensure the speed we set was accepted
result = self.vm.qmp('query-block-jobs')
self.assert_qmp(result, 'return[0]/device', 'drive0')
self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
event = self.cancel_and_wait()
self.assert_qmp(event, 'data/type', 'backup')
# Check setting speed in drive-backup works
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full', speed=4*1024*1024)
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('query-block-jobs')
self.assert_qmp(result, 'return[0]/device', 'drive0')
self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
event = self.cancel_and_wait()
self.assert_qmp(event, 'data/type', 'backup')
def test_set_speed_invalid(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full', speed=-1)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
self.assert_qmp(result, 'error/class', 'GenericError')
event = self.cancel_and_wait()
self.assert_qmp(event, 'data/type', 'backup')
class TestSingleTransaction(iotests.QMPTestCase):
image_len = 64 * 1024 * 1024 # MB
def setUp(self):
qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len))
qemu_io('-c', 'write -P0x5d 0 64k', test_img)
qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
def tearDown(self):
self.vm.shutdown()
os.remove(test_img)
try:
os.remove(target_img)
except OSError:
pass
def test_cancel(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'drive0',
'target': target_img,
'sync': 'full' },
}
])
self.assert_qmp(result, 'return', {})
event = self.cancel_and_wait()
self.assert_qmp(event, 'data/type', 'backup')
def test_pause(self):
self.assert_no_active_block_jobs()
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'drive0',
'target': target_img,
'sync': 'full' },
}
])
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-pause', device='drive0')
self.assert_qmp(result, 'return', {})
time.sleep(1)
result = self.vm.qmp('query-block-jobs')
offset = self.dictpath(result, 'return[0]/offset')
time.sleep(1)
result = self.vm.qmp('query-block-jobs')
self.assert_qmp(result, 'return[0]/offset', offset)
result = self.vm.qmp('block-job-resume', device='drive0')
self.assert_qmp(result, 'return', {})
self.wait_until_completed()
self.vm.shutdown()
self.assertTrue(iotests.compare_images(test_img, target_img),
'target image does not match source after backup')
def test_medium_not_found(self):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'ide1-cd0',
'target': target_img,
'sync': 'full' },
}
])
self.assert_qmp(result, 'error/class', 'GenericError')
def test_image_not_found(self):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'drive0',
'mode': 'existing',
'target': target_img,
'sync': 'full' },
}
])
self.assert_qmp(result, 'error/class', 'GenericError')
def test_device_not_found(self):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'nonexistent',
'mode': 'existing',
'target': target_img,
'sync': 'full' },
}
])
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
def test_abort(self):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'nonexistent',
'mode': 'existing',
'target': target_img,
'sync': 'full' },
}, {
'type': 'Abort',
'data': {},
}
])
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_no_active_block_jobs()
if __name__ == '__main__':
iotests.main(supported_fmts=['raw', 'qcow2'])