Browse Source

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
changes/81/771081/3
Alan Bishop 8 months ago
parent
commit
f91aec5869
  1. 2
      api-ref/source/v3/ext-backups.inc
  2. 6
      api-ref/source/v3/parameters.yaml
  3. 4
      api-ref/source/v3/samples/versions/version-show-response.json
  4. 4
      api-ref/source/v3/samples/versions/versions-response.json
  5. 2
      api-ref/source/v3/volumes-v3-volumes.inc
  6. 2
      cinder/api/microversions.py
  7. 5
      cinder/api/openstack/api_version_request.py
  8. 5
      cinder/api/openstack/rest_api_version_history.rst
  9. 8
      cinder/api/v3/views/backups.py
  10. 7
      cinder/api/v3/views/volumes.py
  11. 3
      cinder/common/constants.py
  12. 20
      cinder/tests/unit/api/v3/test_backups.py
  13. 44
      cinder/tests/unit/api/v3/test_volumes.py
  14. 6
      releasenotes/notes/add-encryption-key-id-to-details-e721977fba0f2b51.yaml

2
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
----------------

6
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

4
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"
}
]
}

4
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"
}
]
}

2
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

2
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.

5
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

5
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.

8
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

7
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,

3
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'

20
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,

44
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',

6
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.
Loading…
Cancel
Save