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