Merge "Compress images uploaded to Glance"

This commit is contained in:
Zuul 2019-08-04 20:26:09 +00:00 committed by Gerrit Code Review
commit 80a46a80ed
4 changed files with 76 additions and 11 deletions

View File

@ -57,7 +57,12 @@ image_opts = [
cfg.StrOpt('image_conversion_dir',
default='$state_path/conversion',
help='Directory used for temporary storage '
'during image conversion'), ]
'during image conversion'),
cfg.BoolOpt('image_compress_on_upload',
default=True,
help='When possible, compress images uploaded '
'to the image service'),
]
CONF = cfg.CONF
CONF.register_opts(image_opts)
@ -79,6 +84,8 @@ QEMU_IMG_VERSION = None
QEMU_IMG_MIN_FORCE_SHARE_VERSION = [2, 10, 0]
QEMU_IMG_MIN_CONVERT_LUKS_VERSION = '2.10'
COMPRESSIBLE_IMAGE_FORMATS = ('qcow2')
def fixup_disk_format(disk_format):
"""Return the format to be provided to qemu-img convert."""
@ -141,7 +148,8 @@ def qemu_img_supports_force_share():
def _get_qemu_convert_cmd(src, dest, out_format, src_format=None,
out_subformat=None, cache_mode=None,
prefix=None, cipher_spec=None, passphrase_file=None):
prefix=None, cipher_spec=None,
passphrase_file=None, compress=False):
if out_format == 'vhd':
# qemu-img still uses the legacy vpc name
@ -155,6 +163,10 @@ def _get_qemu_convert_cmd(src, dest, out_format, src_format=None,
if cache_mode:
cmd += ('-t', cache_mode)
if CONF.image_compress_on_upload and compress:
if out_format in COMPRESSIBLE_IMAGE_FORMATS:
cmd += ('-c',)
if out_subformat:
cmd += ('-o', 'subformat=%s' % out_subformat)
@ -206,8 +218,21 @@ def check_qemu_img_version(minimum_version):
def _convert_image(prefix, source, dest, out_format,
out_subformat=None, src_format=None,
run_as_root=True, cipher_spec=None, passphrase_file=None):
"""Convert image to other format."""
run_as_root=True, cipher_spec=None,
passphrase_file=None, compress=False):
"""Convert image to other format.
:param prefix: command prefix, i.e. cgexec for throttling
:param source: source filename
:param dest: destination filename
:param out_format: output image format of qemu-img
:param out_subformat: output image subformat
:param src_format: source image format
:param run_as_root: run qemu-img as root
:param cipher_spec: encryption details
:param passphrase_file: filename containing luks passphrase
:param compress: compress w/ qemu-img when possible (best effort)
"""
# Check whether O_DIRECT is supported and set '-t none' if it is
# This is needed to ensure that all data hit the device before
@ -234,7 +259,8 @@ def _convert_image(prefix, source, dest, out_format,
cache_mode=cache_mode,
prefix=prefix,
cipher_spec=cipher_spec,
passphrase_file=passphrase_file)
passphrase_file=passphrase_file,
compress=compress)
start_time = timeutils.utcnow()
@ -286,7 +312,8 @@ def _convert_image(prefix, source, dest, out_format,
def convert_image(source, dest, out_format, out_subformat=None,
src_format=None, run_as_root=True, throttle=None,
cipher_spec=None, passphrase_file=None):
cipher_spec=None, passphrase_file=None,
compress=False):
if not throttle:
throttle = throttling.Throttle.get_default()
with throttle.subcommand(source, dest) as throttle_cmd:
@ -297,7 +324,8 @@ def convert_image(source, dest, out_format, out_subformat=None,
src_format=src_format,
run_as_root=run_as_root,
cipher_spec=cipher_spec,
passphrase_file=passphrase_file)
passphrase_file=passphrase_file,
compress=compress)
def resize_image(source, size, run_as_root=False):
@ -641,7 +669,8 @@ def upload_volume(context, image_service, image_meta, volume_path,
out_format = fixup_disk_format(image_meta['disk_format'])
convert_image(volume_path, tmp, out_format,
run_as_root=run_as_root)
run_as_root=run_as_root,
compress=True)
data = qemu_img_info(tmp, run_as_root=run_as_root)
if data.file_format != out_format:

View File

@ -124,6 +124,7 @@ class TestQemuImgInfo(test.TestCase):
current_version=[1, 8])
@ddt.ddt
class TestConvertImage(test.TestCase):
@mock.patch('cinder.image.image_utils.qemu_img_info')
@mock.patch('cinder.utils.execute')
@ -280,6 +281,31 @@ class TestConvertImage(test.TestCase):
'-O', 'vpc',
source, dest, run_as_root=True)
@ddt.data(True, False)
@mock.patch('cinder.image.image_utils.qemu_img_info')
@mock.patch('cinder.utils.execute')
@mock.patch('cinder.utils.is_blk_device', return_value=False)
def test_convert_to_qcow2(self,
compress_option,
mock_isblk, mock_exec, mock_info):
self.override_config('image_compress_on_upload', compress_option)
source = mock.sentinel.source
dest = mock.sentinel.dest
out_format = 'qcow2'
mock_info.return_value.virtual_size = 1048576
image_utils.convert_image(source,
dest,
out_format,
compress=True)
exec_args = ['qemu-img', 'convert', '-O', 'qcow2']
if compress_option:
exec_args.append('-c')
exec_args.extend((source, dest))
mock_exec.assert_called_once_with(*exec_args,
run_as_root=True)
@mock.patch('cinder.image.image_utils.CONF')
@mock.patch('cinder.volume.utils.check_for_odirect_support',
return_value=True)
@ -727,7 +753,8 @@ class TestUploadVolume(test.TestCase):
mock_convert.assert_called_once_with(volume_path,
temp_file,
output_format,
run_as_root=True)
run_as_root=True,
compress=True)
mock_info.assert_called_with(temp_file, run_as_root=True)
self.assertEqual(2, mock_info.call_count)
mock_open.assert_called_once_with(temp_file, 'rb')
@ -823,7 +850,8 @@ class TestUploadVolume(test.TestCase):
mock_convert.assert_called_once_with(volume_path,
temp_file,
mock.sentinel.disk_format,
run_as_root=True)
run_as_root=True,
compress=True)
mock_info.assert_called_with(temp_file, run_as_root=True)
self.assertEqual(2, mock_info.call_count)
self.assertFalse(image_service.update.called)

View File

@ -896,7 +896,8 @@ class BaseVD(object):
image_utils.upload_volume(context,
image_service,
image_meta,
attach_info['device']['path'])
attach_info['device']['path'],
compress=True)
finally:
# Since attached volume was not used for writing we can force
# detach it

View File

@ -0,0 +1,7 @@
---
features:
- |
When uploading qcow2 images to Glance, image data will be compressed. This
will generally result in less data transferred to Glance at the expense of
higher CPU usage. This behavior is controlled by the
"image_compress_on_upload" boolean option, which defaults to True.