xref: /openbmc/qemu/tests/qemu-iotests/139 (revision 903cb1bf)
1*903cb1bfSPhilippe Mathieu-Daudé#!/usr/bin/env python3
2342075fdSAlberto Garcia#
379b7a77eSMarkus Armbruster# Test cases for the QMP 'blockdev-del' command
4342075fdSAlberto Garcia#
5342075fdSAlberto Garcia# Copyright (C) 2015 Igalia, S.L.
6342075fdSAlberto Garcia# Author: Alberto Garcia <berto@igalia.com>
7342075fdSAlberto Garcia#
8342075fdSAlberto Garcia# This program is free software; you can redistribute it and/or modify
9342075fdSAlberto Garcia# it under the terms of the GNU General Public License as published by
10342075fdSAlberto Garcia# the Free Software Foundation; either version 2 of the License, or
11342075fdSAlberto Garcia# (at your option) any later version.
12342075fdSAlberto Garcia#
13342075fdSAlberto Garcia# This program is distributed in the hope that it will be useful,
14342075fdSAlberto Garcia# but WITHOUT ANY WARRANTY; without even the implied warranty of
15342075fdSAlberto Garcia# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16342075fdSAlberto Garcia# GNU General Public License for more details.
17342075fdSAlberto Garcia#
18342075fdSAlberto Garcia# You should have received a copy of the GNU General Public License
19342075fdSAlberto Garcia# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20342075fdSAlberto Garcia#
21342075fdSAlberto Garcia
22342075fdSAlberto Garciaimport os
23342075fdSAlberto Garciaimport iotests
24342075fdSAlberto Garciaimport time
25342075fdSAlberto Garcia
26342075fdSAlberto Garciabase_img = os.path.join(iotests.test_dir, 'base.img')
27342075fdSAlberto Garcianew_img = os.path.join(iotests.test_dir, 'new.img')
28f1d5516aSCornelia Huckif iotests.qemu_default_machine == 's390-ccw-virtio':
29f1d5516aSCornelia Huck    default_virtio_blk = 'virtio-blk-ccw'
30f1d5516aSCornelia Huckelse:
31f1d5516aSCornelia Huck    default_virtio_blk = 'virtio-blk-pci'
32342075fdSAlberto Garcia
33342075fdSAlberto Garciaclass TestBlockdevDel(iotests.QMPTestCase):
34342075fdSAlberto Garcia
35342075fdSAlberto Garcia    def setUp(self):
36342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
37342075fdSAlberto Garcia        self.vm = iotests.VM()
38f357576fSJohn Snow        self.vm.add_device("{},id=virtio-scsi".format(
39f357576fSJohn Snow            iotests.get_virtio_scsi_device()))
40342075fdSAlberto Garcia        self.vm.launch()
41342075fdSAlberto Garcia
42342075fdSAlberto Garcia    def tearDown(self):
43342075fdSAlberto Garcia        self.vm.shutdown()
44342075fdSAlberto Garcia        os.remove(base_img)
45342075fdSAlberto Garcia        if os.path.isfile(new_img):
46342075fdSAlberto Garcia            os.remove(new_img)
47342075fdSAlberto Garcia
48342075fdSAlberto Garcia    # Check whether a BlockDriverState exists
49342075fdSAlberto Garcia    def checkBlockDriverState(self, node, must_exist = True):
50342075fdSAlberto Garcia        result = self.vm.qmp('query-named-block-nodes')
5168474776SMax Reitz        nodes = [x for x in result['return'] if x['node-name'] == node]
52342075fdSAlberto Garcia        self.assertLessEqual(len(nodes), 1)
53342075fdSAlberto Garcia        self.assertEqual(must_exist, len(nodes) == 1)
54342075fdSAlberto Garcia
55342075fdSAlberto Garcia    # Add a BlockDriverState without a BlockBackend
56342075fdSAlberto Garcia    def addBlockDriverState(self, node):
57342075fdSAlberto Garcia        file_node = '%s_file' % node
58342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
59342075fdSAlberto Garcia        self.checkBlockDriverState(file_node, False)
60342075fdSAlberto Garcia        opts = {'driver': iotests.imgfmt,
61342075fdSAlberto Garcia                'node-name': node,
62342075fdSAlberto Garcia                'file': {'driver': 'file',
63342075fdSAlberto Garcia                         'node-name': file_node,
64342075fdSAlberto Garcia                         'filename': base_img}}
650153d2f5SKevin Wolf        result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
66342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
67342075fdSAlberto Garcia        self.checkBlockDriverState(node)
68342075fdSAlberto Garcia        self.checkBlockDriverState(file_node)
69342075fdSAlberto Garcia
70342075fdSAlberto Garcia    # Add a BlockDriverState that will be used as overlay for the base_img BDS
71342075fdSAlberto Garcia    def addBlockDriverStateOverlay(self, node):
72342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
736e6e55f5SJohn Snow        iotests.qemu_img('create', '-u', '-f', iotests.imgfmt,
74342075fdSAlberto Garcia                         '-b', base_img, new_img, '1M')
75342075fdSAlberto Garcia        opts = {'driver': iotests.imgfmt,
76342075fdSAlberto Garcia                'node-name': node,
77c42e8742SMarkus Armbruster                'backing': None,
78342075fdSAlberto Garcia                'file': {'driver': 'file',
79342075fdSAlberto Garcia                         'filename': new_img}}
800153d2f5SKevin Wolf        result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
81342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
82342075fdSAlberto Garcia        self.checkBlockDriverState(node)
83342075fdSAlberto Garcia
84342075fdSAlberto Garcia    # Delete a BlockDriverState
85342075fdSAlberto Garcia    def delBlockDriverState(self, node, expect_error = False):
86342075fdSAlberto Garcia        self.checkBlockDriverState(node)
8779b7a77eSMarkus Armbruster        result = self.vm.qmp('blockdev-del', node_name = node)
88342075fdSAlberto Garcia        if expect_error:
89342075fdSAlberto Garcia            self.assert_qmp(result, 'error/class', 'GenericError')
90342075fdSAlberto Garcia        else:
91342075fdSAlberto Garcia            self.assert_qmp(result, 'return', {})
92342075fdSAlberto Garcia        self.checkBlockDriverState(node, expect_error)
93342075fdSAlberto Garcia
94342075fdSAlberto Garcia    # Add a device model
95f1d5516aSCornelia Huck    def addDeviceModel(self, device, backend, driver = default_virtio_blk):
96342075fdSAlberto Garcia        result = self.vm.qmp('device_add', id = device,
9762acae8aSKevin Wolf                             driver = driver, drive = backend)
98342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
99342075fdSAlberto Garcia
100342075fdSAlberto Garcia    # Delete a device model
10162acae8aSKevin Wolf    def delDeviceModel(self, device, is_virtio_blk = True):
102342075fdSAlberto Garcia        result = self.vm.qmp('device_del', id = device)
103342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
104342075fdSAlberto Garcia
105342075fdSAlberto Garcia        result = self.vm.qmp('system_reset')
106342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
107342075fdSAlberto Garcia
10862acae8aSKevin Wolf        if is_virtio_blk:
109342075fdSAlberto Garcia            device_path = '/machine/peripheral/%s/virtio-backend' % device
110342075fdSAlberto Garcia            event = self.vm.event_wait(name="DEVICE_DELETED",
111342075fdSAlberto Garcia                                       match={'data': {'path': device_path}})
112342075fdSAlberto Garcia            self.assertNotEqual(event, None)
113342075fdSAlberto Garcia
114342075fdSAlberto Garcia        event = self.vm.event_wait(name="DEVICE_DELETED",
115342075fdSAlberto Garcia                                   match={'data': {'device': device}})
116342075fdSAlberto Garcia        self.assertNotEqual(event, None)
117342075fdSAlberto Garcia
118342075fdSAlberto Garcia    # Remove a BlockDriverState
11962acae8aSKevin Wolf    def ejectDrive(self, device, node, expect_error = False,
120342075fdSAlberto Garcia                   destroys_media = True):
121342075fdSAlberto Garcia        self.checkBlockDriverState(node)
12262acae8aSKevin Wolf        result = self.vm.qmp('eject', id = device)
123342075fdSAlberto Garcia        if expect_error:
124342075fdSAlberto Garcia            self.assert_qmp(result, 'error/class', 'GenericError')
125342075fdSAlberto Garcia            self.checkBlockDriverState(node)
126342075fdSAlberto Garcia        else:
127342075fdSAlberto Garcia            self.assert_qmp(result, 'return', {})
128342075fdSAlberto Garcia            self.checkBlockDriverState(node, not destroys_media)
129342075fdSAlberto Garcia
130342075fdSAlberto Garcia    # Insert a BlockDriverState
13162acae8aSKevin Wolf    def insertDrive(self, device, node):
132342075fdSAlberto Garcia        self.checkBlockDriverState(node)
13334ce1111SMax Reitz        result = self.vm.qmp('blockdev-insert-medium',
13462acae8aSKevin Wolf                             id = device, node_name = node)
135342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
136342075fdSAlberto Garcia        self.checkBlockDriverState(node)
137342075fdSAlberto Garcia
138342075fdSAlberto Garcia    # Create a snapshot using 'blockdev-snapshot-sync'
139342075fdSAlberto Garcia    def createSnapshotSync(self, node, overlay):
140342075fdSAlberto Garcia        self.checkBlockDriverState(node)
141342075fdSAlberto Garcia        self.checkBlockDriverState(overlay, False)
142342075fdSAlberto Garcia        opts = {'node-name': node,
143342075fdSAlberto Garcia                'snapshot-file': new_img,
144342075fdSAlberto Garcia                'snapshot-node-name': overlay,
145342075fdSAlberto Garcia                'format': iotests.imgfmt}
146342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts)
147342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
148342075fdSAlberto Garcia        self.checkBlockDriverState(node)
149342075fdSAlberto Garcia        self.checkBlockDriverState(overlay)
150342075fdSAlberto Garcia
151342075fdSAlberto Garcia    # Create a snapshot using 'blockdev-snapshot'
152342075fdSAlberto Garcia    def createSnapshot(self, node, overlay):
153342075fdSAlberto Garcia        self.checkBlockDriverState(node)
154342075fdSAlberto Garcia        self.checkBlockDriverState(overlay)
155342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-snapshot',
156342075fdSAlberto Garcia                             node = node, overlay = overlay)
157342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
158342075fdSAlberto Garcia        self.checkBlockDriverState(node)
159342075fdSAlberto Garcia        self.checkBlockDriverState(overlay)
160342075fdSAlberto Garcia
161342075fdSAlberto Garcia    # Create a mirror
16262acae8aSKevin Wolf    def createMirror(self, node, new_node):
163342075fdSAlberto Garcia        self.checkBlockDriverState(new_node, False)
16462acae8aSKevin Wolf        opts = {'device': node,
16562acae8aSKevin Wolf                'job-id': node,
166342075fdSAlberto Garcia                'target': new_img,
167342075fdSAlberto Garcia                'node-name': new_node,
168342075fdSAlberto Garcia                'sync': 'top',
169342075fdSAlberto Garcia                'format': iotests.imgfmt}
170342075fdSAlberto Garcia        result = self.vm.qmp('drive-mirror', conv_keys=False, **opts)
171342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
172342075fdSAlberto Garcia        self.checkBlockDriverState(new_node)
173342075fdSAlberto Garcia
174342075fdSAlberto Garcia    # Complete an existing block job
17562acae8aSKevin Wolf    def completeBlockJob(self, id, node_before, node_after):
17662acae8aSKevin Wolf        result = self.vm.qmp('block-job-complete', device=id)
177342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
17862acae8aSKevin Wolf        self.wait_until_completed(id)
179342075fdSAlberto Garcia
180342075fdSAlberto Garcia    # Add a BlkDebug node
18179b7a77eSMarkus Armbruster    # Note that the purpose of this is to test the blockdev-del
182342075fdSAlberto Garcia    # sanity checks, not to create a usable blkdebug drive
183342075fdSAlberto Garcia    def addBlkDebug(self, debug, node):
184342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
185342075fdSAlberto Garcia        self.checkBlockDriverState(debug, False)
186342075fdSAlberto Garcia        image = {'driver': iotests.imgfmt,
187342075fdSAlberto Garcia                 'node-name': node,
188342075fdSAlberto Garcia                 'file': {'driver': 'file',
189342075fdSAlberto Garcia                          'filename': base_img}}
190342075fdSAlberto Garcia        opts = {'driver': 'blkdebug',
191342075fdSAlberto Garcia                'node-name': debug,
192342075fdSAlberto Garcia                'image': image}
1930153d2f5SKevin Wolf        result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
194342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
195342075fdSAlberto Garcia        self.checkBlockDriverState(node)
196342075fdSAlberto Garcia        self.checkBlockDriverState(debug)
197342075fdSAlberto Garcia
198342075fdSAlberto Garcia    # Add a BlkVerify node
19979b7a77eSMarkus Armbruster    # Note that the purpose of this is to test the blockdev-del
200342075fdSAlberto Garcia    # sanity checks, not to create a usable blkverify drive
201342075fdSAlberto Garcia    def addBlkVerify(self, blkverify, test, raw):
202342075fdSAlberto Garcia        self.checkBlockDriverState(test, False)
203342075fdSAlberto Garcia        self.checkBlockDriverState(raw, False)
204342075fdSAlberto Garcia        self.checkBlockDriverState(blkverify, False)
205342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
206342075fdSAlberto Garcia        node_0 = {'driver': iotests.imgfmt,
207342075fdSAlberto Garcia                  'node-name': test,
208342075fdSAlberto Garcia                  'file': {'driver': 'file',
209342075fdSAlberto Garcia                           'filename': base_img}}
210342075fdSAlberto Garcia        node_1 = {'driver': iotests.imgfmt,
211342075fdSAlberto Garcia                  'node-name': raw,
212342075fdSAlberto Garcia                  'file': {'driver': 'file',
213342075fdSAlberto Garcia                           'filename': new_img}}
214342075fdSAlberto Garcia        opts = {'driver': 'blkverify',
215342075fdSAlberto Garcia                'node-name': blkverify,
216342075fdSAlberto Garcia                'test': node_0,
217342075fdSAlberto Garcia                'raw': node_1}
2180153d2f5SKevin Wolf        result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
219342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
220342075fdSAlberto Garcia        self.checkBlockDriverState(test)
221342075fdSAlberto Garcia        self.checkBlockDriverState(raw)
222342075fdSAlberto Garcia        self.checkBlockDriverState(blkverify)
223342075fdSAlberto Garcia
224342075fdSAlberto Garcia    # Add a Quorum node
225342075fdSAlberto Garcia    def addQuorum(self, quorum, child0, child1):
226342075fdSAlberto Garcia        self.checkBlockDriverState(child0, False)
227342075fdSAlberto Garcia        self.checkBlockDriverState(child1, False)
228342075fdSAlberto Garcia        self.checkBlockDriverState(quorum, False)
229342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
230342075fdSAlberto Garcia        child_0 = {'driver': iotests.imgfmt,
231342075fdSAlberto Garcia                   'node-name': child0,
232342075fdSAlberto Garcia                   'file': {'driver': 'file',
233342075fdSAlberto Garcia                            'filename': base_img}}
234342075fdSAlberto Garcia        child_1 = {'driver': iotests.imgfmt,
235342075fdSAlberto Garcia                   'node-name': child1,
236342075fdSAlberto Garcia                   'file': {'driver': 'file',
237342075fdSAlberto Garcia                            'filename': new_img}}
238342075fdSAlberto Garcia        opts = {'driver': 'quorum',
239342075fdSAlberto Garcia                'node-name': quorum,
240342075fdSAlberto Garcia                'vote-threshold': 1,
241342075fdSAlberto Garcia                'children': [ child_0, child_1 ]}
2420153d2f5SKevin Wolf        result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
243342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
244342075fdSAlberto Garcia        self.checkBlockDriverState(child0)
245342075fdSAlberto Garcia        self.checkBlockDriverState(child1)
246342075fdSAlberto Garcia        self.checkBlockDriverState(quorum)
247342075fdSAlberto Garcia
248342075fdSAlberto Garcia    ########################
249342075fdSAlberto Garcia    # The tests start here #
250342075fdSAlberto Garcia    ########################
251342075fdSAlberto Garcia
252342075fdSAlberto Garcia    def testBlockDriverState(self):
253342075fdSAlberto Garcia        self.addBlockDriverState('node0')
254342075fdSAlberto Garcia        # You cannot delete a file BDS directly
255342075fdSAlberto Garcia        self.delBlockDriverState('node0_file', expect_error = True)
256342075fdSAlberto Garcia        self.delBlockDriverState('node0')
257342075fdSAlberto Garcia
258342075fdSAlberto Garcia    def testDeviceModel(self):
25962acae8aSKevin Wolf        self.addBlockDriverState('node0')
26062acae8aSKevin Wolf        self.addDeviceModel('device0', 'node0')
26162acae8aSKevin Wolf        self.ejectDrive('device0', 'node0', expect_error = True)
26262acae8aSKevin Wolf        self.delBlockDriverState('node0', expect_error = True)
263342075fdSAlberto Garcia        self.delDeviceModel('device0')
26462acae8aSKevin Wolf        self.delBlockDriverState('node0')
265342075fdSAlberto Garcia
266342075fdSAlberto Garcia    def testAttachMedia(self):
267342075fdSAlberto Garcia        # This creates a BlockBackend and removes its media
26862acae8aSKevin Wolf        self.addBlockDriverState('node0')
26962acae8aSKevin Wolf        self.addDeviceModel('device0', 'node0', 'scsi-cd')
27062acae8aSKevin Wolf        self.ejectDrive('device0', 'node0', destroys_media = False)
27162acae8aSKevin Wolf        self.delBlockDriverState('node0')
27262acae8aSKevin Wolf
27362acae8aSKevin Wolf        # This creates a new BlockDriverState and inserts it into the device
274342075fdSAlberto Garcia        self.addBlockDriverState('node1')
27562acae8aSKevin Wolf        self.insertDrive('device0', 'node1')
27662acae8aSKevin Wolf        # The node can't be removed: the new device has an extra reference
277342075fdSAlberto Garcia        self.delBlockDriverState('node1', expect_error = True)
278342075fdSAlberto Garcia        # The BDS still exists after being ejected, but now it can be removed
27962acae8aSKevin Wolf        self.ejectDrive('device0', 'node1', destroys_media = False)
280342075fdSAlberto Garcia        self.delBlockDriverState('node1')
28162acae8aSKevin Wolf        self.delDeviceModel('device0', False)
282342075fdSAlberto Garcia
283342075fdSAlberto Garcia    def testSnapshotSync(self):
28462acae8aSKevin Wolf        self.addBlockDriverState('node0')
28562acae8aSKevin Wolf        self.addDeviceModel('device0', 'node0')
286342075fdSAlberto Garcia        self.createSnapshotSync('node0', 'overlay0')
287342075fdSAlberto Garcia        # This fails because node0 is now being used as a backing image
288342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
28962acae8aSKevin Wolf        self.delBlockDriverState('overlay0', expect_error = True)
29062acae8aSKevin Wolf        # This succeeds because device0 only has the backend reference
29162acae8aSKevin Wolf        self.delDeviceModel('device0')
29262acae8aSKevin Wolf        # FIXME Would still be there if blockdev-snapshot-sync took a ref
29362acae8aSKevin Wolf        self.checkBlockDriverState('overlay0', False)
29462acae8aSKevin Wolf        self.delBlockDriverState('node0')
295342075fdSAlberto Garcia
296342075fdSAlberto Garcia    def testSnapshot(self):
29762acae8aSKevin Wolf        self.addBlockDriverState('node0')
29862acae8aSKevin Wolf        self.addDeviceModel('device0', 'node0', 'scsi-cd')
299342075fdSAlberto Garcia        self.addBlockDriverStateOverlay('overlay0')
300342075fdSAlberto Garcia        self.createSnapshot('node0', 'overlay0')
301342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
302342075fdSAlberto Garcia        self.delBlockDriverState('overlay0', expect_error = True)
30362acae8aSKevin Wolf        self.ejectDrive('device0', 'overlay0', destroys_media = False)
304342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
305342075fdSAlberto Garcia        self.delBlockDriverState('overlay0')
30662acae8aSKevin Wolf        self.delBlockDriverState('node0')
307342075fdSAlberto Garcia
308342075fdSAlberto Garcia    def testMirror(self):
30962acae8aSKevin Wolf        self.addBlockDriverState('node0')
31062acae8aSKevin Wolf        self.addDeviceModel('device0', 'node0', 'scsi-cd')
31162acae8aSKevin Wolf        self.createMirror('node0', 'mirror0')
312342075fdSAlberto Garcia        # The block job prevents removing the device
313342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
314342075fdSAlberto Garcia        self.delBlockDriverState('mirror0', expect_error = True)
31562acae8aSKevin Wolf        self.wait_ready('node0')
31662acae8aSKevin Wolf        self.completeBlockJob('node0', 'node0', 'mirror0')
317342075fdSAlberto Garcia        self.assert_no_active_block_jobs()
31862acae8aSKevin Wolf        # This succeeds because the device now points to mirror0
31962acae8aSKevin Wolf        self.delBlockDriverState('node0')
32062acae8aSKevin Wolf        self.delBlockDriverState('mirror0', expect_error = True)
32162acae8aSKevin Wolf        self.delDeviceModel('device0', False)
32262acae8aSKevin Wolf        # FIXME mirror0 disappears, drive-mirror doesn't take a reference
32362acae8aSKevin Wolf        #self.delBlockDriverState('mirror0')
324342075fdSAlberto Garcia
325d9df28e7SAndrey Shinkevich    @iotests.skip_if_unsupported(['blkdebug'])
326342075fdSAlberto Garcia    def testBlkDebug(self):
327342075fdSAlberto Garcia        self.addBlkDebug('debug0', 'node0')
328342075fdSAlberto Garcia        # 'node0' is used by the blkdebug node
329342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
330342075fdSAlberto Garcia        # But we can remove the blkdebug node directly
331342075fdSAlberto Garcia        self.delBlockDriverState('debug0')
332342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
333342075fdSAlberto Garcia
334d9df28e7SAndrey Shinkevich    @iotests.skip_if_unsupported(['blkverify'])
335342075fdSAlberto Garcia    def testBlkVerify(self):
336342075fdSAlberto Garcia        self.addBlkVerify('verify0', 'node0', 'node1')
337342075fdSAlberto Garcia        # We cannot remove the children of a blkverify device
338342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
339342075fdSAlberto Garcia        self.delBlockDriverState('node1', expect_error = True)
340342075fdSAlberto Garcia        # But we can remove the blkverify node directly
341342075fdSAlberto Garcia        self.delBlockDriverState('verify0')
342342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
343342075fdSAlberto Garcia        self.checkBlockDriverState('node1', False)
344342075fdSAlberto Garcia
345d9df28e7SAndrey Shinkevich    @iotests.skip_if_unsupported(['quorum'])
346342075fdSAlberto Garcia    def testQuorum(self):
347b0f90495SAlberto Garcia        if not iotests.supports_quorum():
34892e68987SAlberto Garcia            return
349b0f90495SAlberto Garcia
350342075fdSAlberto Garcia        self.addQuorum('quorum0', 'node0', 'node1')
351342075fdSAlberto Garcia        # We cannot remove the children of a Quorum device
352342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
353342075fdSAlberto Garcia        self.delBlockDriverState('node1', expect_error = True)
354342075fdSAlberto Garcia        # But we can remove the Quorum node directly
355342075fdSAlberto Garcia        self.delBlockDriverState('quorum0')
356342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
357342075fdSAlberto Garcia        self.checkBlockDriverState('node1', False)
358342075fdSAlberto Garcia
359342075fdSAlberto Garcia
360342075fdSAlberto Garciaif __name__ == '__main__':
361103cbc77SMax Reitz    iotests.main(supported_fmts=["qcow2"],
362103cbc77SMax Reitz                 supported_protocols=["file"])
363