xref: /qemu/tests/qemu-iotests/118 (revision e4fd2e9dfca0b592e329eec9ba753914e7941104)
1adfe2030SMax Reitz#!/usr/bin/env python
2adfe2030SMax Reitz#
3adfe2030SMax Reitz# Test case for the QMP 'change' command and all other associated
4adfe2030SMax Reitz# commands
5adfe2030SMax Reitz#
6adfe2030SMax Reitz# Copyright (C) 2015 Red Hat, Inc.
7adfe2030SMax Reitz#
8adfe2030SMax Reitz# This program is free software; you can redistribute it and/or modify
9adfe2030SMax Reitz# it under the terms of the GNU General Public License as published by
10adfe2030SMax Reitz# the Free Software Foundation; either version 2 of the License, or
11adfe2030SMax Reitz# (at your option) any later version.
12adfe2030SMax Reitz#
13adfe2030SMax Reitz# This program is distributed in the hope that it will be useful,
14adfe2030SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of
15adfe2030SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16adfe2030SMax Reitz# GNU General Public License for more details.
17adfe2030SMax Reitz#
18adfe2030SMax Reitz# You should have received a copy of the GNU General Public License
19adfe2030SMax Reitz# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20adfe2030SMax Reitz#
21adfe2030SMax Reitz
22adfe2030SMax Reitzimport os
23adfe2030SMax Reitzimport stat
24adfe2030SMax Reitzimport time
25adfe2030SMax Reitzimport iotests
26adfe2030SMax Reitzfrom iotests import qemu_img
27adfe2030SMax Reitz
28adfe2030SMax Reitzold_img = os.path.join(iotests.test_dir, 'test0.img')
29adfe2030SMax Reitznew_img = os.path.join(iotests.test_dir, 'test1.img')
30adfe2030SMax Reitz
31adfe2030SMax Reitzclass ChangeBaseClass(iotests.QMPTestCase):
32adfe2030SMax Reitz    has_opened = False
33adfe2030SMax Reitz    has_closed = False
34adfe2030SMax Reitz
35adfe2030SMax Reitz    def process_events(self):
36adfe2030SMax Reitz        for event in self.vm.get_qmp_events(wait=False):
37adfe2030SMax Reitz            if (event['event'] == 'DEVICE_TRAY_MOVED' and
38adfe2030SMax Reitz                event['data']['device'] == 'drive0'):
39adfe2030SMax Reitz                if event['data']['tray-open'] == False:
40adfe2030SMax Reitz                    self.has_closed = True
41adfe2030SMax Reitz                else:
42adfe2030SMax Reitz                    self.has_opened = True
43adfe2030SMax Reitz
44adfe2030SMax Reitz    def wait_for_open(self):
45abb3e55bSMax Reitz        if not self.has_real_tray:
46abb3e55bSMax Reitz            return
47abb3e55bSMax Reitz
48adfe2030SMax Reitz        timeout = time.clock() + 3
49adfe2030SMax Reitz        while not self.has_opened and time.clock() < timeout:
50adfe2030SMax Reitz            self.process_events()
51adfe2030SMax Reitz        if not self.has_opened:
52adfe2030SMax Reitz            self.fail('Timeout while waiting for the tray to open')
53adfe2030SMax Reitz
54adfe2030SMax Reitz    def wait_for_close(self):
55abb3e55bSMax Reitz        if not self.has_real_tray:
56abb3e55bSMax Reitz            return
57abb3e55bSMax Reitz
58adfe2030SMax Reitz        timeout = time.clock() + 3
59adfe2030SMax Reitz        while not self.has_closed and time.clock() < timeout:
60adfe2030SMax Reitz            self.process_events()
61adfe2030SMax Reitz        if not self.has_opened:
62adfe2030SMax Reitz            self.fail('Timeout while waiting for the tray to close')
63adfe2030SMax Reitz
64adfe2030SMax Reitzclass GeneralChangeTestsBaseClass(ChangeBaseClass):
65486b88bdSKevin Wolf
66486b88bdSKevin Wolf    device_name = None
67486b88bdSKevin Wolf
68adfe2030SMax Reitz    def test_change(self):
69adfe2030SMax Reitz        result = self.vm.qmp('change', device='drive0', target=new_img,
70adfe2030SMax Reitz                                       arg=iotests.imgfmt)
71adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
72adfe2030SMax Reitz
73adfe2030SMax Reitz        self.wait_for_open()
74adfe2030SMax Reitz        self.wait_for_close()
75adfe2030SMax Reitz
76adfe2030SMax Reitz        result = self.vm.qmp('query-block')
77abb3e55bSMax Reitz        if self.has_real_tray:
78adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
79adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
80adfe2030SMax Reitz
81adfe2030SMax Reitz    def test_blockdev_change_medium(self):
82486b88bdSKevin Wolf        if self.device_name is not None:
83486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-change-medium',
84486b88bdSKevin Wolf                                 id=self.device_name, filename=new_img,
85adfe2030SMax Reitz                                 format=iotests.imgfmt)
86486b88bdSKevin Wolf        else:
87486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-change-medium',
88486b88bdSKevin Wolf                                 device='drive0', filename=new_img,
89486b88bdSKevin Wolf                                 format=iotests.imgfmt)
90486b88bdSKevin Wolf
91adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
92adfe2030SMax Reitz
93adfe2030SMax Reitz        self.wait_for_open()
94adfe2030SMax Reitz        self.wait_for_close()
95adfe2030SMax Reitz
96adfe2030SMax Reitz        result = self.vm.qmp('query-block')
97abb3e55bSMax Reitz        if self.has_real_tray:
98adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
99adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
100adfe2030SMax Reitz
101adfe2030SMax Reitz    def test_eject(self):
102486b88bdSKevin Wolf        if self.device_name is not None:
103486b88bdSKevin Wolf            result = self.vm.qmp('eject', id=self.device_name, force=True)
104486b88bdSKevin Wolf        else:
105adfe2030SMax Reitz            result = self.vm.qmp('eject', device='drive0', force=True)
106adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
107adfe2030SMax Reitz
108adfe2030SMax Reitz        self.wait_for_open()
109adfe2030SMax Reitz
110adfe2030SMax Reitz        result = self.vm.qmp('query-block')
111abb3e55bSMax Reitz        if self.has_real_tray:
112adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
113adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
114adfe2030SMax Reitz
115adfe2030SMax Reitz    def test_tray_eject_change(self):
116486b88bdSKevin Wolf        if self.device_name is not None:
117486b88bdSKevin Wolf            result = self.vm.qmp('eject', id=self.device_name, force=True)
118486b88bdSKevin Wolf        else:
119adfe2030SMax Reitz            result = self.vm.qmp('eject', device='drive0', force=True)
120adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
121adfe2030SMax Reitz
122adfe2030SMax Reitz        self.wait_for_open()
123adfe2030SMax Reitz
124adfe2030SMax Reitz        result = self.vm.qmp('query-block')
125abb3e55bSMax Reitz        if self.has_real_tray:
126adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
127adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
128adfe2030SMax Reitz
129486b88bdSKevin Wolf        if self.device_name is not None:
130486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
131486b88bdSKevin Wolf                                 filename=new_img, format=iotests.imgfmt)
132486b88bdSKevin Wolf        else:
133adfe2030SMax Reitz            result = self.vm.qmp('blockdev-change-medium', device='drive0',
134486b88bdSKevin Wolf                                 filename=new_img, format=iotests.imgfmt)
135adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
136adfe2030SMax Reitz
137adfe2030SMax Reitz        self.wait_for_close()
138adfe2030SMax Reitz
139adfe2030SMax Reitz        result = self.vm.qmp('query-block')
140abb3e55bSMax Reitz        if self.has_real_tray:
141adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
142adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
143adfe2030SMax Reitz
144adfe2030SMax Reitz    def test_tray_open_close(self):
145486b88bdSKevin Wolf        if self.device_name is not None:
146486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-open-tray',
147486b88bdSKevin Wolf                                 id=self.device_name, force=True)
148486b88bdSKevin Wolf        else:
149486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-open-tray',
150486b88bdSKevin Wolf                                 device='drive0', force=True)
151adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
152adfe2030SMax Reitz
153adfe2030SMax Reitz        self.wait_for_open()
154adfe2030SMax Reitz
155adfe2030SMax Reitz        result = self.vm.qmp('query-block')
156abb3e55bSMax Reitz        if self.has_real_tray:
157adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
158adfe2030SMax Reitz        if self.was_empty == True:
159adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
160adfe2030SMax Reitz        else:
161adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
162adfe2030SMax Reitz
163486b88bdSKevin Wolf        if self.device_name is not None:
164486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
165486b88bdSKevin Wolf        else:
166adfe2030SMax Reitz            result = self.vm.qmp('blockdev-close-tray', device='drive0')
167adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
168adfe2030SMax Reitz
169adfe2030SMax Reitz        if self.has_real_tray or not self.was_empty:
170adfe2030SMax Reitz            self.wait_for_close()
171adfe2030SMax Reitz
172adfe2030SMax Reitz        result = self.vm.qmp('query-block')
173abb3e55bSMax Reitz        if self.has_real_tray:
174adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
175adfe2030SMax Reitz        if self.was_empty == True:
176adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
177adfe2030SMax Reitz        else:
178adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
179adfe2030SMax Reitz
180adfe2030SMax Reitz    def test_tray_eject_close(self):
181adfe2030SMax Reitz        result = self.vm.qmp('eject', device='drive0', force=True)
182adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
183adfe2030SMax Reitz
184adfe2030SMax Reitz        self.wait_for_open()
185adfe2030SMax Reitz
186adfe2030SMax Reitz        result = self.vm.qmp('query-block')
187abb3e55bSMax Reitz        if self.has_real_tray:
188adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
189adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
190adfe2030SMax Reitz
191486b88bdSKevin Wolf        if self.device_name is not None:
192486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
193486b88bdSKevin Wolf        else:
194adfe2030SMax Reitz            result = self.vm.qmp('blockdev-close-tray', device='drive0')
195adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
196adfe2030SMax Reitz
197adfe2030SMax Reitz        self.wait_for_close()
198adfe2030SMax Reitz
199adfe2030SMax Reitz        result = self.vm.qmp('query-block')
200adfe2030SMax Reitz        if self.has_real_tray:
201adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
202adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
203adfe2030SMax Reitz
204adfe2030SMax Reitz    def test_tray_open_change(self):
205adfe2030SMax Reitz        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
206adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
207adfe2030SMax Reitz
208adfe2030SMax Reitz        self.wait_for_open()
209adfe2030SMax Reitz
210adfe2030SMax Reitz        result = self.vm.qmp('query-block')
211abb3e55bSMax Reitz        if self.has_real_tray:
212adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
213adfe2030SMax Reitz        if self.was_empty == True:
214adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
215adfe2030SMax Reitz        else:
216adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
217adfe2030SMax Reitz
218adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium', device='drive0',
219adfe2030SMax Reitz                                                       filename=new_img,
220adfe2030SMax Reitz                                                       format=iotests.imgfmt)
221adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
222adfe2030SMax Reitz
223adfe2030SMax Reitz        self.wait_for_close()
224adfe2030SMax Reitz
225adfe2030SMax Reitz        result = self.vm.qmp('query-block')
226abb3e55bSMax Reitz        if self.has_real_tray:
227adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
228adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
229adfe2030SMax Reitz
230adfe2030SMax Reitz    def test_cycle(self):
231adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
232adfe2030SMax Reitz                             options={'node-name': 'new',
233adfe2030SMax Reitz                                      'driver': iotests.imgfmt,
234adfe2030SMax Reitz                                      'file': {'filename': new_img,
235adfe2030SMax Reitz                                               'driver': 'file'}})
236adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
237adfe2030SMax Reitz
238486b88bdSKevin Wolf        if self.device_name is not None:
239486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-open-tray',
240486b88bdSKevin Wolf                                 id=self.device_name, force=True)
241486b88bdSKevin Wolf        else:
242486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-open-tray',
243486b88bdSKevin Wolf                                 device='drive0', force=True)
244adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
245adfe2030SMax Reitz
246adfe2030SMax Reitz        self.wait_for_open()
247adfe2030SMax Reitz
248adfe2030SMax Reitz        result = self.vm.qmp('query-block')
249abb3e55bSMax Reitz        if self.has_real_tray:
250adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
251adfe2030SMax Reitz        if self.was_empty == True:
252adfe2030SMax Reitz            self.assert_qmp_absent(result, 'return[0]/inserted')
253adfe2030SMax Reitz        else:
254adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
255adfe2030SMax Reitz
256486b88bdSKevin Wolf        if self.device_name is not None:
257486b88bdSKevin Wolf            result = self.vm.qmp('x-blockdev-remove-medium',
258486b88bdSKevin Wolf                                 id=self.device_name)
259486b88bdSKevin Wolf        else:
2606e0abc25SMax Reitz            result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
261adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
262adfe2030SMax Reitz
263adfe2030SMax Reitz        result = self.vm.qmp('query-block')
264abb3e55bSMax Reitz        if self.has_real_tray:
265adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
266adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
267adfe2030SMax Reitz
268486b88bdSKevin Wolf        if self.device_name is not None:
269486b88bdSKevin Wolf            result = self.vm.qmp('x-blockdev-insert-medium',
270486b88bdSKevin Wolf                                 id=self.device_name, node_name='new')
271486b88bdSKevin Wolf        else:
272486b88bdSKevin Wolf            result = self.vm.qmp('x-blockdev-insert-medium',
273486b88bdSKevin Wolf                                 device='drive0', node_name='new')
274adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
275adfe2030SMax Reitz
276adfe2030SMax Reitz        result = self.vm.qmp('query-block')
277abb3e55bSMax Reitz        if self.has_real_tray:
278adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', True)
279adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
280adfe2030SMax Reitz
281486b88bdSKevin Wolf        if self.device_name is not None:
282486b88bdSKevin Wolf            result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
283486b88bdSKevin Wolf        else:
284adfe2030SMax Reitz            result = self.vm.qmp('blockdev-close-tray', device='drive0')
285adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
286adfe2030SMax Reitz
287adfe2030SMax Reitz        self.wait_for_close()
288adfe2030SMax Reitz
289adfe2030SMax Reitz        result = self.vm.qmp('query-block')
290abb3e55bSMax Reitz        if self.has_real_tray:
291adfe2030SMax Reitz            self.assert_qmp(result, 'return[0]/tray_open', False)
292adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
293adfe2030SMax Reitz
294adfe2030SMax Reitz    def test_close_on_closed(self):
295adfe2030SMax Reitz        result = self.vm.qmp('blockdev-close-tray', device='drive0')
296adfe2030SMax Reitz        # Should be a no-op
297adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
298adfe2030SMax Reitz        self.assertEquals(self.vm.get_qmp_events(wait=False), [])
299adfe2030SMax Reitz
300adfe2030SMax Reitz    def test_remove_on_closed(self):
301abb3e55bSMax Reitz        if not self.has_real_tray:
302adfe2030SMax Reitz            return
303adfe2030SMax Reitz
3046e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
305adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
306adfe2030SMax Reitz
307adfe2030SMax Reitz    def test_insert_on_closed(self):
308abb3e55bSMax Reitz        if not self.has_real_tray:
309adfe2030SMax Reitz            return
310adfe2030SMax Reitz
311adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
312adfe2030SMax Reitz                             options={'node-name': 'new',
313adfe2030SMax Reitz                                      'driver': iotests.imgfmt,
314adfe2030SMax Reitz                                      'file': {'filename': new_img,
315adfe2030SMax Reitz                                               'driver': 'file'}})
316adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
317adfe2030SMax Reitz
3186e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
319adfe2030SMax Reitz                                                       node_name='new')
320adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
321adfe2030SMax Reitz
322adfe2030SMax Reitzclass TestInitiallyFilled(GeneralChangeTestsBaseClass):
323adfe2030SMax Reitz    was_empty = False
324adfe2030SMax Reitz
325adfe2030SMax Reitz    def setUp(self, media, interface):
326adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
327adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
328486b88bdSKevin Wolf        self.vm = iotests.VM()
329486b88bdSKevin Wolf        if interface == 'ide':
330486b88bdSKevin Wolf            self.device_name = 'qdev0'
331486b88bdSKevin Wolf            self.vm.add_drive(old_img, 'media=%s' % media, 'none')
332486b88bdSKevin Wolf            self.vm.add_device('ide-cd,drive=drive0,id=%s' % self.device_name)
333486b88bdSKevin Wolf        else:
334486b88bdSKevin Wolf            self.vm.add_drive(old_img, 'media=%s' % media, interface)
335adfe2030SMax Reitz        self.vm.launch()
336adfe2030SMax Reitz
337adfe2030SMax Reitz    def tearDown(self):
338adfe2030SMax Reitz        self.vm.shutdown()
339adfe2030SMax Reitz        os.remove(old_img)
340adfe2030SMax Reitz        os.remove(new_img)
341adfe2030SMax Reitz
342adfe2030SMax Reitz    def test_insert_on_filled(self):
343adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
344adfe2030SMax Reitz                             options={'node-name': 'new',
345adfe2030SMax Reitz                                      'driver': iotests.imgfmt,
346adfe2030SMax Reitz                                      'file': {'filename': new_img,
347adfe2030SMax Reitz                                               'driver': 'file'}})
348adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
349adfe2030SMax Reitz
350adfe2030SMax Reitz        result = self.vm.qmp('blockdev-open-tray', device='drive0')
351adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
352adfe2030SMax Reitz
353adfe2030SMax Reitz        self.wait_for_open()
354adfe2030SMax Reitz
3556e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
356adfe2030SMax Reitz                                                       node_name='new')
357adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
358adfe2030SMax Reitz
359adfe2030SMax Reitzclass TestInitiallyEmpty(GeneralChangeTestsBaseClass):
360adfe2030SMax Reitz    was_empty = True
361adfe2030SMax Reitz
362adfe2030SMax Reitz    def setUp(self, media, interface):
363adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
364adfe2030SMax Reitz        self.vm = iotests.VM().add_drive(None, 'media=%s' % media, interface)
365adfe2030SMax Reitz        self.vm.launch()
366adfe2030SMax Reitz
367adfe2030SMax Reitz    def tearDown(self):
368adfe2030SMax Reitz        self.vm.shutdown()
369adfe2030SMax Reitz        os.remove(new_img)
370adfe2030SMax Reitz
371adfe2030SMax Reitz    def test_remove_on_empty(self):
372adfe2030SMax Reitz        result = self.vm.qmp('blockdev-open-tray', device='drive0')
373adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
374adfe2030SMax Reitz
375adfe2030SMax Reitz        self.wait_for_open()
376adfe2030SMax Reitz
3776e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
378adfe2030SMax Reitz        # Should be a no-op
379adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
380adfe2030SMax Reitz
381adfe2030SMax Reitzclass TestCDInitiallyFilled(TestInitiallyFilled):
382adfe2030SMax Reitz    TestInitiallyFilled = TestInitiallyFilled
383adfe2030SMax Reitz    has_real_tray = True
384adfe2030SMax Reitz
385adfe2030SMax Reitz    def setUp(self):
386adfe2030SMax Reitz        self.TestInitiallyFilled.setUp(self, 'cdrom', 'ide')
387adfe2030SMax Reitz
388adfe2030SMax Reitzclass TestCDInitiallyEmpty(TestInitiallyEmpty):
389adfe2030SMax Reitz    TestInitiallyEmpty = TestInitiallyEmpty
390adfe2030SMax Reitz    has_real_tray = True
391adfe2030SMax Reitz
392adfe2030SMax Reitz    def setUp(self):
393adfe2030SMax Reitz        self.TestInitiallyEmpty.setUp(self, 'cdrom', 'ide')
394adfe2030SMax Reitz
395adfe2030SMax Reitzclass TestFloppyInitiallyFilled(TestInitiallyFilled):
396adfe2030SMax Reitz    TestInitiallyFilled = TestInitiallyFilled
397adfe2030SMax Reitz    has_real_tray = False
398adfe2030SMax Reitz
399adfe2030SMax Reitz    def setUp(self):
400adfe2030SMax Reitz        self.TestInitiallyFilled.setUp(self, 'disk', 'floppy')
401adfe2030SMax Reitz
402adfe2030SMax Reitzclass TestFloppyInitiallyEmpty(TestInitiallyEmpty):
403adfe2030SMax Reitz    TestInitiallyEmpty = TestInitiallyEmpty
404adfe2030SMax Reitz    has_real_tray = False
405adfe2030SMax Reitz
406adfe2030SMax Reitz    def setUp(self):
407adfe2030SMax Reitz        self.TestInitiallyEmpty.setUp(self, 'disk', 'floppy')
408adfe2030SMax Reitz        # FDDs not having a real tray and there not being a medium inside the
409adfe2030SMax Reitz        # tray at startup means the tray will be considered open
410adfe2030SMax Reitz        self.has_opened = True
411adfe2030SMax Reitz
412adfe2030SMax Reitzclass TestChangeReadOnly(ChangeBaseClass):
413adfe2030SMax Reitz    def setUp(self):
414adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
415adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
416adfe2030SMax Reitz        self.vm = iotests.VM()
417adfe2030SMax Reitz
418adfe2030SMax Reitz    def tearDown(self):
419adfe2030SMax Reitz        self.vm.shutdown()
420adfe2030SMax Reitz        os.chmod(old_img, 0666)
421adfe2030SMax Reitz        os.chmod(new_img, 0666)
422adfe2030SMax Reitz        os.remove(old_img)
423adfe2030SMax Reitz        os.remove(new_img)
424adfe2030SMax Reitz
425adfe2030SMax Reitz    def test_ro_ro_retain(self):
426adfe2030SMax Reitz        os.chmod(old_img, 0444)
427adfe2030SMax Reitz        os.chmod(new_img, 0444)
428adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
429adfe2030SMax Reitz        self.vm.launch()
430adfe2030SMax Reitz
431adfe2030SMax Reitz        result = self.vm.qmp('query-block')
432adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
433adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
434adfe2030SMax Reitz
435adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium', device='drive0',
436adfe2030SMax Reitz                                                       filename=new_img,
437adfe2030SMax Reitz                                                       format=iotests.imgfmt,
438adfe2030SMax Reitz                                                       read_only_mode='retain')
439adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
440adfe2030SMax Reitz
441adfe2030SMax Reitz        result = self.vm.qmp('query-block')
442adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
443adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
444adfe2030SMax Reitz
445adfe2030SMax Reitz    def test_ro_rw_retain(self):
446adfe2030SMax Reitz        os.chmod(old_img, 0444)
447adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
448adfe2030SMax Reitz        self.vm.launch()
449adfe2030SMax Reitz
450adfe2030SMax Reitz        result = self.vm.qmp('query-block')
451adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
452adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
453adfe2030SMax Reitz
454adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium', device='drive0',
455adfe2030SMax Reitz                                                       filename=new_img,
456adfe2030SMax Reitz                                                       format=iotests.imgfmt,
457adfe2030SMax Reitz                                                       read_only_mode='retain')
458adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
459adfe2030SMax Reitz
460adfe2030SMax Reitz        result = self.vm.qmp('query-block')
461adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
462adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
463adfe2030SMax Reitz
464adfe2030SMax Reitz    def test_rw_ro_retain(self):
465adfe2030SMax Reitz        os.chmod(new_img, 0444)
466adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'floppy')
467adfe2030SMax Reitz        self.vm.launch()
468adfe2030SMax Reitz
469adfe2030SMax Reitz        result = self.vm.qmp('query-block')
470adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
471adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
472adfe2030SMax Reitz
473adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium', device='drive0',
474adfe2030SMax Reitz                                                       filename=new_img,
475adfe2030SMax Reitz                                                       format=iotests.imgfmt,
476adfe2030SMax Reitz                                                       read_only_mode='retain')
477adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
478adfe2030SMax Reitz
479adfe2030SMax Reitz        self.assertEquals(self.vm.get_qmp_events(wait=False), [])
480adfe2030SMax Reitz
481adfe2030SMax Reitz        result = self.vm.qmp('query-block')
482adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
483adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
484adfe2030SMax Reitz
485adfe2030SMax Reitz    def test_ro_rw(self):
486adfe2030SMax Reitz        os.chmod(old_img, 0444)
487adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
488adfe2030SMax Reitz        self.vm.launch()
489adfe2030SMax Reitz
490adfe2030SMax Reitz        result = self.vm.qmp('query-block')
491adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
492adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
493adfe2030SMax Reitz
494adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
495adfe2030SMax Reitz                             device='drive0',
496adfe2030SMax Reitz                             filename=new_img,
497adfe2030SMax Reitz                             format=iotests.imgfmt,
498adfe2030SMax Reitz                             read_only_mode='read-write')
499adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
500adfe2030SMax Reitz
501adfe2030SMax Reitz        result = self.vm.qmp('query-block')
502adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
503adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
504adfe2030SMax Reitz
505adfe2030SMax Reitz    def test_rw_ro(self):
506adfe2030SMax Reitz        os.chmod(new_img, 0444)
507adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'floppy')
508adfe2030SMax Reitz        self.vm.launch()
509adfe2030SMax Reitz
510adfe2030SMax Reitz        result = self.vm.qmp('query-block')
511adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
512adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
513adfe2030SMax Reitz
514adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
515adfe2030SMax Reitz                             device='drive0',
516adfe2030SMax Reitz                             filename=new_img,
517adfe2030SMax Reitz                             format=iotests.imgfmt,
518adfe2030SMax Reitz                             read_only_mode='read-only')
519adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
520adfe2030SMax Reitz
521adfe2030SMax Reitz        result = self.vm.qmp('query-block')
522adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
523adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
524adfe2030SMax Reitz
525adfe2030SMax Reitz    def test_make_rw_ro(self):
526adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'floppy')
527adfe2030SMax Reitz        self.vm.launch()
528adfe2030SMax Reitz
529adfe2030SMax Reitz        result = self.vm.qmp('query-block')
530adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
531adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
532adfe2030SMax Reitz
533adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
534adfe2030SMax Reitz                             device='drive0',
535adfe2030SMax Reitz                             filename=new_img,
536adfe2030SMax Reitz                             format=iotests.imgfmt,
537adfe2030SMax Reitz                             read_only_mode='read-only')
538adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
539adfe2030SMax Reitz
540adfe2030SMax Reitz        result = self.vm.qmp('query-block')
541adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
542adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
543adfe2030SMax Reitz
544adfe2030SMax Reitz    def test_make_ro_rw(self):
545adfe2030SMax Reitz        os.chmod(new_img, 0444)
546adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'floppy')
547adfe2030SMax Reitz        self.vm.launch()
548adfe2030SMax Reitz
549adfe2030SMax Reitz        result = self.vm.qmp('query-block')
550adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
551adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
552adfe2030SMax Reitz
553adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium',
554adfe2030SMax Reitz                             device='drive0',
555adfe2030SMax Reitz                             filename=new_img,
556adfe2030SMax Reitz                             format=iotests.imgfmt,
557adfe2030SMax Reitz                             read_only_mode='read-write')
558adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
559adfe2030SMax Reitz
560adfe2030SMax Reitz        result = self.vm.qmp('query-block')
561adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
562adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
563adfe2030SMax Reitz
564adfe2030SMax Reitz    def test_make_rw_ro_by_retain(self):
565adfe2030SMax Reitz        os.chmod(old_img, 0444)
566adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
567adfe2030SMax Reitz        self.vm.launch()
568adfe2030SMax Reitz
569adfe2030SMax Reitz        result = self.vm.qmp('query-block')
570adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
571adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
572adfe2030SMax Reitz
573adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium', device='drive0',
574adfe2030SMax Reitz                                                       filename=new_img,
575adfe2030SMax Reitz                                                       format=iotests.imgfmt,
576adfe2030SMax Reitz                                                       read_only_mode='retain')
577adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
578adfe2030SMax Reitz
579adfe2030SMax Reitz        result = self.vm.qmp('query-block')
580adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
581adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
582adfe2030SMax Reitz
583adfe2030SMax Reitz    def test_make_ro_rw_by_retain(self):
584adfe2030SMax Reitz        os.chmod(new_img, 0444)
585adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'floppy')
586adfe2030SMax Reitz        self.vm.launch()
587adfe2030SMax Reitz
588adfe2030SMax Reitz        result = self.vm.qmp('query-block')
589adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
590adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
591adfe2030SMax Reitz
592adfe2030SMax Reitz        result = self.vm.qmp('blockdev-change-medium', device='drive0',
593adfe2030SMax Reitz                                                       filename=new_img,
594adfe2030SMax Reitz                                                       format=iotests.imgfmt,
595adfe2030SMax Reitz                                                       read_only_mode='retain')
596adfe2030SMax Reitz        self.assert_qmp(result, 'error/class', 'GenericError')
597adfe2030SMax Reitz
598adfe2030SMax Reitz        result = self.vm.qmp('query-block')
599adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
600adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
601adfe2030SMax Reitz
602adfe2030SMax Reitz    def test_rw_ro_cycle(self):
603adfe2030SMax Reitz        os.chmod(new_img, 0444)
604adfe2030SMax Reitz        self.vm.add_drive(old_img, 'media=disk', 'floppy')
605adfe2030SMax Reitz        self.vm.launch()
606adfe2030SMax Reitz
607adfe2030SMax Reitz        result = self.vm.qmp('query-block')
608adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
609adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
610adfe2030SMax Reitz
611adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
612adfe2030SMax Reitz                             options={'node-name': 'new',
613adfe2030SMax Reitz                                      'driver': iotests.imgfmt,
614adfe2030SMax Reitz                                      'read-only': True,
615adfe2030SMax Reitz                                      'file': {'filename': new_img,
616adfe2030SMax Reitz                                               'driver': 'file'}})
617adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
618adfe2030SMax Reitz
619adfe2030SMax Reitz        result = self.vm.qmp('query-block')
620adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', False)
621adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
622adfe2030SMax Reitz
6236e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
624adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
625adfe2030SMax Reitz
626adfe2030SMax Reitz        result = self.vm.qmp('query-block')
627adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
628adfe2030SMax Reitz
6296e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
630adfe2030SMax Reitz                                                       node_name='new')
631adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
632adfe2030SMax Reitz
633adfe2030SMax Reitz        result = self.vm.qmp('query-block')
634adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
635adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
636adfe2030SMax Reitz
637adfe2030SMax Reitz        result = self.vm.qmp('query-block')
638adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/ro', True)
639adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
640adfe2030SMax Reitz
641adfe2030SMax ReitzGeneralChangeTestsBaseClass = None
642adfe2030SMax ReitzTestInitiallyFilled = None
643adfe2030SMax ReitzTestInitiallyEmpty = None
644adfe2030SMax Reitz
645adfe2030SMax Reitz
646adfe2030SMax Reitzclass TestBlockJobsAfterCycle(ChangeBaseClass):
647adfe2030SMax Reitz    def setUp(self):
648adfe2030SMax Reitz        qemu_img('create', '-f', iotests.imgfmt, old_img, '1M')
649adfe2030SMax Reitz
650adfe2030SMax Reitz        self.vm = iotests.VM()
651*e4fd2e9dSKevin Wolf        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
652adfe2030SMax Reitz        self.vm.launch()
653adfe2030SMax Reitz
654adfe2030SMax Reitz        result = self.vm.qmp('query-block')
655adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
656adfe2030SMax Reitz
657adfe2030SMax Reitz        # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
658adfe2030SMax Reitz        # is not necessary
6596e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
660adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
661adfe2030SMax Reitz
662adfe2030SMax Reitz        result = self.vm.qmp('query-block')
663adfe2030SMax Reitz        self.assert_qmp_absent(result, 'return[0]/inserted')
664adfe2030SMax Reitz
665adfe2030SMax Reitz        result = self.vm.qmp('blockdev-add',
666adfe2030SMax Reitz                             options={'node-name': 'node0',
667adfe2030SMax Reitz                                      'driver': iotests.imgfmt,
668adfe2030SMax Reitz                                      'file': {'filename': old_img,
669adfe2030SMax Reitz                                               'driver': 'file'}})
670adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
671adfe2030SMax Reitz
6726e0abc25SMax Reitz        result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
673adfe2030SMax Reitz                                                       node_name='node0')
674adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
675adfe2030SMax Reitz
676adfe2030SMax Reitz        result = self.vm.qmp('query-block')
677adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
678adfe2030SMax Reitz
679adfe2030SMax Reitz    def tearDown(self):
680adfe2030SMax Reitz        self.vm.shutdown()
681adfe2030SMax Reitz        os.remove(old_img)
682adfe2030SMax Reitz        try:
683adfe2030SMax Reitz            os.remove(new_img)
684adfe2030SMax Reitz        except OSError:
685adfe2030SMax Reitz            pass
686adfe2030SMax Reitz
687adfe2030SMax Reitz    def test_snapshot_and_commit(self):
688adfe2030SMax Reitz        # We need backing file support
689adfe2030SMax Reitz        if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed':
690adfe2030SMax Reitz            return
691adfe2030SMax Reitz
692adfe2030SMax Reitz        result = self.vm.qmp('blockdev-snapshot-sync', device='drive0',
693adfe2030SMax Reitz                                                       snapshot_file=new_img,
694adfe2030SMax Reitz                                                       format=iotests.imgfmt)
695adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
696adfe2030SMax Reitz
697adfe2030SMax Reitz        result = self.vm.qmp('query-block')
698adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
699adfe2030SMax Reitz        self.assert_qmp(result,
700adfe2030SMax Reitz                        'return[0]/inserted/image/backing-image/filename',
701adfe2030SMax Reitz                        old_img)
702adfe2030SMax Reitz
703adfe2030SMax Reitz        result = self.vm.qmp('block-commit', device='drive0')
704adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
705adfe2030SMax Reitz
706adfe2030SMax Reitz        self.vm.event_wait(name='BLOCK_JOB_READY')
707adfe2030SMax Reitz
708adfe2030SMax Reitz        result = self.vm.qmp('query-block-jobs')
709adfe2030SMax Reitz        self.assert_qmp(result, 'return[0]/device', 'drive0')
710adfe2030SMax Reitz
711adfe2030SMax Reitz        result = self.vm.qmp('block-job-complete', device='drive0')
712adfe2030SMax Reitz        self.assert_qmp(result, 'return', {})
713adfe2030SMax Reitz
714adfe2030SMax Reitz        self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
715adfe2030SMax Reitz
716adfe2030SMax Reitz
717adfe2030SMax Reitzif __name__ == '__main__':
718adfe2030SMax Reitz    if iotests.qemu_default_machine != 'pc':
719adfe2030SMax Reitz        # We need floppy and IDE CD-ROM
720adfe2030SMax Reitz        iotests.notrun('not suitable for this machine type: %s' %
721adfe2030SMax Reitz                       iotests.qemu_default_machine)
722cc8c46b7SMax Reitz    # Need to support image creation
723cc8c46b7SMax Reitz    iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
724cc8c46b7SMax Reitz                                 'vmdk', 'raw', 'vhdx', 'qed'])
725