From f91aec58696abf8949f40d8f1287db2788fd7c0c Mon Sep 17 00:00:00 2001 From: Alan Bishop Date: Fri, 15 Jan 2021 12:41:09 -0800 Subject: [PATCH] Add encryption_key_id to volume and backup details Add microversion 3.64 for including the encryption_key_id in the volume and backup details when the associated volume is encrypted. This facilitates associating encryption keys (typically stored in Barbican) with the volume or backup that uses it. The encryption_key_id is included in the details only when the associated volume is encrypted, and it isn't using the all-zeros key ID used by the legacy fixed-key ConfKeyMgr. APIImpact DocImpact Implements: blueprint include-encryption-key-id-in-details Change-Id: I16f54e6722cdbcbad4af1eb0d30264b0039412fd --- api-ref/source/v3/ext-backups.inc | 2 + api-ref/source/v3/parameters.yaml | 6 +++ .../versions/version-show-response.json | 4 +- .../samples/versions/versions-response.json | 4 +- api-ref/source/v3/volumes-v3-volumes.inc | 2 + cinder/api/microversions.py | 2 + cinder/api/openstack/api_version_request.py | 5 ++- .../openstack/rest_api_version_history.rst | 5 +++ cinder/api/v3/views/backups.py | 8 ++++ cinder/api/v3/views/volumes.py | 7 +++ cinder/common/constants.py | 3 ++ cinder/tests/unit/api/v3/test_backups.py | 20 +++++++++ cinder/tests/unit/api/v3/test_volumes.py | 44 +++++++++++++++++++ ...on-key-id-to-details-e721977fba0f2b51.yaml | 6 +++ 14 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/add-encryption-key-id-to-details-e721977fba0f2b51.yaml diff --git a/api-ref/source/v3/ext-backups.inc b/api-ref/source/v3/ext-backups.inc index 0a6986ee476..01949258a15 100644 --- a/api-ref/source/v3/ext-backups.inc +++ b/api-ref/source/v3/ext-backups.inc @@ -98,6 +98,7 @@ Response Parameters - count: count - metadata: metadata_backup - user_id: user_id_backup + - encryption_key_id: encryption_key_id Response Example ---------------- @@ -157,6 +158,7 @@ Response Parameters - os-backup-project-attr:project_id: os-backup-project-attr:project_id - metadata: metadata_backup - user_id: user_id_backup + - encryption_key_id: encryption_key_id Response Example ---------------- diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml index c521e0b0630..1187ae7b291 100644 --- a/api-ref/source/v3/parameters.yaml +++ b/api-ref/source/v3/parameters.yaml @@ -1140,6 +1140,12 @@ encryption_id_body: in: body required: true type: string +encryption_key_id: + description: | + The UUID of the encryption key. + in: body + required: false + type: string event_id: description: | The id of the event to this message, this id could diff --git a/api-ref/source/v3/samples/versions/version-show-response.json b/api-ref/source/v3/samples/versions/version-show-response.json index 1cd449cbbbe..df31cb2f2b5 100644 --- a/api-ref/source/v3/samples/versions/version-show-response.json +++ b/api-ref/source/v3/samples/versions/version-show-response.json @@ -21,8 +21,8 @@ ], "min_version": "3.0", "status": "CURRENT", - "updated": "2020-11-19T08:56:00Z", - "version": "3.63" + "updated": "2021-02-03T00:00:00Z", + "version": "3.64" } ] } diff --git a/api-ref/source/v3/samples/versions/versions-response.json b/api-ref/source/v3/samples/versions/versions-response.json index 795b50572e9..b1c96e54281 100644 --- a/api-ref/source/v3/samples/versions/versions-response.json +++ b/api-ref/source/v3/samples/versions/versions-response.json @@ -45,8 +45,8 @@ ], "min_version": "3.0", "status": "CURRENT", - "updated": "2020-11-19T08:56:00Z", - "version": "3.63" + "updated": "2021-02-03T00:00:00Z", + "version": "3.64" } ] } diff --git a/api-ref/source/v3/volumes-v3-volumes.inc b/api-ref/source/v3/volumes-v3-volumes.inc index dadfbab9267..49cbc4b0d7f 100644 --- a/api-ref/source/v3/volumes-v3-volumes.inc +++ b/api-ref/source/v3/volumes-v3-volumes.inc @@ -109,6 +109,7 @@ Response Parameters - availability_zone: availability_zone - os-vol-host-attr:host: os-vol-host-attr:host - encrypted: encrypted + - encryption_key_id: encryption_key_id - updated_at: updated_at - replication_status: replication_status - snapshot_id: snapshot_id @@ -355,6 +356,7 @@ Response Parameters - availability_zone: availability_zone - os-vol-host-attr:host: os-vol-host-attr:host - encrypted: encrypted + - encryption_key_id: encryption_key_id - updated_at: updated_at - replication_status: replication_status - snapshot_id: snapshot_id diff --git a/cinder/api/microversions.py b/cinder/api/microversions.py index 8c4268e36e1..e8605c691b5 100644 --- a/cinder/api/microversions.py +++ b/cinder/api/microversions.py @@ -167,6 +167,8 @@ DEFAULT_TYPE_OVERRIDES = '3.62' VOLUME_TYPE_ID_IN_VOLUME_DETAIL = '3.63' +ENCRYPTION_KEY_ID_IN_DETAILS = '3.64' + def get_mv_header(version): """Gets a formatted HTTP microversion header. diff --git a/cinder/api/openstack/api_version_request.py b/cinder/api/openstack/api_version_request.py index 3513d5fe7e1..bde0205d45e 100644 --- a/cinder/api/openstack/api_version_request.py +++ b/cinder/api/openstack/api_version_request.py @@ -147,6 +147,7 @@ REST_API_VERSION_HISTORY = """ in the volume details. This MV affects the volume detail list ("GET /v3/{project_id}/volumes/detail") and volume-show ("GET /v3/{project_id}/volumes/{volume_id}") calls. + * 3.64 - Include 'encryption_key_id' in volume and backup details """ # The minimum and maximum versions of the API supported @@ -154,9 +155,9 @@ REST_API_VERSION_HISTORY = """ # minimum version of the API supported. # Explicitly using /v2 endpoints will still work _MIN_API_VERSION = "3.0" -_MAX_API_VERSION = "3.63" +_MAX_API_VERSION = "3.64" _LEGACY_API_VERSION2 = "2.0" -UPDATED = "2020-11-19T08:56:00Z" +UPDATED = "2021-02-03T00:00:00Z" # NOTE(cyeoh): min and max versions declared as functions so we can diff --git a/cinder/api/openstack/rest_api_version_history.rst b/cinder/api/openstack/rest_api_version_history.rst index 4f6e78ac4ec..c4d1c4130ed 100644 --- a/cinder/api/openstack/rest_api_version_history.rst +++ b/cinder/api/openstack/rest_api_version_history.rst @@ -485,3 +485,8 @@ value. Includes volume type ID in the volume-show and volume-detail-list JSON responses. Before this microversion, Cinder returns only the volume type name in the volume details. + +3.64 +---- +Include the ``encryption_key_id`` in volume and backup details when the +associated volume is encrypted. diff --git a/cinder/api/v3/views/backups.py b/cinder/api/v3/views/backups.py index 2a428ec64c7..07038236e31 100644 --- a/cinder/api/v3/views/backups.py +++ b/cinder/api/v3/views/backups.py @@ -15,6 +15,7 @@ from cinder.api import microversions as mv from cinder.api.views import backups as views_v2 +from cinder.common import constants as cinder_constants class ViewBuilder(views_v2.ViewBuilder): @@ -29,4 +30,11 @@ class ViewBuilder(views_v2.ViewBuilder): req_version = request.api_version_request if req_version.matches(mv.BACKUP_METADATA): backup_ref['backup']['metadata'] = backup.metadata + + if req_version.matches(mv.ENCRYPTION_KEY_ID_IN_DETAILS, None): + encryption_key_id = backup.get('encryption_key_id', None) + if (encryption_key_id and + encryption_key_id != cinder_constants.FIXED_KEY_ID): + backup_ref['backup']['encryption_key_id'] = encryption_key_id + return backup_ref diff --git a/cinder/api/v3/views/volumes.py b/cinder/api/v3/views/volumes.py index 6e61146337c..ed171c7bde1 100644 --- a/cinder/api/v3/views/volumes.py +++ b/cinder/api/v3/views/volumes.py @@ -15,6 +15,7 @@ from cinder.api import microversions as mv from cinder.api.v2.views import volumes as views_v2 +from cinder.common import constants as cinder_constants class ViewBuilder(views_v2.ViewBuilder): @@ -70,6 +71,12 @@ class ViewBuilder(views_v2.ViewBuilder): volume_ref[ 'volume']["volume_type_id"] = volume['volume_type'].get('id') + if req_version.matches(mv.ENCRYPTION_KEY_ID_IN_DETAILS, None): + encryption_key_id = volume.get('encryption_key_id', None) + if (encryption_key_id and + encryption_key_id != cinder_constants.FIXED_KEY_ID): + volume_ref['volume']['encryption_key_id'] = encryption_key_id + return volume_ref def _list_view(self, func, request, volumes, volume_count, diff --git a/cinder/common/constants.py b/cinder/common/constants.py index 46f36f0124d..61c84132d74 100644 --- a/cinder/common/constants.py +++ b/cinder/common/constants.py @@ -26,3 +26,6 @@ SCHEDULER_TOPIC = SCHEDULER_BINARY VOLUME_TOPIC = VOLUME_BINARY BACKUP_TOPIC = BACKUP_BINARY LOG_BINARIES = (SCHEDULER_BINARY, VOLUME_BINARY, BACKUP_BINARY, API_BINARY) + +# The encryption key ID used by the legacy fixed-key ConfKeyMgr +FIXED_KEY_ID = '00000000-0000-0000-0000-000000000000' diff --git a/cinder/tests/unit/api/v3/test_backups.py b/cinder/tests/unit/api/v3/test_backups.py index 6597fc5afb9..f2c9d81f649 100644 --- a/cinder/tests/unit/api/v3/test_backups.py +++ b/cinder/tests/unit/api/v3/test_backups.py @@ -32,6 +32,7 @@ from cinder import context from cinder import exception from cinder.objects import fields from cinder.tests.unit.api import fakes +from cinder.tests.unit.api.v3.test_volumes import ENCRYPTION_KEY_ID_IN_DETAILS from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import test from cinder.tests.unit import utils as test_utils @@ -286,6 +287,25 @@ class BackupsControllerAPITestCase(test.TestCase): else: self.assertIn('metadata', backup_get) + @ddt.data(*ENCRYPTION_KEY_ID_IN_DETAILS) + @ddt.unpack + def test_backup_show_with_encryption_key_id(self, + expected_in_details, + encryption_key_id, + version): + backup = test_utils.create_backup(self.ctxt, + encryption_key_id=encryption_key_id) + self.addCleanup(backup.destroy) + + url = '/v3/%s/backups/%s' % (fake.PROJECT_ID, backup.id) + req = fakes.HTTPRequest.blank(url, version=version) + backup_details = self.controller.show(req, backup.id)['backup'] + + if expected_in_details: + self.assertIn('encryption_key_id', backup_details) + else: + self.assertNotIn('encryption_key_id', backup_details) + def test_backup_update_with_null_validate(self): backup = test_utils.create_backup( self.ctxt, diff --git a/cinder/tests/unit/api/v3/test_volumes.py b/cinder/tests/unit/api/v3/test_volumes.py index 06b936a4914..c2f787021ac 100644 --- a/cinder/tests/unit/api/v3/test_volumes.py +++ b/cinder/tests/unit/api/v3/test_volumes.py @@ -31,6 +31,7 @@ from cinder.api import microversions as mv from cinder.api.v2.views.volumes import ViewBuilder from cinder.api.v3 import volumes from cinder.backup import api as backup_api +from cinder.common import constants as cinder_constants from cinder import context from cinder import db from cinder import exception @@ -50,6 +51,29 @@ from cinder.volume import api as vol_get DEFAULT_AZ = "zone1:host1" +# DDT data for testing whether an 'encryption_key_id' should appear in a +# volume's or backup's details (also used by test_backups.py). +ENCRYPTION_KEY_ID_IN_DETAILS = { + 'expected_in_details': True, + 'encryption_key_id': fake.ENCRYPTION_KEY_ID, + 'version': mv.ENCRYPTION_KEY_ID_IN_DETAILS, +}, { + # No encryption ID to display + 'expected_in_details': False, + 'encryption_key_id': None, + 'version': mv.ENCRYPTION_KEY_ID_IN_DETAILS, +}, { + # Fixed key ID should not be displayed + 'expected_in_details': False, + 'encryption_key_id': cinder_constants.FIXED_KEY_ID, + 'version': mv.ENCRYPTION_KEY_ID_IN_DETAILS, +}, { + # Unsupported microversion + 'expected_in_details': False, + 'encryption_key_id': fake.ENCRYPTION_KEY_ID, + 'version': mv.get_prior_version(mv.ENCRYPTION_KEY_ID_IN_DETAILS), +} + @ddt.ddt class VolumeApiTest(test.TestCase): @@ -856,6 +880,26 @@ class VolumeApiTest(test.TestCase): else: self.assertNotIn('provider_id', res_dict['volume']) + @ddt.data(*ENCRYPTION_KEY_ID_IN_DETAILS) + @ddt.unpack + def test_volume_show_with_encryption_key_id(self, + expected_in_details, + encryption_key_id, + version): + volume = test_utils.create_volume(self.ctxt, + testcase_instance=self, + volume_type_id=None, + encryption_key_id=encryption_key_id) + + req = fakes.HTTPRequest.blank('/v3/volumes/%s' % volume.id, + version=version) + volume_details = self.controller.show(req, volume.id)['volume'] + + if expected_in_details: + self.assertIn('encryption_key_id', volume_details) + else: + self.assertNotIn('encryption_key_id', volume_details) + def _fake_create_volume(self, size=1): vol = { 'display_name': 'fake_volume1', diff --git a/releasenotes/notes/add-encryption-key-id-to-details-e721977fba0f2b51.yaml b/releasenotes/notes/add-encryption-key-id-to-details-e721977fba0f2b51.yaml new file mode 100644 index 00000000000..f7fd87fc9ae --- /dev/null +++ b/releasenotes/notes/add-encryption-key-id-to-details-e721977fba0f2b51.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Starting with API microversion 3.64, an ``encryption_key_id`` attribute + is included in the response body of volume and backup details when the + associated volume is encrypted.