Fix volume upload-to-image for vhd disk-format

It was previously assumed that glance did not support qed
disk-format.
qemu-img still uses the legacy 'vpc' format name as a
parameter. When executing 'qemu-img convert', vhd was
being passed as a parameter which is invalid.

This fix adds 'vhd' to the valid disk formats and passes
'vpc' to 'qemu-img convert', which is correct use of the
command. Also added 'vhdx' to the valid disk formats.

Change-Id: I24e6b78505a2c77b309c79ef11466c08bad1c50a
Closes-Bug: #1585612
This commit is contained in:
Jay Conroy 2016-07-27 17:38:16 +01:00
parent c47d38dc94
commit e815f56bd5
3 changed files with 60 additions and 6 deletions

View File

@ -56,10 +56,10 @@ CONF.register_opts(image_helper_opts)
# NOTE(abhishekk): qemu-img convert command supports raw, qcow2, qed,
# vdi, vmdk and vhd disk-formats but glance doesn't support qed and
# vhd(vpc) disk-formats.
# vdi, vmdk, vhd and vhdx disk-formats but glance doesn't support qed
# disk-format.
# Ref: http://docs.openstack.org/image-guide/convert-images.html
VALID_DISK_FORMATS = ('raw', 'vmdk', 'vdi', 'qcow2')
VALID_DISK_FORMATS = ('raw', 'vmdk', 'vdi', 'qcow2', 'vhd', 'vhdx')
def validate_disk_format(disk_format):
@ -395,15 +395,20 @@ def upload_volume(context, image_service, image_meta, volume_path,
reason=_("fmt=%(fmt)s backed by:%(backing_file)s")
% {'fmt': fmt, 'backing_file': backing_file})
convert_image(volume_path, tmp, image_meta['disk_format'],
out_format = image_meta['disk_format']
# qemu-img accepts 'vpc' as argument for vhd format
if out_format == 'vhd':
out_format = 'vpc'
convert_image(volume_path, tmp, out_format,
run_as_root=run_as_root)
data = qemu_img_info(tmp, run_as_root=run_as_root)
if data.file_format != image_meta['disk_format']:
if data.file_format != out_format:
raise exception.ImageUnacceptable(
image_id=image_id,
reason=_("Converted to %(f1)s, but format is now %(f2)s") %
{'f1': image_meta['disk_format'], 'f2': data.file_format})
{'f1': out_format, 'f2': data.file_format})
with open(tmp, 'rb') as image_file:
image_service.update(context, image_id, {}, image_file)

View File

@ -1304,3 +1304,49 @@ class VolumeImageActionsTest(test.TestCase):
expected['os-volume_upload_image'].update(visibility='public',
protected=True)
self.assertDictMatch(expected, res_dict)
@mock.patch.object(volume_api.API, "get_volume_image_metadata")
@mock.patch.object(glance.GlanceImageService, "create")
@mock.patch.object(volume_rpcapi.VolumeAPI, "copy_volume_to_image")
def test_copy_volume_to_image_vhd(
self, mock_copy_to_image, mock_create, mock_get_image_metadata):
"""Test create image from volume with vhd disk format"""
volume, expected = self._create_volume_with_type()
mock_get_image_metadata.return_value = {}
mock_create.side_effect = self.fake_image_service_create
req = fakes.HTTPRequest.blank(
'/v2/fakeproject/volumes/%s/action' % volume.id)
body = self._get_os_volume_upload_image()
body['os-volume_upload_image']['force'] = True
body['os-volume_upload_image']['container_format'] = 'bare'
body['os-volume_upload_image']['disk_format'] = 'vhd'
res_dict = self.controller._volume_upload_image(req, volume.id, body)
self.assertDictMatch(expected, res_dict)
vol_db = objects.Volume.get_by_id(self.context, volume.id)
self.assertEqual('uploading', vol_db.status)
self.assertEqual('available', vol_db.previous_status)
@mock.patch.object(volume_api.API, "get_volume_image_metadata")
@mock.patch.object(glance.GlanceImageService, "create")
@mock.patch.object(volume_rpcapi.VolumeAPI, "copy_volume_to_image")
def test_copy_volume_to_image_vhdx(
self, mock_copy_to_image, mock_create, mock_get_image_metadata):
"""Test create image from volume with vhdx disk format"""
volume, expected = self._create_volume_with_type()
mock_get_image_metadata.return_value = {}
mock_create.side_effect = self.fake_image_service_create
req = fakes.HTTPRequest.blank(
'/v2/fakeproject/volumes/%s/action' % volume.id)
body = self._get_os_volume_upload_image()
body['os-volume_upload_image']['force'] = True
body['os-volume_upload_image']['container_format'] = 'bare'
body['os-volume_upload_image']['disk_format'] = 'vhdx'
res_dict = self.controller._volume_upload_image(req, volume.id, body)
self.assertDictMatch(expected, res_dict)
vol_db = objects.Volume.get_by_id(self.context, volume.id)
self.assertEqual('uploading', vol_db.status)
self.assertEqual('available', vol_db.previous_status)

View File

@ -0,0 +1,3 @@
---
features:
- Added support for vhd and vhdx disk-formats for volume upload-to-image.