]> Git Repo - qemu.git/blob - tests/qemu-iotests/139
tests: Clean up string interpolation around qtest_qmp_device_add()
[qemu.git] / tests / qemu-iotests / 139
1 #!/usr/bin/env python
2 #
3 # Test cases for the QMP 'blockdev-del' command
4 #
5 # Copyright (C) 2015 Igalia, S.L.
6 # Author: Alberto Garcia <[email protected]>
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21
22 import os
23 import iotests
24 import time
25
26 base_img = os.path.join(iotests.test_dir, 'base.img')
27 new_img = os.path.join(iotests.test_dir, 'new.img')
28 if iotests.qemu_default_machine == 's390-ccw-virtio':
29     default_virtio_blk = 'virtio-blk-ccw'
30 else:
31     default_virtio_blk = 'virtio-blk-pci'
32
33 class TestBlockdevDel(iotests.QMPTestCase):
34
35     def setUp(self):
36         iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
37         self.vm = iotests.VM()
38         if iotests.qemu_default_machine == 's390-ccw-virtio':
39             self.vm.add_device("virtio-scsi-ccw,id=virtio-scsi")
40         else:
41             self.vm.add_device("virtio-scsi-pci,id=virtio-scsi")
42
43         self.vm.launch()
44
45     def tearDown(self):
46         self.vm.shutdown()
47         os.remove(base_img)
48         if os.path.isfile(new_img):
49             os.remove(new_img)
50
51     # Check whether a BlockDriverState exists
52     def checkBlockDriverState(self, node, must_exist = True):
53         result = self.vm.qmp('query-named-block-nodes')
54         nodes = filter(lambda x: x['node-name'] == node, result['return'])
55         self.assertLessEqual(len(nodes), 1)
56         self.assertEqual(must_exist, len(nodes) == 1)
57
58     # Add a BlockDriverState without a BlockBackend
59     def addBlockDriverState(self, node):
60         file_node = '%s_file' % node
61         self.checkBlockDriverState(node, False)
62         self.checkBlockDriverState(file_node, False)
63         opts = {'driver': iotests.imgfmt,
64                 'node-name': node,
65                 'file': {'driver': 'file',
66                          'node-name': file_node,
67                          'filename': base_img}}
68         result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
69         self.assert_qmp(result, 'return', {})
70         self.checkBlockDriverState(node)
71         self.checkBlockDriverState(file_node)
72
73     # Add a BlockDriverState that will be used as overlay for the base_img BDS
74     def addBlockDriverStateOverlay(self, node):
75         self.checkBlockDriverState(node, False)
76         iotests.qemu_img('create', '-u', '-f', iotests.imgfmt,
77                          '-b', base_img, new_img, '1M')
78         opts = {'driver': iotests.imgfmt,
79                 'node-name': node,
80                 'backing': None,
81                 'file': {'driver': 'file',
82                          'filename': new_img}}
83         result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
84         self.assert_qmp(result, 'return', {})
85         self.checkBlockDriverState(node)
86
87     # Delete a BlockDriverState
88     def delBlockDriverState(self, node, expect_error = False):
89         self.checkBlockDriverState(node)
90         result = self.vm.qmp('blockdev-del', node_name = node)
91         if expect_error:
92             self.assert_qmp(result, 'error/class', 'GenericError')
93         else:
94             self.assert_qmp(result, 'return', {})
95         self.checkBlockDriverState(node, expect_error)
96
97     # Add a device model
98     def addDeviceModel(self, device, backend, driver = default_virtio_blk):
99         result = self.vm.qmp('device_add', id = device,
100                              driver = driver, drive = backend)
101         self.assert_qmp(result, 'return', {})
102
103     # Delete a device model
104     def delDeviceModel(self, device, is_virtio_blk = True):
105         result = self.vm.qmp('device_del', id = device)
106         self.assert_qmp(result, 'return', {})
107
108         result = self.vm.qmp('system_reset')
109         self.assert_qmp(result, 'return', {})
110
111         if is_virtio_blk:
112             device_path = '/machine/peripheral/%s/virtio-backend' % device
113             event = self.vm.event_wait(name="DEVICE_DELETED",
114                                        match={'data': {'path': device_path}})
115             self.assertNotEqual(event, None)
116
117         event = self.vm.event_wait(name="DEVICE_DELETED",
118                                    match={'data': {'device': device}})
119         self.assertNotEqual(event, None)
120
121     # Remove a BlockDriverState
122     def ejectDrive(self, device, node, expect_error = False,
123                    destroys_media = True):
124         self.checkBlockDriverState(node)
125         result = self.vm.qmp('eject', id = device)
126         if expect_error:
127             self.assert_qmp(result, 'error/class', 'GenericError')
128             self.checkBlockDriverState(node)
129         else:
130             self.assert_qmp(result, 'return', {})
131             self.checkBlockDriverState(node, not destroys_media)
132
133     # Insert a BlockDriverState
134     def insertDrive(self, device, node):
135         self.checkBlockDriverState(node)
136         result = self.vm.qmp('blockdev-insert-medium',
137                              id = device, node_name = node)
138         self.assert_qmp(result, 'return', {})
139         self.checkBlockDriverState(node)
140
141     # Create a snapshot using 'blockdev-snapshot-sync'
142     def createSnapshotSync(self, node, overlay):
143         self.checkBlockDriverState(node)
144         self.checkBlockDriverState(overlay, False)
145         opts = {'node-name': node,
146                 'snapshot-file': new_img,
147                 'snapshot-node-name': overlay,
148                 'format': iotests.imgfmt}
149         result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts)
150         self.assert_qmp(result, 'return', {})
151         self.checkBlockDriverState(node)
152         self.checkBlockDriverState(overlay)
153
154     # Create a snapshot using 'blockdev-snapshot'
155     def createSnapshot(self, node, overlay):
156         self.checkBlockDriverState(node)
157         self.checkBlockDriverState(overlay)
158         result = self.vm.qmp('blockdev-snapshot',
159                              node = node, overlay = overlay)
160         self.assert_qmp(result, 'return', {})
161         self.checkBlockDriverState(node)
162         self.checkBlockDriverState(overlay)
163
164     # Create a mirror
165     def createMirror(self, node, new_node):
166         self.checkBlockDriverState(new_node, False)
167         opts = {'device': node,
168                 'job-id': node,
169                 'target': new_img,
170                 'node-name': new_node,
171                 'sync': 'top',
172                 'format': iotests.imgfmt}
173         result = self.vm.qmp('drive-mirror', conv_keys=False, **opts)
174         self.assert_qmp(result, 'return', {})
175         self.checkBlockDriverState(new_node)
176
177     # Complete an existing block job
178     def completeBlockJob(self, id, node_before, node_after):
179         result = self.vm.qmp('block-job-complete', device=id)
180         self.assert_qmp(result, 'return', {})
181         self.wait_until_completed(id)
182
183     # Add a BlkDebug node
184     # Note that the purpose of this is to test the blockdev-del
185     # sanity checks, not to create a usable blkdebug drive
186     def addBlkDebug(self, debug, node):
187         self.checkBlockDriverState(node, False)
188         self.checkBlockDriverState(debug, False)
189         image = {'driver': iotests.imgfmt,
190                  'node-name': node,
191                  'file': {'driver': 'file',
192                           'filename': base_img}}
193         opts = {'driver': 'blkdebug',
194                 'node-name': debug,
195                 'image': image}
196         result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
197         self.assert_qmp(result, 'return', {})
198         self.checkBlockDriverState(node)
199         self.checkBlockDriverState(debug)
200
201     # Add a BlkVerify node
202     # Note that the purpose of this is to test the blockdev-del
203     # sanity checks, not to create a usable blkverify drive
204     def addBlkVerify(self, blkverify, test, raw):
205         self.checkBlockDriverState(test, False)
206         self.checkBlockDriverState(raw, False)
207         self.checkBlockDriverState(blkverify, False)
208         iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
209         node_0 = {'driver': iotests.imgfmt,
210                   'node-name': test,
211                   'file': {'driver': 'file',
212                            'filename': base_img}}
213         node_1 = {'driver': iotests.imgfmt,
214                   'node-name': raw,
215                   'file': {'driver': 'file',
216                            'filename': new_img}}
217         opts = {'driver': 'blkverify',
218                 'node-name': blkverify,
219                 'test': node_0,
220                 'raw': node_1}
221         result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
222         self.assert_qmp(result, 'return', {})
223         self.checkBlockDriverState(test)
224         self.checkBlockDriverState(raw)
225         self.checkBlockDriverState(blkverify)
226
227     # Add a Quorum node
228     def addQuorum(self, quorum, child0, child1):
229         self.checkBlockDriverState(child0, False)
230         self.checkBlockDriverState(child1, False)
231         self.checkBlockDriverState(quorum, False)
232         iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
233         child_0 = {'driver': iotests.imgfmt,
234                    'node-name': child0,
235                    'file': {'driver': 'file',
236                             'filename': base_img}}
237         child_1 = {'driver': iotests.imgfmt,
238                    'node-name': child1,
239                    'file': {'driver': 'file',
240                             'filename': new_img}}
241         opts = {'driver': 'quorum',
242                 'node-name': quorum,
243                 'vote-threshold': 1,
244                 'children': [ child_0, child_1 ]}
245         result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
246         self.assert_qmp(result, 'return', {})
247         self.checkBlockDriverState(child0)
248         self.checkBlockDriverState(child1)
249         self.checkBlockDriverState(quorum)
250
251     ########################
252     # The tests start here #
253     ########################
254
255     def testBlockDriverState(self):
256         self.addBlockDriverState('node0')
257         # You cannot delete a file BDS directly
258         self.delBlockDriverState('node0_file', expect_error = True)
259         self.delBlockDriverState('node0')
260
261     def testDeviceModel(self):
262         self.addBlockDriverState('node0')
263         self.addDeviceModel('device0', 'node0')
264         self.ejectDrive('device0', 'node0', expect_error = True)
265         self.delBlockDriverState('node0', expect_error = True)
266         self.delDeviceModel('device0')
267         self.delBlockDriverState('node0')
268
269     def testAttachMedia(self):
270         # This creates a BlockBackend and removes its media
271         self.addBlockDriverState('node0')
272         self.addDeviceModel('device0', 'node0', 'scsi-cd')
273         self.ejectDrive('device0', 'node0', destroys_media = False)
274         self.delBlockDriverState('node0')
275
276         # This creates a new BlockDriverState and inserts it into the device
277         self.addBlockDriverState('node1')
278         self.insertDrive('device0', 'node1')
279         # The node can't be removed: the new device has an extra reference
280         self.delBlockDriverState('node1', expect_error = True)
281         # The BDS still exists after being ejected, but now it can be removed
282         self.ejectDrive('device0', 'node1', destroys_media = False)
283         self.delBlockDriverState('node1')
284         self.delDeviceModel('device0', False)
285
286     def testSnapshotSync(self):
287         self.addBlockDriverState('node0')
288         self.addDeviceModel('device0', 'node0')
289         self.createSnapshotSync('node0', 'overlay0')
290         # This fails because node0 is now being used as a backing image
291         self.delBlockDriverState('node0', expect_error = True)
292         self.delBlockDriverState('overlay0', expect_error = True)
293         # This succeeds because device0 only has the backend reference
294         self.delDeviceModel('device0')
295         # FIXME Would still be there if blockdev-snapshot-sync took a ref
296         self.checkBlockDriverState('overlay0', False)
297         self.delBlockDriverState('node0')
298
299     def testSnapshot(self):
300         self.addBlockDriverState('node0')
301         self.addDeviceModel('device0', 'node0', 'scsi-cd')
302         self.addBlockDriverStateOverlay('overlay0')
303         self.createSnapshot('node0', 'overlay0')
304         self.delBlockDriverState('node0', expect_error = True)
305         self.delBlockDriverState('overlay0', expect_error = True)
306         self.ejectDrive('device0', 'overlay0', destroys_media = False)
307         self.delBlockDriverState('node0', expect_error = True)
308         self.delBlockDriverState('overlay0')
309         self.delBlockDriverState('node0')
310
311     def testMirror(self):
312         self.addBlockDriverState('node0')
313         self.addDeviceModel('device0', 'node0', 'scsi-cd')
314         self.createMirror('node0', 'mirror0')
315         # The block job prevents removing the device
316         self.delBlockDriverState('node0', expect_error = True)
317         self.delBlockDriverState('mirror0', expect_error = True)
318         self.wait_ready('node0')
319         self.completeBlockJob('node0', 'node0', 'mirror0')
320         self.assert_no_active_block_jobs()
321         # This succeeds because the device now points to mirror0
322         self.delBlockDriverState('node0')
323         self.delBlockDriverState('mirror0', expect_error = True)
324         self.delDeviceModel('device0', False)
325         # FIXME mirror0 disappears, drive-mirror doesn't take a reference
326         #self.delBlockDriverState('mirror0')
327
328     def testBlkDebug(self):
329         self.addBlkDebug('debug0', 'node0')
330         # 'node0' is used by the blkdebug node
331         self.delBlockDriverState('node0', expect_error = True)
332         # But we can remove the blkdebug node directly
333         self.delBlockDriverState('debug0')
334         self.checkBlockDriverState('node0', False)
335
336     def testBlkVerify(self):
337         self.addBlkVerify('verify0', 'node0', 'node1')
338         # We cannot remove the children of a blkverify device
339         self.delBlockDriverState('node0', expect_error = True)
340         self.delBlockDriverState('node1', expect_error = True)
341         # But we can remove the blkverify node directly
342         self.delBlockDriverState('verify0')
343         self.checkBlockDriverState('node0', False)
344         self.checkBlockDriverState('node1', False)
345
346     def testQuorum(self):
347         if not iotests.supports_quorum():
348             return
349
350         self.addQuorum('quorum0', 'node0', 'node1')
351         # We cannot remove the children of a Quorum device
352         self.delBlockDriverState('node0', expect_error = True)
353         self.delBlockDriverState('node1', expect_error = True)
354         # But we can remove the Quorum node directly
355         self.delBlockDriverState('quorum0')
356         self.checkBlockDriverState('node0', False)
357         self.checkBlockDriverState('node1', False)
358
359
360 if __name__ == '__main__':
361     iotests.main(supported_fmts=["qcow2"])
This page took 0.046843 seconds and 4 git commands to generate.