From de8b3b0b00421a01ed777880d2b5bf6fffc068d5 Mon Sep 17 00:00:00 2001 From: Brian Rosmaita Date: Fri, 9 Jul 2021 11:08:34 -0400 Subject: [PATCH] Reject bad img formats for uploaded encrypted vols Cinder only supports uploading volumes of encrypted volume types as images with disk format 'raw' and container format 'bare'. Screen for this at the REST API layer when the request is made. Change-Id: Ibb77b8b1be6c35c5db3b07fdc4056afd51d48782 Closes-bug: #1935688 --- api-ref/source/v3/parameters.yaml | 14 ++++++++ .../source/v3/volumes-v3-volumes-actions.inc | 4 +-- cinder/api/contrib/volume_actions.py | 8 +++++ .../unit/api/contrib/test_volume_actions.py | 32 +++++++++++++++++++ .../notes/bug-193688-bb045badcd5aecad.yaml | 12 +++++++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/bug-193688-bb045badcd5aecad.yaml diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml index b82cae1afb3..75ca8f2e4b5 100644 --- a/api-ref/source/v3/parameters.yaml +++ b/api-ref/source/v3/parameters.yaml @@ -853,6 +853,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 @@ -1100,6 +1107,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 a9d578115f2..deb326be079 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 fbd7e348b30..852ba7dbab9 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.