]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add encrypted flag to volumes
authorBrianna Poulos <Brianna.Poulos@jhuapl.edu>
Mon, 10 Feb 2014 21:13:59 +0000 (16:13 -0500)
committerBrianna Poulos <Brianna.Poulos@jhuapl.edu>
Fri, 14 Feb 2014 17:59:47 +0000 (12:59 -0500)
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

cinder/api/v1/volumes.py
cinder/api/v2/views/volumes.py
cinder/tests/api/v1/test_volumes.py
cinder/tests/api/v2/stubs.py
cinder/tests/api/v2/test_volumes.py

index 708152196cbd9c418d91fa36d785968a0269c554..1b1f1b0c249e2e849232405785a4883084ebf491 100644 (file)
@@ -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
 
index c1b45acc65546ae88df0c3a24f0c4c2f8d28d3a2..778be7767359dc2af6adf88fccf86b5a0b2ac69f 100644 (file)
@@ -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 = []
index 2bcf3ee233b7e2c8537be4e7471afae232bf7afd..fb937bd96d5d974471d8d75eea9c81b5b70ebedd 100644 (file)
@@ -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)
 
index 23384c2863d3acbd6db823ff805c397d397c7a96..cac93fc8ae1aeca1fc4eae331312b8c859220cf8 100644 (file)
@@ -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,
index 9fe16c8e72c55f2eba08aa84b8614c864eb4e8b7..4788c78bc71eec8569ede59086a782acd4410175 100644 (file)
@@ -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)