xref: /qemu/tests/qemu-iotests/139 (revision 92e68987745b0f89f04d29fe1d0c821010d58ea6)
1342075fdSAlberto Garcia#!/usr/bin/env python
2342075fdSAlberto Garcia#
3342075fdSAlberto Garcia# Test cases for the QMP 'x-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')
28342075fdSAlberto Garcia
29342075fdSAlberto Garciaclass TestBlockdevDel(iotests.QMPTestCase):
30342075fdSAlberto Garcia
31342075fdSAlberto Garcia    def setUp(self):
32342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
33342075fdSAlberto Garcia        self.vm = iotests.VM()
34342075fdSAlberto Garcia        self.vm.launch()
35342075fdSAlberto Garcia
36342075fdSAlberto Garcia    def tearDown(self):
37342075fdSAlberto Garcia        self.vm.shutdown()
38342075fdSAlberto Garcia        os.remove(base_img)
39342075fdSAlberto Garcia        if os.path.isfile(new_img):
40342075fdSAlberto Garcia            os.remove(new_img)
41342075fdSAlberto Garcia
42342075fdSAlberto Garcia    # Check whether a BlockBackend exists
43342075fdSAlberto Garcia    def checkBlockBackend(self, backend, node, must_exist = True):
44342075fdSAlberto Garcia        result = self.vm.qmp('query-block')
45342075fdSAlberto Garcia        backends = filter(lambda x: x['device'] == backend, result['return'])
46342075fdSAlberto Garcia        self.assertLessEqual(len(backends), 1)
47342075fdSAlberto Garcia        self.assertEqual(must_exist, len(backends) == 1)
48342075fdSAlberto Garcia        if must_exist:
49342075fdSAlberto Garcia            if node:
50342075fdSAlberto Garcia                self.assertEqual(backends[0]['inserted']['node-name'], node)
51342075fdSAlberto Garcia            else:
52342075fdSAlberto Garcia                self.assertFalse(backends[0].has_key('inserted'))
53342075fdSAlberto Garcia
54342075fdSAlberto Garcia    # Check whether a BlockDriverState exists
55342075fdSAlberto Garcia    def checkBlockDriverState(self, node, must_exist = True):
56342075fdSAlberto Garcia        result = self.vm.qmp('query-named-block-nodes')
57342075fdSAlberto Garcia        nodes = filter(lambda x: x['node-name'] == node, result['return'])
58342075fdSAlberto Garcia        self.assertLessEqual(len(nodes), 1)
59342075fdSAlberto Garcia        self.assertEqual(must_exist, len(nodes) == 1)
60342075fdSAlberto Garcia
61342075fdSAlberto Garcia    # Add a new BlockBackend (with its attached BlockDriverState)
62342075fdSAlberto Garcia    def addBlockBackend(self, backend, node):
63342075fdSAlberto Garcia        file_node = '%s_file' % node
64342075fdSAlberto Garcia        self.checkBlockBackend(backend, node, False)
65342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
66342075fdSAlberto Garcia        self.checkBlockDriverState(file_node, False)
67342075fdSAlberto Garcia        opts = {'driver': iotests.imgfmt,
68342075fdSAlberto Garcia                'id': backend,
69342075fdSAlberto Garcia                'node-name': node,
70342075fdSAlberto Garcia                'file': {'driver': 'file',
71342075fdSAlberto Garcia                         'node-name': file_node,
72342075fdSAlberto Garcia                         'filename': base_img}}
73342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
74342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
75342075fdSAlberto Garcia        self.checkBlockBackend(backend, node)
76342075fdSAlberto Garcia        self.checkBlockDriverState(node)
77342075fdSAlberto Garcia        self.checkBlockDriverState(file_node)
78342075fdSAlberto Garcia
79342075fdSAlberto Garcia    # Add a BlockDriverState without a BlockBackend
80342075fdSAlberto Garcia    def addBlockDriverState(self, node):
81342075fdSAlberto Garcia        file_node = '%s_file' % node
82342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
83342075fdSAlberto Garcia        self.checkBlockDriverState(file_node, False)
84342075fdSAlberto Garcia        opts = {'driver': iotests.imgfmt,
85342075fdSAlberto Garcia                'node-name': node,
86342075fdSAlberto Garcia                'file': {'driver': 'file',
87342075fdSAlberto Garcia                         'node-name': file_node,
88342075fdSAlberto Garcia                         'filename': base_img}}
89342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
90342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
91342075fdSAlberto Garcia        self.checkBlockDriverState(node)
92342075fdSAlberto Garcia        self.checkBlockDriverState(file_node)
93342075fdSAlberto Garcia
94342075fdSAlberto Garcia    # Add a BlockDriverState that will be used as overlay for the base_img BDS
95342075fdSAlberto Garcia    def addBlockDriverStateOverlay(self, node):
96342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
97342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt,
98342075fdSAlberto Garcia                         '-b', base_img, new_img, '1M')
99342075fdSAlberto Garcia        opts = {'driver': iotests.imgfmt,
100342075fdSAlberto Garcia                'node-name': node,
101342075fdSAlberto Garcia                'backing': '',
102342075fdSAlberto Garcia                'file': {'driver': 'file',
103342075fdSAlberto Garcia                         'filename': new_img}}
104342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
105342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
106342075fdSAlberto Garcia        self.checkBlockDriverState(node)
107342075fdSAlberto Garcia
108342075fdSAlberto Garcia    # Delete a BlockBackend
109342075fdSAlberto Garcia    def delBlockBackend(self, backend, node, expect_error = False,
110342075fdSAlberto Garcia                        destroys_media = True):
111342075fdSAlberto Garcia        self.checkBlockBackend(backend, node)
112342075fdSAlberto Garcia        if node:
113342075fdSAlberto Garcia            self.checkBlockDriverState(node)
114342075fdSAlberto Garcia        result = self.vm.qmp('x-blockdev-del', id = backend)
115342075fdSAlberto Garcia        if expect_error:
116342075fdSAlberto Garcia            self.assert_qmp(result, 'error/class', 'GenericError')
117342075fdSAlberto Garcia            if node:
118342075fdSAlberto Garcia                self.checkBlockDriverState(node)
119342075fdSAlberto Garcia        else:
120342075fdSAlberto Garcia            self.assert_qmp(result, 'return', {})
121342075fdSAlberto Garcia            if node:
122342075fdSAlberto Garcia                self.checkBlockDriverState(node, not destroys_media)
123342075fdSAlberto Garcia        self.checkBlockBackend(backend, node, must_exist = expect_error)
124342075fdSAlberto Garcia
125342075fdSAlberto Garcia    # Delete a BlockDriverState
126342075fdSAlberto Garcia    def delBlockDriverState(self, node, expect_error = False):
127342075fdSAlberto Garcia        self.checkBlockDriverState(node)
128342075fdSAlberto Garcia        result = self.vm.qmp('x-blockdev-del', node_name = node)
129342075fdSAlberto Garcia        if expect_error:
130342075fdSAlberto Garcia            self.assert_qmp(result, 'error/class', 'GenericError')
131342075fdSAlberto Garcia        else:
132342075fdSAlberto Garcia            self.assert_qmp(result, 'return', {})
133342075fdSAlberto Garcia        self.checkBlockDriverState(node, expect_error)
134342075fdSAlberto Garcia
135342075fdSAlberto Garcia    # Add a device model
136342075fdSAlberto Garcia    def addDeviceModel(self, device, backend):
137342075fdSAlberto Garcia        result = self.vm.qmp('device_add', id = device,
138342075fdSAlberto Garcia                             driver = 'virtio-blk-pci', drive = backend)
139342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
140342075fdSAlberto Garcia
141342075fdSAlberto Garcia    # Delete a device model
142342075fdSAlberto Garcia    def delDeviceModel(self, device):
143342075fdSAlberto Garcia        result = self.vm.qmp('device_del', id = device)
144342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
145342075fdSAlberto Garcia
146342075fdSAlberto Garcia        result = self.vm.qmp('system_reset')
147342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
148342075fdSAlberto Garcia
149342075fdSAlberto Garcia        device_path = '/machine/peripheral/%s/virtio-backend' % device
150342075fdSAlberto Garcia        event = self.vm.event_wait(name="DEVICE_DELETED",
151342075fdSAlberto Garcia                                   match={'data': {'path': device_path}})
152342075fdSAlberto Garcia        self.assertNotEqual(event, None)
153342075fdSAlberto Garcia
154342075fdSAlberto Garcia        event = self.vm.event_wait(name="DEVICE_DELETED",
155342075fdSAlberto Garcia                                   match={'data': {'device': device}})
156342075fdSAlberto Garcia        self.assertNotEqual(event, None)
157342075fdSAlberto Garcia
158342075fdSAlberto Garcia    # Remove a BlockDriverState
159342075fdSAlberto Garcia    def ejectDrive(self, backend, node, expect_error = False,
160342075fdSAlberto Garcia                   destroys_media = True):
161342075fdSAlberto Garcia        self.checkBlockBackend(backend, node)
162342075fdSAlberto Garcia        self.checkBlockDriverState(node)
163342075fdSAlberto Garcia        result = self.vm.qmp('eject', device = backend)
164342075fdSAlberto Garcia        if expect_error:
165342075fdSAlberto Garcia            self.assert_qmp(result, 'error/class', 'GenericError')
166342075fdSAlberto Garcia            self.checkBlockDriverState(node)
167342075fdSAlberto Garcia            self.checkBlockBackend(backend, node)
168342075fdSAlberto Garcia        else:
169342075fdSAlberto Garcia            self.assert_qmp(result, 'return', {})
170342075fdSAlberto Garcia            self.checkBlockDriverState(node, not destroys_media)
171342075fdSAlberto Garcia            self.checkBlockBackend(backend, None)
172342075fdSAlberto Garcia
173342075fdSAlberto Garcia    # Insert a BlockDriverState
174342075fdSAlberto Garcia    def insertDrive(self, backend, node):
175342075fdSAlberto Garcia        self.checkBlockBackend(backend, None)
176342075fdSAlberto Garcia        self.checkBlockDriverState(node)
177342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-insert-medium',
178342075fdSAlberto Garcia                             device = backend, node_name = node)
179342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
180342075fdSAlberto Garcia        self.checkBlockBackend(backend, node)
181342075fdSAlberto Garcia        self.checkBlockDriverState(node)
182342075fdSAlberto Garcia
183342075fdSAlberto Garcia    # Create a snapshot using 'blockdev-snapshot-sync'
184342075fdSAlberto Garcia    def createSnapshotSync(self, node, overlay):
185342075fdSAlberto Garcia        self.checkBlockDriverState(node)
186342075fdSAlberto Garcia        self.checkBlockDriverState(overlay, False)
187342075fdSAlberto Garcia        opts = {'node-name': node,
188342075fdSAlberto Garcia                'snapshot-file': new_img,
189342075fdSAlberto Garcia                'snapshot-node-name': overlay,
190342075fdSAlberto Garcia                'format': iotests.imgfmt}
191342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts)
192342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
193342075fdSAlberto Garcia        self.checkBlockDriverState(node)
194342075fdSAlberto Garcia        self.checkBlockDriverState(overlay)
195342075fdSAlberto Garcia
196342075fdSAlberto Garcia    # Create a snapshot using 'blockdev-snapshot'
197342075fdSAlberto Garcia    def createSnapshot(self, node, overlay):
198342075fdSAlberto Garcia        self.checkBlockDriverState(node)
199342075fdSAlberto Garcia        self.checkBlockDriverState(overlay)
200342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-snapshot',
201342075fdSAlberto Garcia                             node = node, overlay = overlay)
202342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
203342075fdSAlberto Garcia        self.checkBlockDriverState(node)
204342075fdSAlberto Garcia        self.checkBlockDriverState(overlay)
205342075fdSAlberto Garcia
206342075fdSAlberto Garcia    # Create a mirror
207342075fdSAlberto Garcia    def createMirror(self, backend, node, new_node):
208342075fdSAlberto Garcia        self.checkBlockBackend(backend, node)
209342075fdSAlberto Garcia        self.checkBlockDriverState(new_node, False)
210342075fdSAlberto Garcia        opts = {'device': backend,
211342075fdSAlberto Garcia                'target': new_img,
212342075fdSAlberto Garcia                'node-name': new_node,
213342075fdSAlberto Garcia                'sync': 'top',
214342075fdSAlberto Garcia                'format': iotests.imgfmt}
215342075fdSAlberto Garcia        result = self.vm.qmp('drive-mirror', conv_keys=False, **opts)
216342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
217342075fdSAlberto Garcia        self.checkBlockBackend(backend, node)
218342075fdSAlberto Garcia        self.checkBlockDriverState(new_node)
219342075fdSAlberto Garcia
220342075fdSAlberto Garcia    # Complete an existing block job
221342075fdSAlberto Garcia    def completeBlockJob(self, backend, node_before, node_after):
222342075fdSAlberto Garcia        self.checkBlockBackend(backend, node_before)
223342075fdSAlberto Garcia        result = self.vm.qmp('block-job-complete', device=backend)
224342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
225342075fdSAlberto Garcia        self.wait_until_completed(backend)
226342075fdSAlberto Garcia        self.checkBlockBackend(backend, node_after)
227342075fdSAlberto Garcia
228342075fdSAlberto Garcia    # Add a BlkDebug node
229342075fdSAlberto Garcia    # Note that the purpose of this is to test the x-blockdev-del
230342075fdSAlberto Garcia    # sanity checks, not to create a usable blkdebug drive
231342075fdSAlberto Garcia    def addBlkDebug(self, debug, node):
232342075fdSAlberto Garcia        self.checkBlockDriverState(node, False)
233342075fdSAlberto Garcia        self.checkBlockDriverState(debug, False)
234342075fdSAlberto Garcia        image = {'driver': iotests.imgfmt,
235342075fdSAlberto Garcia                 'node-name': node,
236342075fdSAlberto Garcia                 'file': {'driver': 'file',
237342075fdSAlberto Garcia                          'filename': base_img}}
238342075fdSAlberto Garcia        opts = {'driver': 'blkdebug',
239342075fdSAlberto Garcia                'node-name': debug,
240342075fdSAlberto Garcia                'image': image}
241342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
242342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
243342075fdSAlberto Garcia        self.checkBlockDriverState(node)
244342075fdSAlberto Garcia        self.checkBlockDriverState(debug)
245342075fdSAlberto Garcia
246342075fdSAlberto Garcia    # Add a BlkVerify node
247342075fdSAlberto Garcia    # Note that the purpose of this is to test the x-blockdev-del
248342075fdSAlberto Garcia    # sanity checks, not to create a usable blkverify drive
249342075fdSAlberto Garcia    def addBlkVerify(self, blkverify, test, raw):
250342075fdSAlberto Garcia        self.checkBlockDriverState(test, False)
251342075fdSAlberto Garcia        self.checkBlockDriverState(raw, False)
252342075fdSAlberto Garcia        self.checkBlockDriverState(blkverify, False)
253342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
254342075fdSAlberto Garcia        node_0 = {'driver': iotests.imgfmt,
255342075fdSAlberto Garcia                  'node-name': test,
256342075fdSAlberto Garcia                  'file': {'driver': 'file',
257342075fdSAlberto Garcia                           'filename': base_img}}
258342075fdSAlberto Garcia        node_1 = {'driver': iotests.imgfmt,
259342075fdSAlberto Garcia                  'node-name': raw,
260342075fdSAlberto Garcia                  'file': {'driver': 'file',
261342075fdSAlberto Garcia                           'filename': new_img}}
262342075fdSAlberto Garcia        opts = {'driver': 'blkverify',
263342075fdSAlberto Garcia                'node-name': blkverify,
264342075fdSAlberto Garcia                'test': node_0,
265342075fdSAlberto Garcia                'raw': node_1}
266342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
267342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
268342075fdSAlberto Garcia        self.checkBlockDriverState(test)
269342075fdSAlberto Garcia        self.checkBlockDriverState(raw)
270342075fdSAlberto Garcia        self.checkBlockDriverState(blkverify)
271342075fdSAlberto Garcia
272342075fdSAlberto Garcia    # Add a Quorum node
273342075fdSAlberto Garcia    def addQuorum(self, quorum, child0, child1):
274342075fdSAlberto Garcia        self.checkBlockDriverState(child0, False)
275342075fdSAlberto Garcia        self.checkBlockDriverState(child1, False)
276342075fdSAlberto Garcia        self.checkBlockDriverState(quorum, False)
277342075fdSAlberto Garcia        iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
278342075fdSAlberto Garcia        child_0 = {'driver': iotests.imgfmt,
279342075fdSAlberto Garcia                   'node-name': child0,
280342075fdSAlberto Garcia                   'file': {'driver': 'file',
281342075fdSAlberto Garcia                            'filename': base_img}}
282342075fdSAlberto Garcia        child_1 = {'driver': iotests.imgfmt,
283342075fdSAlberto Garcia                   'node-name': child1,
284342075fdSAlberto Garcia                   'file': {'driver': 'file',
285342075fdSAlberto Garcia                            'filename': new_img}}
286342075fdSAlberto Garcia        opts = {'driver': 'quorum',
287342075fdSAlberto Garcia                'node-name': quorum,
288342075fdSAlberto Garcia                'vote-threshold': 1,
289342075fdSAlberto Garcia                'children': [ child_0, child_1 ]}
290342075fdSAlberto Garcia        result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
291342075fdSAlberto Garcia        self.assert_qmp(result, 'return', {})
292342075fdSAlberto Garcia        self.checkBlockDriverState(child0)
293342075fdSAlberto Garcia        self.checkBlockDriverState(child1)
294342075fdSAlberto Garcia        self.checkBlockDriverState(quorum)
295342075fdSAlberto Garcia
296342075fdSAlberto Garcia    ########################
297342075fdSAlberto Garcia    # The tests start here #
298342075fdSAlberto Garcia    ########################
299342075fdSAlberto Garcia
300342075fdSAlberto Garcia    def testWrongParameters(self):
301342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
302342075fdSAlberto Garcia        result = self.vm.qmp('x-blockdev-del')
303342075fdSAlberto Garcia        self.assert_qmp(result, 'error/class', 'GenericError')
304342075fdSAlberto Garcia        result = self.vm.qmp('x-blockdev-del', id='drive0', node_name='node0')
305342075fdSAlberto Garcia        self.assert_qmp(result, 'error/class', 'GenericError')
306342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'node0')
307342075fdSAlberto Garcia
308342075fdSAlberto Garcia    def testBlockBackend(self):
309342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
310342075fdSAlberto Garcia        # You cannot delete a BDS that is attached to a backend
311342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
312342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'node0')
313342075fdSAlberto Garcia
314342075fdSAlberto Garcia    def testBlockDriverState(self):
315342075fdSAlberto Garcia        self.addBlockDriverState('node0')
316342075fdSAlberto Garcia        # You cannot delete a file BDS directly
317342075fdSAlberto Garcia        self.delBlockDriverState('node0_file', expect_error = True)
318342075fdSAlberto Garcia        self.delBlockDriverState('node0')
319342075fdSAlberto Garcia
320342075fdSAlberto Garcia    def testEject(self):
321342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
322342075fdSAlberto Garcia        self.ejectDrive('drive0', 'node0')
323342075fdSAlberto Garcia        self.delBlockBackend('drive0', None)
324342075fdSAlberto Garcia
325342075fdSAlberto Garcia    def testDeviceModel(self):
326342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
327342075fdSAlberto Garcia        self.addDeviceModel('device0', 'drive0')
328342075fdSAlberto Garcia        self.ejectDrive('drive0', 'node0', expect_error = True)
329342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'node0', expect_error = True)
330342075fdSAlberto Garcia        self.delDeviceModel('device0')
331342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'node0')
332342075fdSAlberto Garcia
333342075fdSAlberto Garcia    def testAttachMedia(self):
334342075fdSAlberto Garcia        # This creates a BlockBackend and removes its media
335342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
336342075fdSAlberto Garcia        self.ejectDrive('drive0', 'node0')
337342075fdSAlberto Garcia        # This creates a new BlockDriverState and inserts it into the backend
338342075fdSAlberto Garcia        self.addBlockDriverState('node1')
339342075fdSAlberto Garcia        self.insertDrive('drive0', 'node1')
340342075fdSAlberto Garcia        # The backend can't be removed: the new BDS has an extra reference
341342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'node1', expect_error = True)
342342075fdSAlberto Garcia        self.delBlockDriverState('node1', expect_error = True)
343342075fdSAlberto Garcia        # The BDS still exists after being ejected, but now it can be removed
344342075fdSAlberto Garcia        self.ejectDrive('drive0', 'node1', destroys_media = False)
345342075fdSAlberto Garcia        self.delBlockDriverState('node1')
346342075fdSAlberto Garcia        self.delBlockBackend('drive0', None)
347342075fdSAlberto Garcia
348342075fdSAlberto Garcia    def testSnapshotSync(self):
349342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
350342075fdSAlberto Garcia        self.createSnapshotSync('node0', 'overlay0')
351342075fdSAlberto Garcia        # This fails because node0 is now being used as a backing image
352342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
353342075fdSAlberto Garcia        # This succeeds because overlay0 only has the backend reference
354342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'overlay0')
355342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
356342075fdSAlberto Garcia
357342075fdSAlberto Garcia    def testSnapshot(self):
358342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
359342075fdSAlberto Garcia        self.addBlockDriverStateOverlay('overlay0')
360342075fdSAlberto Garcia        self.createSnapshot('node0', 'overlay0')
361342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'overlay0', expect_error = True)
362342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
363342075fdSAlberto Garcia        self.delBlockDriverState('overlay0', expect_error = True)
364342075fdSAlberto Garcia        self.ejectDrive('drive0', 'overlay0', destroys_media = False)
365342075fdSAlberto Garcia        self.delBlockBackend('drive0', None)
366342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
367342075fdSAlberto Garcia        self.delBlockDriverState('overlay0')
368342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
369342075fdSAlberto Garcia
370342075fdSAlberto Garcia    def testMirror(self):
371342075fdSAlberto Garcia        self.addBlockBackend('drive0', 'node0')
372342075fdSAlberto Garcia        self.createMirror('drive0', 'node0', 'mirror0')
373342075fdSAlberto Garcia        # The block job prevents removing the device
374342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'node0', expect_error = True)
375342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
376342075fdSAlberto Garcia        self.delBlockDriverState('mirror0', expect_error = True)
377342075fdSAlberto Garcia        self.wait_ready('drive0')
378342075fdSAlberto Garcia        self.completeBlockJob('drive0', 'node0', 'mirror0')
379342075fdSAlberto Garcia        self.assert_no_active_block_jobs()
380342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
381342075fdSAlberto Garcia        # This succeeds because the backend now points to mirror0
382342075fdSAlberto Garcia        self.delBlockBackend('drive0', 'mirror0')
383342075fdSAlberto Garcia
384342075fdSAlberto Garcia    def testBlkDebug(self):
385342075fdSAlberto Garcia        self.addBlkDebug('debug0', 'node0')
386342075fdSAlberto Garcia        # 'node0' is used by the blkdebug node
387342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
388342075fdSAlberto Garcia        # But we can remove the blkdebug node directly
389342075fdSAlberto Garcia        self.delBlockDriverState('debug0')
390342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
391342075fdSAlberto Garcia
392342075fdSAlberto Garcia    def testBlkVerify(self):
393342075fdSAlberto Garcia        self.addBlkVerify('verify0', 'node0', 'node1')
394342075fdSAlberto Garcia        # We cannot remove the children of a blkverify device
395342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
396342075fdSAlberto Garcia        self.delBlockDriverState('node1', expect_error = True)
397342075fdSAlberto Garcia        # But we can remove the blkverify node directly
398342075fdSAlberto Garcia        self.delBlockDriverState('verify0')
399342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
400342075fdSAlberto Garcia        self.checkBlockDriverState('node1', False)
401342075fdSAlberto Garcia
402342075fdSAlberto Garcia    def testQuorum(self):
403*92e68987SAlberto Garcia        if not 'quorum' in iotests.qemu_img_pipe('--help'):
404*92e68987SAlberto Garcia            return
405342075fdSAlberto Garcia        self.addQuorum('quorum0', 'node0', 'node1')
406342075fdSAlberto Garcia        # We cannot remove the children of a Quorum device
407342075fdSAlberto Garcia        self.delBlockDriverState('node0', expect_error = True)
408342075fdSAlberto Garcia        self.delBlockDriverState('node1', expect_error = True)
409342075fdSAlberto Garcia        # But we can remove the Quorum node directly
410342075fdSAlberto Garcia        self.delBlockDriverState('quorum0')
411342075fdSAlberto Garcia        self.checkBlockDriverState('node0', False)
412342075fdSAlberto Garcia        self.checkBlockDriverState('node1', False)
413342075fdSAlberto Garcia
414342075fdSAlberto Garcia
415342075fdSAlberto Garciaif __name__ == '__main__':
416342075fdSAlberto Garcia    iotests.main(supported_fmts=["qcow2"])
417