Add encrypted flag to volumes
Currently, the only way to determine whether a volume is encrypted is by retrieving the encryption metadata about the volume (through cinder.api.contrib.volume_encryption_metadata) and checking the encryption_key_id value. This patch adds an "encrypted" flag to the basic volume api to enable other services (like Horizon: see patch https://review.openstack.org/#/c/71125) to easily tell whether a volume is encrypted using a basic get call,instead of requiring an additional call. Implements blueprint encrypt-cinder-volumes https://blueprints.launchpad.net/nova/+spec/encrypt-cinder-volumes Change-Id: Id8e422135f17795de06589930afd0309fde28fd1
This commit is contained in:
parent
ae5ae5079e
commit
3caa76a2b2
|
@ -106,6 +106,8 @@ def _translate_volume_summary_view(context, vol, image_id=None):
|
|||
d['snapshot_id'] = vol['snapshot_id']
|
||||
d['source_volid'] = vol['source_volid']
|
||||
|
||||
d['encrypted'] = vol['encryption_key_id'] is not None
|
||||
|
||||
if image_id:
|
||||
d['image_id'] = image_id
|
||||
|
||||
|
|
|
@ -66,10 +66,15 @@ class ViewBuilder(common.ViewBuilder):
|
|||
'metadata': self._get_volume_metadata(volume),
|
||||
'links': self._get_links(request, volume['id']),
|
||||
'user_id': volume.get('user_id'),
|
||||
'bootable': str(volume.get('bootable')).lower()
|
||||
'bootable': str(volume.get('bootable')).lower(),
|
||||
'encrypted': self._is_volume_encrypted(volume)
|
||||
}
|
||||
}
|
||||
|
||||
def _is_volume_encrypted(self, volume):
|
||||
"""Determine if volume is encrypted."""
|
||||
return volume.get('encryption_key_id') is not None
|
||||
|
||||
def _get_attachments(self, volume):
|
||||
"""Retrieve the attachments of the volume object."""
|
||||
attachments = []
|
||||
|
|
|
@ -90,6 +90,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'Volume Test Desc',
|
||||
'availability_zone': 'zone1:host1',
|
||||
'display_name': 'Volume Test Name',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -104,7 +105,8 @@ class VolumeApiTest(test.TestCase):
|
|||
'id': '1',
|
||||
'created_at': datetime.datetime(1, 1, 1,
|
||||
1, 1, 1),
|
||||
'size': 100}}
|
||||
'size': 100,
|
||||
'encrypted': False}}
|
||||
self.assertEqual(res_dict, expected)
|
||||
|
||||
def test_volume_create_with_type(self):
|
||||
|
@ -180,6 +182,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'Volume Test Desc',
|
||||
'availability_zone': 'nova',
|
||||
'display_name': 'Volume Test Name',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -247,6 +250,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'Updated Test Name',
|
||||
'encrypted': False,
|
||||
'attachments': [{
|
||||
'id': '1',
|
||||
'volume_id': '1',
|
||||
|
@ -282,6 +286,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{
|
||||
'id': '1',
|
||||
'volume_id': '1',
|
||||
|
@ -331,6 +336,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'Updated Test Name',
|
||||
'encrypted': False,
|
||||
'attachments': [{
|
||||
'id': '1',
|
||||
'volume_id': '1',
|
||||
|
@ -386,6 +392,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -425,6 +432,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -453,6 +461,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -492,6 +501,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -642,6 +652,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -673,6 +684,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [],
|
||||
'bootable': 'false',
|
||||
'volume_type': 'vol_type_name',
|
||||
|
@ -698,6 +710,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -772,6 +785,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'display_description': 'displaydesc',
|
||||
'availability_zone': 'fakeaz',
|
||||
'display_name': 'displayname',
|
||||
'encrypted': False,
|
||||
'attachments': [{'device': '/',
|
||||
'server_id': 'fakeuuid',
|
||||
'host_name': None,
|
||||
|
@ -789,6 +803,26 @@ class VolumeApiTest(test.TestCase):
|
|||
'size': 1}}
|
||||
self.assertEqual(res_dict, expected)
|
||||
|
||||
def test_volume_show_with_encrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
self.assertEqual(res_dict['volume']['encrypted'], True)
|
||||
|
||||
def test_volume_show_with_unencrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id=None)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v1/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
self.assertEqual(res_dict['volume']['encrypted'], False)
|
||||
|
||||
def test_volume_delete(self):
|
||||
self.stubs.Set(db, 'volume_get', stubs.stub_volume_get_db)
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ def stub_volume(id, **kwargs):
|
|||
'snapshot_id': None,
|
||||
'source_volid': None,
|
||||
'volume_type_id': '3e196c20-3c06-11e2-81c1-0800200c9a66',
|
||||
'encryption_key_id': None,
|
||||
'volume_admin_metadata': [{'key': 'attached_mode', 'value': 'rw'},
|
||||
{'key': 'readonly', 'value': 'False'}],
|
||||
'bootable': False,
|
||||
|
|
|
@ -116,7 +116,8 @@ class VolumeApiTest(test.TestCase):
|
|||
'source_volid': None,
|
||||
'status': 'fakestatus',
|
||||
'user_id': 'fakeuser',
|
||||
'volume_type': 'vol_type_name'}}
|
||||
'volume_type': 'vol_type_name',
|
||||
'encrypted': False}}
|
||||
self.assertEqual(res_dict, ex)
|
||||
|
||||
def test_volume_create_with_type(self):
|
||||
|
@ -204,6 +205,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'bootable': 'false',
|
||||
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
|
||||
'description': 'Volume Test Desc',
|
||||
'encrypted': False,
|
||||
'id': '1',
|
||||
'links':
|
||||
[{'href': 'http://localhost/v2/fake/volumes/1',
|
||||
|
@ -273,6 +275,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'volume': {
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'Updated Test Name',
|
||||
|
@ -322,6 +325,7 @@ class VolumeApiTest(test.TestCase):
|
|||
expected = {'volume': {
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -382,6 +386,7 @@ class VolumeApiTest(test.TestCase):
|
|||
expected = {'volume': {
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -483,6 +488,7 @@ class VolumeApiTest(test.TestCase):
|
|||
{
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -541,6 +547,7 @@ class VolumeApiTest(test.TestCase):
|
|||
{
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -873,6 +880,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'volume': {
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -921,6 +929,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'volume': {
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -977,6 +986,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'volume': {
|
||||
'status': 'fakestatus',
|
||||
'description': 'displaydesc',
|
||||
'encrypted': False,
|
||||
'availability_zone': 'fakeaz',
|
||||
'bootable': 'false',
|
||||
'name': 'displayname',
|
||||
|
@ -1012,6 +1022,26 @@ class VolumeApiTest(test.TestCase):
|
|||
}
|
||||
self.assertEqual(res_dict, expected)
|
||||
|
||||
def test_volume_show_with_encrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
self.assertEqual(res_dict['volume']['encrypted'], True)
|
||||
|
||||
def test_volume_show_with_unencrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id=None)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes/1')
|
||||
res_dict = self.controller.show(req, 1)
|
||||
self.assertEqual(res_dict['volume']['encrypted'], False)
|
||||
|
||||
def test_volume_delete(self):
|
||||
self.stubs.Set(volume_api.API, 'get', stubs.stub_volume_get)
|
||||
|
||||
|
|
Loading…
Reference in New Issue