Merge "Support Stream Optimized VMDKs"
This commit is contained in:
commit
2fa64aea03
|
@ -512,7 +512,7 @@ class VHDXInspector(FileInspector):
|
|||
#
|
||||
# https://www.vmware.com/app/vmdk/?src=vmdk
|
||||
class VMDKInspector(FileInspector):
|
||||
"""vmware VMDK format (monolithicSparse variant only)
|
||||
"""vmware VMDK format (monolithicSparse and streamOptimized variants only)
|
||||
|
||||
This needs to store the 512 byte header and the descriptor region
|
||||
which should be just after that. The descriptor region is some
|
||||
|
@ -582,7 +582,7 @@ class VMDKInspector(FileInspector):
|
|||
vmdktype = descriptor[type_idx:type_end]
|
||||
else:
|
||||
vmdktype = b'formatnotfound'
|
||||
if vmdktype != b'monolithicSparse':
|
||||
if vmdktype not in (b'monolithicSparse', b'streamOptimized'):
|
||||
LOG.warning('Unsupported VMDK format %s', vmdktype)
|
||||
return 0
|
||||
|
||||
|
|
|
@ -51,38 +51,51 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
def _create_img(self, fmt, size):
|
||||
def _create_img(self, fmt, size, subformat=None):
|
||||
if fmt == 'vhd':
|
||||
# QEMU calls the vhd format vpc
|
||||
fmt = 'vpc'
|
||||
|
||||
fn = tempfile.mktemp(prefix='glance-unittest-formatinspector-',
|
||||
opt = ''
|
||||
prefix = 'glance-unittest-formatinspector-'
|
||||
|
||||
if subformat:
|
||||
opt = ' -o subformat=%s' % subformat
|
||||
prefix += subformat + '-'
|
||||
|
||||
fn = tempfile.mktemp(prefix=prefix,
|
||||
suffix='.%s' % fmt)
|
||||
self._created_files.append(fn)
|
||||
subprocess.check_output(
|
||||
'qemu-img create -f %s %s %i' % (fmt, fn, size),
|
||||
'qemu-img create -f %s %s %s %i' % (fmt, opt, fn, size),
|
||||
shell=True)
|
||||
return fn
|
||||
|
||||
def _create_allocated_vmdk(self, size_mb):
|
||||
def _create_allocated_vmdk(self, size_mb, subformat=None):
|
||||
# We need a "big" VMDK file to exercise some parts of the code of the
|
||||
# format_inspector. A way to create one is to first create an empty
|
||||
# file, and then to convert it with the -S 0 option.
|
||||
fn = tempfile.mktemp(prefix='glance-unittest-formatinspector-',
|
||||
suffix='.vmdk')
|
||||
self._created_files.append(fn)
|
||||
zeroes = tempfile.mktemp(prefix='glance-unittest-formatinspector-',
|
||||
suffix='.zero')
|
||||
self._created_files.append(zeroes)
|
||||
|
||||
# Create an empty file
|
||||
if subformat is None:
|
||||
# Matches qemu-img default, see `qemu-img convert -O vmdk -o help`
|
||||
subformat = 'monolithicSparse'
|
||||
|
||||
prefix = 'glance-unittest-formatinspector-%s-' % subformat
|
||||
fn = tempfile.mktemp(prefix=prefix, suffix='.vmdk')
|
||||
self._created_files.append(fn)
|
||||
raw = tempfile.mktemp(prefix=prefix, suffix='.raw')
|
||||
self._created_files.append(raw)
|
||||
|
||||
# Create a file with pseudo-random data, otherwise it will get
|
||||
# compressed in the streamOptimized format
|
||||
subprocess.check_output(
|
||||
'dd if=/dev/zero of=%s bs=1M count=%i' % (zeroes, size_mb),
|
||||
'dd if=/dev/urandom of=%s bs=1M count=%i' % (raw, size_mb),
|
||||
shell=True)
|
||||
|
||||
# Convert it to VMDK
|
||||
subprocess.check_output(
|
||||
'qemu-img convert -f raw -O vmdk -S 0 %s %s' % (zeroes, fn),
|
||||
'qemu-img convert -f raw -O vmdk -o subformat=%s -S 0 %s %s' % (
|
||||
subformat, raw, fn),
|
||||
shell=True)
|
||||
return fn
|
||||
|
||||
|
@ -101,8 +114,9 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
wrapper.close()
|
||||
return fmt
|
||||
|
||||
def _test_format_at_image_size(self, format_name, image_size):
|
||||
img = self._create_img(format_name, image_size)
|
||||
def _test_format_at_image_size(self, format_name, image_size,
|
||||
subformat=None):
|
||||
img = self._create_img(format_name, image_size, subformat=subformat)
|
||||
|
||||
# Some formats have internal alignment restrictions making this not
|
||||
# always exactly like image_size, so get the real value for comparison
|
||||
|
@ -124,11 +138,12 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
'Format used more than 512KiB of memory: %s' % (
|
||||
fmt.context_info))
|
||||
|
||||
def _test_format(self, format_name):
|
||||
def _test_format(self, format_name, subformat=None):
|
||||
# Try a few different image sizes, including some odd and very small
|
||||
# sizes
|
||||
for image_size in (512, 513, 2057, 7):
|
||||
self._test_format_at_image_size(format_name, image_size * units.Mi)
|
||||
self._test_format_at_image_size(format_name, image_size * units.Mi,
|
||||
subformat=subformat)
|
||||
|
||||
def test_qcow2(self):
|
||||
self._test_format('qcow2')
|
||||
|
@ -142,12 +157,15 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
def test_vmdk(self):
|
||||
self._test_format('vmdk')
|
||||
|
||||
def test_vmdk_bad_descriptor_offset(self):
|
||||
def test_vmdk_stream_optimized(self):
|
||||
self._test_format('vmdk', 'streamOptimized')
|
||||
|
||||
def _test_vmdk_bad_descriptor_offset(self, subformat=None):
|
||||
format_name = 'vmdk'
|
||||
image_size = 10 * units.Mi
|
||||
descriptorOffsetAddr = 0x1c
|
||||
BAD_ADDRESS = 0x400
|
||||
img = self._create_img(format_name, image_size)
|
||||
img = self._create_img(format_name, image_size, subformat=subformat)
|
||||
|
||||
# Corrupt the header
|
||||
fd = open(img, 'r+b')
|
||||
|
@ -167,7 +185,13 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
'size %i block %i') % (format_name, image_size,
|
||||
block_size))
|
||||
|
||||
def test_vmdk_bad_descriptor_mem_limit(self):
|
||||
def test_vmdk_bad_descriptor_offset(self):
|
||||
self._test_vmdk_bad_descriptor_offset()
|
||||
|
||||
def test_vmdk_bad_descriptor_offset_stream_optimized(self):
|
||||
self._test_vmdk_bad_descriptor_offset(subformat='streamOptimized')
|
||||
|
||||
def _test_vmdk_bad_descriptor_mem_limit(self, subformat=None):
|
||||
format_name = 'vmdk'
|
||||
image_size = 5 * units.Mi
|
||||
virtual_size = 5 * units.Mi
|
||||
|
@ -176,7 +200,8 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
twoMBInSectors = (2 << 20) // 512
|
||||
# We need a big VMDK because otherwise we will not have enough data to
|
||||
# fill-up the CaptureRegion.
|
||||
img = self._create_allocated_vmdk(image_size // units.Mi)
|
||||
img = self._create_allocated_vmdk(image_size // units.Mi,
|
||||
subformat=subformat)
|
||||
|
||||
# Corrupt the end of descriptor address so it "ends" at 2MB
|
||||
fd = open(img, 'r+b')
|
||||
|
@ -200,6 +225,12 @@ class TestFormatInspectors(test_utils.BaseTestCase):
|
|||
'Format used more than 1.5MiB of memory: %s' % (
|
||||
fmt.context_info))
|
||||
|
||||
def test_vmdk_bad_descriptor_mem_limit(self):
|
||||
self._test_vmdk_bad_descriptor_mem_limit()
|
||||
|
||||
def test_vmdk_bad_descriptor_mem_limit_stream_optimized(self):
|
||||
self._test_vmdk_bad_descriptor_mem_limit(subformat='streamOptimized')
|
||||
|
||||
def test_vdi(self):
|
||||
self._test_format('vdi')
|
||||
|
||||
|
|
Loading…
Reference in New Issue