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