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