xref: /openbmc/qemu/tests/qemu-iotests/tests/migrate-bitmaps-test (revision a44be0334beae3a9affb4a3a92cc6852993d7a84)
1*a44be033SVladimir Sementsov-Ogievskiy#!/usr/bin/env python3
2*a44be033SVladimir Sementsov-Ogievskiy# group: rw migration
3*a44be033SVladimir Sementsov-Ogievskiy#
4*a44be033SVladimir Sementsov-Ogievskiy# Tests for dirty bitmaps migration.
5*a44be033SVladimir Sementsov-Ogievskiy#
6*a44be033SVladimir Sementsov-Ogievskiy# Copyright (c) 2016-2017 Virtuozzo International GmbH. All rights reserved.
7*a44be033SVladimir Sementsov-Ogievskiy#
8*a44be033SVladimir Sementsov-Ogievskiy# This program is free software; you can redistribute it and/or modify
9*a44be033SVladimir Sementsov-Ogievskiy# it under the terms of the GNU General Public License as published by
10*a44be033SVladimir Sementsov-Ogievskiy# the Free Software Foundation; either version 2 of the License, or
11*a44be033SVladimir Sementsov-Ogievskiy# (at your option) any later version.
12*a44be033SVladimir Sementsov-Ogievskiy#
13*a44be033SVladimir Sementsov-Ogievskiy# This program is distributed in the hope that it will be useful,
14*a44be033SVladimir Sementsov-Ogievskiy# but WITHOUT ANY WARRANTY; without even the implied warranty of
15*a44be033SVladimir Sementsov-Ogievskiy# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*a44be033SVladimir Sementsov-Ogievskiy# GNU General Public License for more details.
17*a44be033SVladimir Sementsov-Ogievskiy#
18*a44be033SVladimir Sementsov-Ogievskiy# You should have received a copy of the GNU General Public License
19*a44be033SVladimir Sementsov-Ogievskiy# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*a44be033SVladimir Sementsov-Ogievskiy#
21*a44be033SVladimir Sementsov-Ogievskiy
22*a44be033SVladimir Sementsov-Ogievskiyimport os
23*a44be033SVladimir Sementsov-Ogievskiyimport iotests
24*a44be033SVladimir Sementsov-Ogievskiyimport time
25*a44be033SVladimir Sementsov-Ogievskiyimport itertools
26*a44be033SVladimir Sementsov-Ogievskiyimport operator
27*a44be033SVladimir Sementsov-Ogievskiyimport re
28*a44be033SVladimir Sementsov-Ogievskiyfrom iotests import qemu_img, qemu_img_create, Timeout
29*a44be033SVladimir Sementsov-Ogievskiy
30*a44be033SVladimir Sementsov-Ogievskiy
31*a44be033SVladimir Sementsov-Ogievskiydisk_a = os.path.join(iotests.test_dir, 'disk_a')
32*a44be033SVladimir Sementsov-Ogievskiydisk_b = os.path.join(iotests.test_dir, 'disk_b')
33*a44be033SVladimir Sementsov-Ogievskiybase_a = os.path.join(iotests.test_dir, 'base_a')
34*a44be033SVladimir Sementsov-Ogievskiysize = '1M'
35*a44be033SVladimir Sementsov-Ogievskiymig_file = os.path.join(iotests.test_dir, 'mig_file')
36*a44be033SVladimir Sementsov-Ogievskiymig_cmd = 'exec: cat > ' + mig_file
37*a44be033SVladimir Sementsov-Ogievskiyincoming_cmd = 'exec: cat ' + mig_file
38*a44be033SVladimir Sementsov-Ogievskiy
39*a44be033SVladimir Sementsov-Ogievskiy
40*a44be033SVladimir Sementsov-Ogievskiyclass TestDirtyBitmapMigration(iotests.QMPTestCase):
41*a44be033SVladimir Sementsov-Ogievskiy    def tearDown(self):
42*a44be033SVladimir Sementsov-Ogievskiy        self.vm_a.shutdown()
43*a44be033SVladimir Sementsov-Ogievskiy        self.vm_b.shutdown()
44*a44be033SVladimir Sementsov-Ogievskiy        os.remove(disk_a)
45*a44be033SVladimir Sementsov-Ogievskiy        os.remove(disk_b)
46*a44be033SVladimir Sementsov-Ogievskiy        os.remove(mig_file)
47*a44be033SVladimir Sementsov-Ogievskiy
48*a44be033SVladimir Sementsov-Ogievskiy    def setUp(self):
49*a44be033SVladimir Sementsov-Ogievskiy        qemu_img('create', '-f', iotests.imgfmt, disk_a, size)
50*a44be033SVladimir Sementsov-Ogievskiy        qemu_img('create', '-f', iotests.imgfmt, disk_b, size)
51*a44be033SVladimir Sementsov-Ogievskiy
52*a44be033SVladimir Sementsov-Ogievskiy        self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a)
53*a44be033SVladimir Sementsov-Ogievskiy        self.vm_a.launch()
54*a44be033SVladimir Sementsov-Ogievskiy
55*a44be033SVladimir Sementsov-Ogievskiy        self.vm_b = iotests.VM(path_suffix='b')
56*a44be033SVladimir Sementsov-Ogievskiy
57*a44be033SVladimir Sementsov-Ogievskiy    def add_bitmap(self, vm, granularity, persistent):
58*a44be033SVladimir Sementsov-Ogievskiy        params = {'node': 'drive0',
59*a44be033SVladimir Sementsov-Ogievskiy                  'name': 'bitmap0',
60*a44be033SVladimir Sementsov-Ogievskiy                  'granularity': granularity}
61*a44be033SVladimir Sementsov-Ogievskiy        if persistent:
62*a44be033SVladimir Sementsov-Ogievskiy            params['persistent'] = True
63*a44be033SVladimir Sementsov-Ogievskiy
64*a44be033SVladimir Sementsov-Ogievskiy        result = vm.qmp('block-dirty-bitmap-add', **params)
65*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {});
66*a44be033SVladimir Sementsov-Ogievskiy
67*a44be033SVladimir Sementsov-Ogievskiy    def get_bitmap_hash(self, vm):
68*a44be033SVladimir Sementsov-Ogievskiy        result = vm.qmp('x-debug-block-dirty-bitmap-sha256',
69*a44be033SVladimir Sementsov-Ogievskiy                        node='drive0', name='bitmap0')
70*a44be033SVladimir Sementsov-Ogievskiy        return result['return']['sha256']
71*a44be033SVladimir Sementsov-Ogievskiy
72*a44be033SVladimir Sementsov-Ogievskiy    def check_bitmap(self, vm, sha256):
73*a44be033SVladimir Sementsov-Ogievskiy        result = vm.qmp('x-debug-block-dirty-bitmap-sha256',
74*a44be033SVladimir Sementsov-Ogievskiy                        node='drive0', name='bitmap0')
75*a44be033SVladimir Sementsov-Ogievskiy        if sha256:
76*a44be033SVladimir Sementsov-Ogievskiy            self.assert_qmp(result, 'return/sha256', sha256);
77*a44be033SVladimir Sementsov-Ogievskiy        else:
78*a44be033SVladimir Sementsov-Ogievskiy            self.assert_qmp(result, 'error/desc',
79*a44be033SVladimir Sementsov-Ogievskiy                            "Dirty bitmap 'bitmap0' not found");
80*a44be033SVladimir Sementsov-Ogievskiy
81*a44be033SVladimir Sementsov-Ogievskiy    def do_test_migration_resume_source(self, persistent, migrate_bitmaps):
82*a44be033SVladimir Sementsov-Ogievskiy        granularity = 512
83*a44be033SVladimir Sementsov-Ogievskiy
84*a44be033SVladimir Sementsov-Ogievskiy        # regions = ((start, count), ...)
85*a44be033SVladimir Sementsov-Ogievskiy        regions = ((0, 0x10000),
86*a44be033SVladimir Sementsov-Ogievskiy                   (0xf0000, 0x10000),
87*a44be033SVladimir Sementsov-Ogievskiy                   (0xa0201, 0x1000))
88*a44be033SVladimir Sementsov-Ogievskiy
89*a44be033SVladimir Sementsov-Ogievskiy        mig_caps = [{'capability': 'events', 'state': True}]
90*a44be033SVladimir Sementsov-Ogievskiy        if migrate_bitmaps:
91*a44be033SVladimir Sementsov-Ogievskiy            mig_caps.append({'capability': 'dirty-bitmaps', 'state': True})
92*a44be033SVladimir Sementsov-Ogievskiy
93*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm_a.qmp('migrate-set-capabilities',
94*a44be033SVladimir Sementsov-Ogievskiy                               capabilities=mig_caps)
95*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
96*a44be033SVladimir Sementsov-Ogievskiy
97*a44be033SVladimir Sementsov-Ogievskiy        self.add_bitmap(self.vm_a, granularity, persistent)
98*a44be033SVladimir Sementsov-Ogievskiy        for r in regions:
99*a44be033SVladimir Sementsov-Ogievskiy            self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % r)
100*a44be033SVladimir Sementsov-Ogievskiy        sha256 = self.get_bitmap_hash(self.vm_a)
101*a44be033SVladimir Sementsov-Ogievskiy
102*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm_a.qmp('migrate', uri=mig_cmd)
103*a44be033SVladimir Sementsov-Ogievskiy        while True:
104*a44be033SVladimir Sementsov-Ogievskiy            event = self.vm_a.event_wait('MIGRATION')
105*a44be033SVladimir Sementsov-Ogievskiy            if event['data']['status'] == 'completed':
106*a44be033SVladimir Sementsov-Ogievskiy                break
107*a44be033SVladimir Sementsov-Ogievskiy        while True:
108*a44be033SVladimir Sementsov-Ogievskiy            result = self.vm_a.qmp('query-status')
109*a44be033SVladimir Sementsov-Ogievskiy            if (result['return']['status'] == 'postmigrate'):
110*a44be033SVladimir Sementsov-Ogievskiy                break
111*a44be033SVladimir Sementsov-Ogievskiy
112*a44be033SVladimir Sementsov-Ogievskiy        # test that bitmap is still here
113*a44be033SVladimir Sementsov-Ogievskiy        removed = (not migrate_bitmaps) and persistent
114*a44be033SVladimir Sementsov-Ogievskiy        self.check_bitmap(self.vm_a, False if removed else sha256)
115*a44be033SVladimir Sementsov-Ogievskiy
116*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm_a.qmp('cont')
117*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
118*a44be033SVladimir Sementsov-Ogievskiy
119*a44be033SVladimir Sementsov-Ogievskiy        # test that bitmap is still here after invalidation
120*a44be033SVladimir Sementsov-Ogievskiy        self.check_bitmap(self.vm_a, sha256)
121*a44be033SVladimir Sementsov-Ogievskiy
122*a44be033SVladimir Sementsov-Ogievskiy        # shutdown and check that invalidation didn't fail
123*a44be033SVladimir Sementsov-Ogievskiy        self.vm_a.shutdown()
124*a44be033SVladimir Sementsov-Ogievskiy
125*a44be033SVladimir Sementsov-Ogievskiy        # catch 'Could not reopen qcow2 layer: Bitmap already exists'
126*a44be033SVladimir Sementsov-Ogievskiy        # possible error
127*a44be033SVladimir Sementsov-Ogievskiy        log = self.vm_a.get_log()
128*a44be033SVladimir Sementsov-Ogievskiy        log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
129*a44be033SVladimir Sementsov-Ogievskiy        log = re.sub(r'^(wrote .* bytes at offset .*\n.*KiB.*ops.*sec.*\n){3}',
130*a44be033SVladimir Sementsov-Ogievskiy                     '', log)
131*a44be033SVladimir Sementsov-Ogievskiy        log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
132*a44be033SVladimir Sementsov-Ogievskiy        self.assertEqual(log, '')
133*a44be033SVladimir Sementsov-Ogievskiy
134*a44be033SVladimir Sementsov-Ogievskiy        # test that bitmap is still persistent
135*a44be033SVladimir Sementsov-Ogievskiy        self.vm_a.launch()
136*a44be033SVladimir Sementsov-Ogievskiy        self.check_bitmap(self.vm_a, sha256 if persistent else False)
137*a44be033SVladimir Sementsov-Ogievskiy
138*a44be033SVladimir Sementsov-Ogievskiy    def do_test_migration(self, persistent, migrate_bitmaps, online,
139*a44be033SVladimir Sementsov-Ogievskiy                          shared_storage, pre_shutdown):
140*a44be033SVladimir Sementsov-Ogievskiy        granularity = 512
141*a44be033SVladimir Sementsov-Ogievskiy
142*a44be033SVladimir Sementsov-Ogievskiy        # regions = ((start, count), ...)
143*a44be033SVladimir Sementsov-Ogievskiy        regions = ((0, 0x10000),
144*a44be033SVladimir Sementsov-Ogievskiy                   (0xf0000, 0x10000),
145*a44be033SVladimir Sementsov-Ogievskiy                   (0xa0201, 0x1000))
146*a44be033SVladimir Sementsov-Ogievskiy
147*a44be033SVladimir Sementsov-Ogievskiy        should_migrate = \
148*a44be033SVladimir Sementsov-Ogievskiy            (migrate_bitmaps and (persistent or not pre_shutdown)) or \
149*a44be033SVladimir Sementsov-Ogievskiy            (persistent and shared_storage)
150*a44be033SVladimir Sementsov-Ogievskiy        mig_caps = [{'capability': 'events', 'state': True}]
151*a44be033SVladimir Sementsov-Ogievskiy        if migrate_bitmaps:
152*a44be033SVladimir Sementsov-Ogievskiy            mig_caps.append({'capability': 'dirty-bitmaps', 'state': True})
153*a44be033SVladimir Sementsov-Ogievskiy
154*a44be033SVladimir Sementsov-Ogievskiy        self.vm_b.add_incoming(incoming_cmd if online else "defer")
155*a44be033SVladimir Sementsov-Ogievskiy        self.vm_b.add_drive(disk_a if shared_storage else disk_b)
156*a44be033SVladimir Sementsov-Ogievskiy
157*a44be033SVladimir Sementsov-Ogievskiy        if online:
158*a44be033SVladimir Sementsov-Ogievskiy            os.mkfifo(mig_file)
159*a44be033SVladimir Sementsov-Ogievskiy            self.vm_b.launch()
160*a44be033SVladimir Sementsov-Ogievskiy            result = self.vm_b.qmp('migrate-set-capabilities',
161*a44be033SVladimir Sementsov-Ogievskiy                                   capabilities=mig_caps)
162*a44be033SVladimir Sementsov-Ogievskiy            self.assert_qmp(result, 'return', {})
163*a44be033SVladimir Sementsov-Ogievskiy
164*a44be033SVladimir Sementsov-Ogievskiy        self.add_bitmap(self.vm_a, granularity, persistent)
165*a44be033SVladimir Sementsov-Ogievskiy        for r in regions:
166*a44be033SVladimir Sementsov-Ogievskiy            self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % r)
167*a44be033SVladimir Sementsov-Ogievskiy        sha256 = self.get_bitmap_hash(self.vm_a)
168*a44be033SVladimir Sementsov-Ogievskiy
169*a44be033SVladimir Sementsov-Ogievskiy        if pre_shutdown:
170*a44be033SVladimir Sementsov-Ogievskiy            self.vm_a.shutdown()
171*a44be033SVladimir Sementsov-Ogievskiy            self.vm_a.launch()
172*a44be033SVladimir Sementsov-Ogievskiy
173*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm_a.qmp('migrate-set-capabilities',
174*a44be033SVladimir Sementsov-Ogievskiy                               capabilities=mig_caps)
175*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
176*a44be033SVladimir Sementsov-Ogievskiy
177*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm_a.qmp('migrate', uri=mig_cmd)
178*a44be033SVladimir Sementsov-Ogievskiy        while True:
179*a44be033SVladimir Sementsov-Ogievskiy            event = self.vm_a.event_wait('MIGRATION')
180*a44be033SVladimir Sementsov-Ogievskiy            if event['data']['status'] == 'completed':
181*a44be033SVladimir Sementsov-Ogievskiy                break
182*a44be033SVladimir Sementsov-Ogievskiy
183*a44be033SVladimir Sementsov-Ogievskiy        if not online:
184*a44be033SVladimir Sementsov-Ogievskiy            self.vm_a.shutdown()
185*a44be033SVladimir Sementsov-Ogievskiy            self.vm_b.launch()
186*a44be033SVladimir Sementsov-Ogievskiy            result = self.vm_b.qmp('migrate-set-capabilities',
187*a44be033SVladimir Sementsov-Ogievskiy                                   capabilities=mig_caps)
188*a44be033SVladimir Sementsov-Ogievskiy            self.assert_qmp(result, 'return', {})
189*a44be033SVladimir Sementsov-Ogievskiy            result = self.vm_b.qmp('migrate-incoming', uri=incoming_cmd)
190*a44be033SVladimir Sementsov-Ogievskiy            self.assert_qmp(result, 'return', {})
191*a44be033SVladimir Sementsov-Ogievskiy
192*a44be033SVladimir Sementsov-Ogievskiy        while True:
193*a44be033SVladimir Sementsov-Ogievskiy            event = self.vm_b.event_wait('MIGRATION')
194*a44be033SVladimir Sementsov-Ogievskiy            if event['data']['status'] == 'completed':
195*a44be033SVladimir Sementsov-Ogievskiy                break
196*a44be033SVladimir Sementsov-Ogievskiy
197*a44be033SVladimir Sementsov-Ogievskiy        self.check_bitmap(self.vm_b, sha256 if should_migrate else False)
198*a44be033SVladimir Sementsov-Ogievskiy
199*a44be033SVladimir Sementsov-Ogievskiy        if should_migrate:
200*a44be033SVladimir Sementsov-Ogievskiy            self.vm_b.shutdown()
201*a44be033SVladimir Sementsov-Ogievskiy
202*a44be033SVladimir Sementsov-Ogievskiy            # catch 'Could not reopen qcow2 layer: Bitmap already exists'
203*a44be033SVladimir Sementsov-Ogievskiy            # possible error
204*a44be033SVladimir Sementsov-Ogievskiy            log = self.vm_b.get_log()
205*a44be033SVladimir Sementsov-Ogievskiy            log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
206*a44be033SVladimir Sementsov-Ogievskiy            log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
207*a44be033SVladimir Sementsov-Ogievskiy            self.assertEqual(log, '')
208*a44be033SVladimir Sementsov-Ogievskiy
209*a44be033SVladimir Sementsov-Ogievskiy            # recreate vm_b, as we don't want -incoming option (this will lead
210*a44be033SVladimir Sementsov-Ogievskiy            # to "cat" process left alive after test finish)
211*a44be033SVladimir Sementsov-Ogievskiy            self.vm_b = iotests.VM(path_suffix='b')
212*a44be033SVladimir Sementsov-Ogievskiy            self.vm_b.add_drive(disk_a if shared_storage else disk_b)
213*a44be033SVladimir Sementsov-Ogievskiy            self.vm_b.launch()
214*a44be033SVladimir Sementsov-Ogievskiy            self.check_bitmap(self.vm_b, sha256 if persistent else False)
215*a44be033SVladimir Sementsov-Ogievskiy
216*a44be033SVladimir Sementsov-Ogievskiy
217*a44be033SVladimir Sementsov-Ogievskiydef inject_test_case(klass, name, method, *args, **kwargs):
218*a44be033SVladimir Sementsov-Ogievskiy    mc = operator.methodcaller(method, *args, **kwargs)
219*a44be033SVladimir Sementsov-Ogievskiy    setattr(klass, 'test_' + method + name, lambda self: mc(self))
220*a44be033SVladimir Sementsov-Ogievskiy
221*a44be033SVladimir Sementsov-Ogievskiyfor cmb in list(itertools.product((True, False), repeat=5)):
222*a44be033SVladimir Sementsov-Ogievskiy    name = ('_' if cmb[0] else '_not_') + 'persistent_'
223*a44be033SVladimir Sementsov-Ogievskiy    name += ('_' if cmb[1] else '_not_') + 'migbitmap_'
224*a44be033SVladimir Sementsov-Ogievskiy    name += '_online' if cmb[2] else '_offline'
225*a44be033SVladimir Sementsov-Ogievskiy    name += '_shared' if cmb[3] else '_nonshared'
226*a44be033SVladimir Sementsov-Ogievskiy    if (cmb[4]):
227*a44be033SVladimir Sementsov-Ogievskiy        name += '__pre_shutdown'
228*a44be033SVladimir Sementsov-Ogievskiy
229*a44be033SVladimir Sementsov-Ogievskiy    inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration',
230*a44be033SVladimir Sementsov-Ogievskiy                     *list(cmb))
231*a44be033SVladimir Sementsov-Ogievskiy
232*a44be033SVladimir Sementsov-Ogievskiyfor cmb in list(itertools.product((True, False), repeat=2)):
233*a44be033SVladimir Sementsov-Ogievskiy    name = ('_' if cmb[0] else '_not_') + 'persistent_'
234*a44be033SVladimir Sementsov-Ogievskiy    name += ('_' if cmb[1] else '_not_') + 'migbitmap'
235*a44be033SVladimir Sementsov-Ogievskiy
236*a44be033SVladimir Sementsov-Ogievskiy    inject_test_case(TestDirtyBitmapMigration, name,
237*a44be033SVladimir Sementsov-Ogievskiy                     'do_test_migration_resume_source', *list(cmb))
238*a44be033SVladimir Sementsov-Ogievskiy
239*a44be033SVladimir Sementsov-Ogievskiy
240*a44be033SVladimir Sementsov-Ogievskiyclass TestDirtyBitmapBackingMigration(iotests.QMPTestCase):
241*a44be033SVladimir Sementsov-Ogievskiy    def setUp(self):
242*a44be033SVladimir Sementsov-Ogievskiy        qemu_img_create('-f', iotests.imgfmt, base_a, size)
243*a44be033SVladimir Sementsov-Ogievskiy        qemu_img_create('-f', iotests.imgfmt, '-F', iotests.imgfmt,
244*a44be033SVladimir Sementsov-Ogievskiy                        '-b', base_a, disk_a, size)
245*a44be033SVladimir Sementsov-Ogievskiy
246*a44be033SVladimir Sementsov-Ogievskiy        for f in (disk_a, base_a):
247*a44be033SVladimir Sementsov-Ogievskiy            qemu_img('bitmap', '--add', f, 'bmap0')
248*a44be033SVladimir Sementsov-Ogievskiy
249*a44be033SVladimir Sementsov-Ogievskiy        blockdev = {
250*a44be033SVladimir Sementsov-Ogievskiy            'node-name': 'node0',
251*a44be033SVladimir Sementsov-Ogievskiy            'driver': iotests.imgfmt,
252*a44be033SVladimir Sementsov-Ogievskiy            'file': {
253*a44be033SVladimir Sementsov-Ogievskiy                'driver': 'file',
254*a44be033SVladimir Sementsov-Ogievskiy                'filename': disk_a
255*a44be033SVladimir Sementsov-Ogievskiy            },
256*a44be033SVladimir Sementsov-Ogievskiy            'backing': {
257*a44be033SVladimir Sementsov-Ogievskiy                'node-name': 'node0-base',
258*a44be033SVladimir Sementsov-Ogievskiy                'driver': iotests.imgfmt,
259*a44be033SVladimir Sementsov-Ogievskiy                'file': {
260*a44be033SVladimir Sementsov-Ogievskiy                    'driver': 'file',
261*a44be033SVladimir Sementsov-Ogievskiy                    'filename': base_a
262*a44be033SVladimir Sementsov-Ogievskiy                }
263*a44be033SVladimir Sementsov-Ogievskiy            }
264*a44be033SVladimir Sementsov-Ogievskiy        }
265*a44be033SVladimir Sementsov-Ogievskiy
266*a44be033SVladimir Sementsov-Ogievskiy        self.vm = iotests.VM()
267*a44be033SVladimir Sementsov-Ogievskiy        self.vm.launch()
268*a44be033SVladimir Sementsov-Ogievskiy
269*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm.qmp('blockdev-add', **blockdev)
270*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
271*a44be033SVladimir Sementsov-Ogievskiy
272*a44be033SVladimir Sementsov-Ogievskiy        # Check that the bitmaps are there
273*a44be033SVladimir Sementsov-Ogievskiy        for node in self.vm.qmp('query-named-block-nodes', flat=True)['return']:
274*a44be033SVladimir Sementsov-Ogievskiy            if 'node0' in node['node-name']:
275*a44be033SVladimir Sementsov-Ogievskiy                self.assert_qmp(node, 'dirty-bitmaps[0]/name', 'bmap0')
276*a44be033SVladimir Sementsov-Ogievskiy
277*a44be033SVladimir Sementsov-Ogievskiy        caps = [{'capability': 'events', 'state': True}]
278*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm.qmp('migrate-set-capabilities', capabilities=caps)
279*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
280*a44be033SVladimir Sementsov-Ogievskiy
281*a44be033SVladimir Sementsov-Ogievskiy    def tearDown(self):
282*a44be033SVladimir Sementsov-Ogievskiy        self.vm.shutdown()
283*a44be033SVladimir Sementsov-Ogievskiy        for f in (disk_a, base_a):
284*a44be033SVladimir Sementsov-Ogievskiy            os.remove(f)
285*a44be033SVladimir Sementsov-Ogievskiy
286*a44be033SVladimir Sementsov-Ogievskiy    def test_cont_on_source(self):
287*a44be033SVladimir Sementsov-Ogievskiy        """
288*a44be033SVladimir Sementsov-Ogievskiy        Continue the source after migration.
289*a44be033SVladimir Sementsov-Ogievskiy        """
290*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm.qmp('migrate', uri=f'exec: cat > /dev/null')
291*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
292*a44be033SVladimir Sementsov-Ogievskiy
293*a44be033SVladimir Sementsov-Ogievskiy        with Timeout(10, 'Migration timeout'):
294*a44be033SVladimir Sementsov-Ogievskiy            self.vm.wait_migration('postmigrate')
295*a44be033SVladimir Sementsov-Ogievskiy
296*a44be033SVladimir Sementsov-Ogievskiy        result = self.vm.qmp('cont')
297*a44be033SVladimir Sementsov-Ogievskiy        self.assert_qmp(result, 'return', {})
298*a44be033SVladimir Sementsov-Ogievskiy
299*a44be033SVladimir Sementsov-Ogievskiy
300*a44be033SVladimir Sementsov-Ogievskiyif __name__ == '__main__':
301*a44be033SVladimir Sementsov-Ogievskiy    iotests.main(supported_fmts=['qcow2'],
302*a44be033SVladimir Sementsov-Ogievskiy                 supported_protocols=['file'])
303