1#!/usr/bin/env python
2#
3# Test vmdk and file image creation
4#
5# Copyright (C) 2018 Red Hat, Inc.
6#
7# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program.  If not, see <http://www.gnu.org/licenses/>.
21#
22
23import math
24import iotests
25from iotests import imgfmt
26
27iotests.verify_image_format(supported_fmts=['vmdk'])
28
29def blockdev_create(vm, options):
30    result = vm.qmp_log('blockdev-create', job_id='job0', options=options,
31                        filters=[iotests.filter_qmp_testfiles])
32
33    if 'return' in result:
34        assert result['return'] == {}
35        vm.run_job('job0')
36    iotests.log("")
37
38with iotests.FilePath('t.vmdk') as disk_path, \
39     iotests.FilePath('t.vmdk.1') as extent1_path, \
40     iotests.FilePath('t.vmdk.2') as extent2_path, \
41     iotests.FilePath('t.vmdk.3') as extent3_path, \
42     iotests.VM() as vm:
43
44    #
45    # Successful image creation (defaults)
46    #
47    iotests.log("=== Successful image creation (defaults) ===")
48    iotests.log("")
49
50    size = 5 * 1024 * 1024 * 1024
51
52    vm.launch()
53    blockdev_create(vm, { 'driver': 'file',
54                          'filename': disk_path,
55                          'size': 0 })
56
57    vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
58               node_name='imgfile', filters=[iotests.filter_qmp_testfiles])
59
60    blockdev_create(vm, { 'driver': imgfmt,
61                          'file': 'imgfile',
62                          'size': size })
63    vm.shutdown()
64
65    iotests.img_info_log(disk_path)
66
67    #
68    # Successful image creation (inline blockdev-add, explicit defaults)
69    #
70    iotests.log("=== Successful image creation (inline blockdev-add, explicit defaults) ===")
71    iotests.log("")
72
73    # Choose a different size to show that we got a new image
74    size = 64 * 1024 * 1024
75
76    vm.launch()
77    blockdev_create(vm, { 'driver': 'file',
78                          'filename': disk_path,
79                          'size': 0 })
80
81    blockdev_create(vm, { 'driver': imgfmt,
82                          'file': {
83                              'driver': 'file',
84                              'filename': disk_path,
85                          },
86                          'size': size,
87                          'extents': [],
88                          'subformat': 'monolithicSparse',
89                          'adapter-type': 'ide',
90                          'hwversion': '4',
91                          'zeroed-grain': False })
92    vm.shutdown()
93
94    iotests.img_info_log(disk_path)
95
96    #
97    # Successful image creation (non-default options)
98    #
99    iotests.log("=== Successful image creation (with non-default options) ===")
100    iotests.log("")
101
102    # Choose a different size to show that we got a new image
103    size = 32 * 1024 * 1024
104
105    vm.launch()
106    blockdev_create(vm, { 'driver': 'file',
107                          'filename': disk_path,
108                          'size': 0 })
109
110    blockdev_create(vm, { 'driver': imgfmt,
111                          'file': {
112                              'driver': 'file',
113                              'filename': disk_path,
114                          },
115                          'size': size,
116                          'extents': [],
117                          'subformat': 'monolithicSparse',
118                          'adapter-type': 'buslogic',
119                          'zeroed-grain': True })
120    vm.shutdown()
121
122    iotests.img_info_log(disk_path)
123
124    #
125    # Invalid BlockdevRef
126    #
127    iotests.log("=== Invalid BlockdevRef ===")
128    iotests.log("")
129
130    vm.launch()
131    blockdev_create(vm, { 'driver': imgfmt,
132                          'file': "this doesn't exist",
133                          'size': size })
134    vm.shutdown()
135
136    #
137    # Adapter types
138    #
139
140    iotests.log("=== Adapter types ===")
141    iotests.log("")
142
143    vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path))
144
145    # Valid
146    iotests.log("== Valid adapter types ==")
147    iotests.log("")
148
149    vm.launch()
150    for adapter_type in [ 'ide', 'buslogic', 'lsilogic', 'legacyESX' ]:
151        blockdev_create(vm, { 'driver': imgfmt,
152                              'file': 'node0',
153                              'size': size,
154                              'adapter-type': adapter_type })
155    vm.shutdown()
156
157    # Invalid
158    iotests.log("== Invalid adapter types ==")
159    iotests.log("")
160
161    vm.launch()
162    for adapter_type in [ 'foo', 'IDE', 'legacyesx', 1 ]:
163        blockdev_create(vm, { 'driver': imgfmt,
164                              'file': 'node0',
165                              'size': size,
166                              'adapter-type': adapter_type })
167    vm.shutdown()
168
169    #
170    # Other subformats
171    #
172    iotests.log("=== Other subformats ===")
173    iotests.log("")
174
175    for path in [ extent1_path, extent2_path, extent3_path ]:
176        msg = iotests.qemu_img_pipe('create', '-f', imgfmt, path, '0')
177        iotests.log(msg, [iotests.filter_testfiles])
178
179    vm.add_blockdev('driver=file,filename=%s,node-name=ext1' % (extent1_path))
180    vm.add_blockdev('driver=file,filename=%s,node-name=ext2' % (extent2_path))
181    vm.add_blockdev('driver=file,filename=%s,node-name=ext3' % (extent3_path))
182
183    # Missing extent
184    iotests.log("== Missing extent ==")
185    iotests.log("")
186
187    vm.launch()
188    blockdev_create(vm, { 'driver': imgfmt,
189                          'file': 'node0',
190                          'size': size,
191                          'subformat': 'monolithicFlat' })
192    vm.shutdown()
193
194    # Correct extent
195    iotests.log("== Correct extent ==")
196    iotests.log("")
197
198    vm.launch()
199    blockdev_create(vm, { 'driver': imgfmt,
200                          'file': 'node0',
201                          'size': size,
202                          'subformat': 'monolithicFlat',
203                          'extents': ['ext1'] })
204    vm.shutdown()
205
206    # Extra extent
207    iotests.log("== Extra extent ==")
208    iotests.log("")
209
210    vm.launch()
211    blockdev_create(vm, { 'driver': imgfmt,
212                          'file': 'node0',
213                          'size': 512,
214                          'subformat': 'monolithicFlat',
215                          'extents': ['ext1', 'ext2', 'ext3'] })
216    vm.shutdown()
217
218    # Split formats
219    iotests.log("== Split formats ==")
220    iotests.log("")
221
222    for size in [ 512, 1073741824, 2147483648, 5368709120 ]:
223        for subfmt in [ 'twoGbMaxExtentFlat', 'twoGbMaxExtentSparse' ]:
224            iotests.log("= %s %d =" % (subfmt, size))
225            iotests.log("")
226
227            num_extents = int(math.ceil(size / 2.0**31))
228            extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ]
229
230            vm.launch()
231            blockdev_create(vm, { 'driver': imgfmt,
232                                  'file': 'node0',
233                                  'size': size,
234                                  'subformat': subfmt,
235                                  'extents': extents })
236            vm.shutdown()
237
238            iotests.img_info_log(disk_path)
239