From e815f56bd54548e98c45e19a95f80ffd51cc21f1 Mon Sep 17 00:00:00 2001 From: Jay Conroy Date: Wed, 27 Jul 2016 17:38:16 +0100 Subject: [PATCH] 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 --- cinder/image/image_utils.py | 17 ++++--- .../unit/api/contrib/test_volume_actions.py | 46 +++++++++++++++++++ ...rmat-upload-to-image-5851f9d35f4ee447.yaml | 3 ++ 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/vhd-disk-format-upload-to-image-5851f9d35f4ee447.yaml diff --git a/cinder/image/image_utils.py b/cinder/image/image_utils.py index c51179ba314..fac5cd927ba 100644 --- a/cinder/image/image_utils.py +++ b/cinder/image/image_utils.py @@ -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) diff --git a/cinder/tests/unit/api/contrib/test_volume_actions.py b/cinder/tests/unit/api/contrib/test_volume_actions.py index ffd9a0450a6..bf6260ad73f 100644 --- a/cinder/tests/unit/api/contrib/test_volume_actions.py +++ b/cinder/tests/unit/api/contrib/test_volume_actions.py @@ -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) diff --git a/releasenotes/notes/vhd-disk-format-upload-to-image-5851f9d35f4ee447.yaml b/releasenotes/notes/vhd-disk-format-upload-to-image-5851f9d35f4ee447.yaml new file mode 100644 index 00000000000..e31e34aad15 --- /dev/null +++ b/releasenotes/notes/vhd-disk-format-upload-to-image-5851f9d35f4ee447.yaml @@ -0,0 +1,3 @@ +--- +features: + - Added support for vhd and vhdx disk-formats for volume upload-to-image.