| 1 | #!/usr/bin/env python3 |
| 2 | # group: rw quick |
| 3 | # |
| 4 | # Copyright (C) Red Hat, Inc. |
| 5 | # |
| 6 | # This program is free software; you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU General Public License as published by |
| 8 | # the Free Software Foundation; either version 2 of the License, or |
| 9 | # (at your option) any later version. |
| 10 | # |
| 11 | # This program is distributed in the hope that it will be useful, |
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | # GNU General Public License for more details. |
| 15 | # |
| 16 | # You should have received a copy of the GNU General Public License |
| 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | # |
| 19 | # Creator/Owner: Kevin Wolf <kwolf@redhat.com> |
| 20 | |
| 21 | import iotests |
| 22 | |
| 23 | from iotests import filter_qemu_io, filter_qtest |
| 24 | |
| 25 | iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'], |
| 26 | supported_protocols=['file'], |
| 27 | supported_platforms=['linux'], |
| 28 | require_hmp=True) |
| 29 | |
| 30 | with iotests.FilePath('disk.img') as path, \ |
| 31 | iotests.FilePath('nbd-src.sock', base_dir=iotests.sock_dir) as nbd_src, \ |
| 32 | iotests.FilePath('nbd-dst.sock', base_dir=iotests.sock_dir) as nbd_dst, \ |
| 33 | iotests.FilePath('migrate.sock', base_dir=iotests.sock_dir) as mig_sock, \ |
| 34 | iotests.VM(path_suffix="-src") as vm_src, \ |
| 35 | iotests.VM(path_suffix="-dst") as vm_dst: |
| 36 | |
| 37 | img_size = '10M' |
| 38 | |
| 39 | iotests.log('Preparing disk...') |
| 40 | iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size) |
| 41 | |
| 42 | iotests.log('Launching source QSD...') |
| 43 | qsd_src = iotests.QemuStorageDaemon( |
| 44 | '--blockdev', f'file,node-name=disk-file,filename={path}', |
| 45 | '--blockdev', f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt', |
| 46 | '--nbd-server', f'addr.type=unix,addr.path={nbd_src}', |
| 47 | '--export', 'nbd,id=exp0,node-name=disk-fmt,writable=true,' |
| 48 | 'allow-inactive=true', |
| 49 | qmp=True, |
| 50 | ) |
| 51 | |
| 52 | iotests.log('Launching source VM...') |
| 53 | vm_src.add_args('-blockdev', f'nbd,node-name=disk,server.type=unix,' |
| 54 | f'server.path={nbd_src},export=disk-fmt') |
| 55 | vm_src.add_args('-device', 'virtio-blk,drive=disk,id=virtio0') |
| 56 | vm_src.launch() |
| 57 | |
| 58 | iotests.log('Launching destination QSD...') |
| 59 | qsd_dst = iotests.QemuStorageDaemon( |
| 60 | '--blockdev', f'file,node-name=disk-file,filename={path},active=off', |
| 61 | '--blockdev', f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt,' |
| 62 | f'active=off', |
| 63 | '--nbd-server', f'addr.type=unix,addr.path={nbd_dst}', |
| 64 | '--export', 'nbd,id=exp0,node-name=disk-fmt,writable=true,' |
| 65 | 'allow-inactive=true', |
| 66 | qmp=True, |
| 67 | instance_id='b', |
| 68 | ) |
| 69 | |
| 70 | iotests.log('Launching destination VM...') |
| 71 | vm_dst.add_args('-blockdev', f'nbd,node-name=disk,server.type=unix,' |
| 72 | f'server.path={nbd_dst},export=disk-fmt') |
| 73 | vm_dst.add_args('-device', 'virtio-blk,drive=disk,id=virtio0') |
| 74 | vm_dst.add_args('-incoming', f'unix:{mig_sock}') |
| 75 | vm_dst.launch() |
| 76 | |
| 77 | iotests.log('\nTest I/O on the source') |
| 78 | vm_src.hmp_qemu_io('virtio0/virtio-backend', 'write -P 0x11 0 4k', |
| 79 | use_log=True, qdev=True) |
| 80 | vm_src.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k', |
| 81 | use_log=True, qdev=True) |
| 82 | |
| 83 | iotests.log('\nStarting migration...') |
| 84 | |
| 85 | mig_caps = [ |
| 86 | {'capability': 'events', 'state': True}, |
| 87 | {'capability': 'pause-before-switchover', 'state': True}, |
| 88 | ] |
| 89 | vm_src.qmp_log('migrate-set-capabilities', capabilities=mig_caps) |
| 90 | vm_dst.qmp_log('migrate-set-capabilities', capabilities=mig_caps) |
| 91 | vm_src.qmp_log('migrate', uri=f'unix:{mig_sock}', |
| 92 | filters=[iotests.filter_qmp_testfiles]) |
| 93 | |
| 94 | vm_src.event_wait('MIGRATION', |
| 95 | match={'data': {'status': 'pre-switchover'}}) |
| 96 | |
| 97 | iotests.log('\nPre-switchover: Reconfigure QSD instances') |
| 98 | |
| 99 | iotests.log(qsd_src.qmp('blockdev-set-active', {'active': False})) |
| 100 | |
| 101 | # Reading is okay from both sides while the image is inactive. Note that |
| 102 | # the destination may have stale data until it activates the image, though. |
| 103 | vm_src.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k', |
| 104 | use_log=True, qdev=True) |
| 105 | vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read 0 4k', |
| 106 | use_log=True, qdev=True) |
| 107 | |
| 108 | iotests.log(qsd_dst.qmp('blockdev-set-active', {'active': True})) |
| 109 | |
| 110 | iotests.log('\nCompleting migration...') |
| 111 | |
| 112 | vm_src.qmp_log('migrate-continue', state='pre-switchover') |
| 113 | vm_dst.event_wait('MIGRATION', match={'data': {'status': 'completed'}}) |
| 114 | |
| 115 | iotests.log('\nTest I/O on the destination') |
| 116 | |
| 117 | # Now the destination must see what the source wrote |
| 118 | vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k', |
| 119 | use_log=True, qdev=True) |
| 120 | |
| 121 | # And be able to overwrite it |
| 122 | vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'write -P 0x22 0 4k', |
| 123 | use_log=True, qdev=True) |
| 124 | vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x22 0 4k', |
| 125 | use_log=True, qdev=True) |
| 126 | |
| 127 | iotests.log('\nDone') |
| 128 | |
| 129 | vm_src.shutdown() |
| 130 | iotests.log('\n--- vm_src log ---') |
| 131 | log = vm_src.get_log() |
| 132 | if log: |
| 133 | iotests.log(log, [filter_qtest, filter_qemu_io]) |
| 134 | qsd_src.stop() |
| 135 | |
| 136 | vm_dst.shutdown() |
| 137 | iotests.log('\n--- vm_dst log ---') |
| 138 | log = vm_dst.get_log() |
| 139 | if log: |
| 140 | iotests.log(log, [filter_qtest, filter_qemu_io]) |
| 141 | qsd_dst.stop() |