diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml index cf806829d3e..f887e4b3b0e 100644 --- a/api-ref/source/v3/parameters.yaml +++ b/api-ref/source/v3/parameters.yaml @@ -874,6 +874,13 @@ container_format: in: body required: false type: string +container_format_upload: + description: | + Container format for the new image. Default is bare. (Note: Volumes + of an encrypted volume type must use a bare container format.) + in: body + required: false + type: string control_location: description: | Notional service where encryption is performed. Valid values are @@ -1121,6 +1128,13 @@ disk_format: in: body required: false type: string +disk_format_upload: + description: | + Disk format for the new image. Default is raw. (Note: volumes of an + encrypted volume type can only be uploaded in raw format.) + in: body + required: false + type: string display_name: description: | The name of volume backend capabilities. diff --git a/api-ref/source/v3/volumes-v3-volumes-actions.inc b/api-ref/source/v3/volumes-v3-volumes-actions.inc index 935a0f4c6c1..597d623563d 100644 --- a/api-ref/source/v3/volumes-v3-volumes-actions.inc +++ b/api-ref/source/v3/volumes-v3-volumes-actions.inc @@ -699,8 +699,8 @@ Request - os-volume_upload_image: os-volume_upload_image - image_name: image_name - force: force_upload_vol - - disk_format: disk_format - - container_format: container_format + - disk_format: disk_format_upload + - container_format: container_format_upload - visibility: visibility_min - protected: protected diff --git a/cinder/api/contrib/volume_actions.py b/cinder/api/contrib/volume_actions.py index e1389e6b73a..da09d07f3eb 100644 --- a/cinder/api/contrib/volume_actions.py +++ b/cinder/api/contrib/volume_actions.py @@ -217,6 +217,14 @@ class VolumeActionsController(wsgi.Controller): "name": params["image_name"]} if volume.encryption_key_id: + # encrypted volumes cannot be converted on upload + if (image_metadata['disk_format'] != 'raw' + or image_metadata['container_format'] != 'bare'): + msg = _("An encrypted volume uploaded as an image must use " + "'raw' disk_format and 'bare' container_format, " + "which are the defaults for these options.") + raise webob.exc.HTTPBadRequest(explanation=msg) + # Clone volume encryption key: the current key cannot # be reused because it will be deleted when the volume is # deleted. diff --git a/cinder/tests/unit/api/contrib/test_volume_actions.py b/cinder/tests/unit/api/contrib/test_volume_actions.py index 608f2e9d711..6573f2a1ff2 100644 --- a/cinder/tests/unit/api/contrib/test_volume_actions.py +++ b/cinder/tests/unit/api/contrib/test_volume_actions.py @@ -1003,6 +1003,38 @@ class VolumeImageActionsTest(test.TestCase): id, body=body) + @mock.patch.object(volume_api.API, 'get', fake_volume_get_obj) + def test_copy_volume_to_image_bad_disk_format_for_encrypted_vol(self): + id = ENCRYPTED_VOLUME_ID + vol = {"container_format": 'bare', + "disk_format": 'qcow2', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v3/%s/volumes/%s/action' + % (fake.PROJECT_ID, id)) + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller._volume_upload_image, + req, + id, + body=body) + + @mock.patch.object(volume_api.API, 'get', fake_volume_get_obj) + def test_copy_volume_to_image_bad_container_format_for_encrypted_vol(self): + id = ENCRYPTED_VOLUME_ID + vol = {"container_format": 'ovf', + "disk_format": 'raw', + "image_name": 'image_name', + "force": True} + body = {"os-volume_upload_image": vol} + req = fakes.HTTPRequest.blank('/v3/%s/volumes/%s/action' + % (fake.PROJECT_ID, id)) + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller._volume_upload_image, + req, + id, + body=body) + @mock.patch.object(volume_api.API, "copy_volume_to_image") def test_copy_volume_to_image_disk_format_ploop(self, mock_copy_to_image): diff --git a/releasenotes/notes/bug-193688-bb045badcd5aecad.yaml b/releasenotes/notes/bug-193688-bb045badcd5aecad.yaml new file mode 100644 index 00000000000..f4a141dbacb --- /dev/null +++ b/releasenotes/notes/bug-193688-bb045badcd5aecad.yaml @@ -0,0 +1,12 @@ +--- +fixes: + - | + `Bug #1935688 `_: + Cinder only supports uploading a volume of an encrypted volume type as an + image to the Image service in ``raw`` format using a ``bare`` container + type. Previously, ``os-volume_upload_image`` action requests to the Block + Storage API specifying different format option values were accepted, but + would result in a later failure. This condition is now checked at the API + layer, and ``os-volume_upload_image`` action requests on a volume of an + encrypted type that specify unsupported values for ``disk_format`` or + ``container_format`` now result in a 400 (Bad Request) response.