]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add extra spec capability for Nimble Cinder Driver
authorRaunak Kumar <rkumar@nimblestorage.com>
Mon, 6 Jul 2015 18:40:40 +0000 (11:40 -0700)
committerRaunak Kumar <rkumar@nimblestorage.com>
Mon, 27 Jul 2015 01:48:46 +0000 (18:48 -0700)
Supported Extra Specs are

1. Performance Policy Name
nimble:perfpol-name = <Performance Policy Name>

2. Encryption
nimble:encryption = "yes"

Implements: blueprint nimble-add-extra-specs-support

Change-Id: I45a18b189746b778f10eecbf669be7943828e28b

cinder/tests/unit/test_nimble.py [changed mode: 0644->0755]
cinder/volume/drivers/nimble.py [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 4e3d024..8bbcc28
@@ -19,6 +19,7 @@ from oslo_config import cfg
 from cinder import exception
 from cinder import test
 from cinder.volume.drivers import nimble
+from cinder.volume import volume_types
 
 
 CONF = cfg.CONF
@@ -59,13 +60,33 @@ FAKE_NEGATIVE_NETCONFIG_RESPONSE = {'err-list': {'err-list':
                                                  [{'code': 13}]}}
 
 FAKE_CREATE_VOLUME_POSITIVE_RESPONSE = {'err-list': {'err-list':
-                                                     [{'code': 0}]},
+                                        [{'code': 0}]},
                                         'name': "openstack-test11"}
 
+FAKE_CREATE_VOLUME_POSITIVE_RESPONSE_ENCRYPTION = {'err-list': {'err-list':
+                                                   [{'code': 0}]},
+                                                   'name':
+                                                   "openstack-test-encryption"}
+
+FAKE_CREATE_VOLUME_POSITIVE_RESPONSE_PERFPOLICY = {'err-list': {'err-list':
+                                                   [{'code': 0}]},
+                                                   'name':
+                                                   "openstack-test-perfpolicy"}
+
 FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE = {'err-list': {'err-list':
                                                      [{'code': 17}]},
                                         'name': "openstack-test11"}
 
+FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE_ENCRYPTION = {'err-list': {'err-list':
+                                                   [{'code': 17}]},
+                                                   'name':
+                                                   "openstack-test-encryption"}
+
+FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE_PERFPOLICY = {'err-list': {'err-list':
+                                                   [{'code': 17}]},
+                                                   'name':
+                                                   "openstack-test-perfpolicy"}
+
 FAKE_GENERIC_POSITIVE_RESPONSE = {'err-list': {'err-list':
                                                [{'code': 0}]}}
 
@@ -90,6 +111,8 @@ FAKE_GET_VOL_INFO_RESPONSE = {'err-list': {'err-list':
                                            [{'code': 0}]},
                               'vol': {'target-name': 'iqn.test'}}
 
+FAKE_TYPE_ID = 12345
+
 
 def create_configuration(username, password, ip_address,
                          pool_name=None, subnet_label=None,
@@ -214,6 +237,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
             'provider_auth': None},
             self.driver.create_volume({'name': 'testvolume',
                                        'size': 1,
+                                       'volume_type_id': None,
                                        'display_name': '',
                                        'display_description': ''}))
         self.mock_client_service.service.createVol.assert_called_once_with(
@@ -222,7 +246,84 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
                          'name': 'testvolume', 'reserve': 0,
                          'online': True, 'pool-name': 'default',
                          'size': 1073741824, 'quota': 1073741824,
-                         'perfpol-name': 'default', 'description': ''},
+                         'perfpol-name': 'default', 'description': '',
+                         'encryptionAttr': {'cipher': 3}},
+                'sid': 'a9b9aba7'})
+
+    @mock.patch(NIMBLE_URLLIB2)
+    @mock.patch(NIMBLE_CLIENT)
+    @mock.patch.object(volume_types, 'get_volume_type_extra_specs',
+                       mock.Mock(type_id=FAKE_TYPE_ID, return_value={
+                                 'nimble:perfpol-name': 'default',
+                                 'nimble:encryption': 'yes'}))
+    @NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
+        'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
+    def test_create_volume_encryption_positive(self):
+        self.mock_client_service.service.createVol.return_value = \
+            FAKE_CREATE_VOLUME_POSITIVE_RESPONSE_ENCRYPTION
+        self.mock_client_service.service.getVolInfo.return_value = \
+            FAKE_GET_VOL_INFO_RESPONSE
+        self.mock_client_service.service.getNetConfig.return_value = \
+            FAKE_POSITIVE_NETCONFIG_RESPONSE
+
+        self.assertEqual({
+            'provider_location': '172.18.108.21:3260 iqn.test 0',
+            'provider_auth': None},
+            self.driver.create_volume({'name': 'testvolume-encryption',
+                                       'size': 1,
+                                       'volume_type_id': FAKE_TYPE_ID,
+                                       'display_name': '',
+                                       'display_description': ''}))
+
+        mock_volume_type = volume_types.get_volume_type_extra_specs
+        mock_volume_type.assert_called_once_with(FAKE_TYPE_ID)
+
+        self.mock_client_service.service.createVol.assert_called_once_with(
+            request={
+                'attr': {'snap-quota': 1073741824, 'warn-level': 858993459,
+                         'name': 'testvolume-encryption', 'reserve': 0,
+                         'online': True, 'pool-name': 'default',
+                         'size': 1073741824, 'quota': 1073741824,
+                         'perfpol-name': 'default', 'description': '',
+                         'encryptionAttr': {'cipher': 2}},
+                'sid': 'a9b9aba7'})
+
+    @mock.patch(NIMBLE_URLLIB2)
+    @mock.patch(NIMBLE_CLIENT)
+    @mock.patch.object(volume_types, 'get_volume_type_extra_specs',
+                       mock.Mock(type_id=FAKE_TYPE_ID, return_value={
+                                 'nimble:perfpol-name': 'VMware ESX',
+                                 'nimble:encryption': 'no'}))
+    @NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
+        'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
+    def test_create_volume_perfpolicy_positive(self):
+        self.mock_client_service.service.createVol.return_value = \
+            FAKE_CREATE_VOLUME_POSITIVE_RESPONSE_PERFPOLICY
+        self.mock_client_service.service.getVolInfo.return_value = \
+            FAKE_GET_VOL_INFO_RESPONSE
+        self.mock_client_service.service.getNetConfig.return_value = \
+            FAKE_POSITIVE_NETCONFIG_RESPONSE
+
+        self.assertEqual(
+            {'provider_location': '172.18.108.21:3260 iqn.test 0',
+             'provider_auth': None},
+            self.driver.create_volume({'name': 'testvolume-perfpolicy',
+                                       'size': 1,
+                                       'volume_type_id': FAKE_TYPE_ID,
+                                       'display_name': '',
+                                       'display_description': ''}))
+
+        mock_volume_type = volume_types.get_volume_type_extra_specs
+        mock_volume_type.assert_called_once_with(FAKE_TYPE_ID)
+
+        self.mock_client_service.service.createVol.assert_called_once_with(
+            request={
+                'attr': {'snap-quota': 1073741824, 'warn-level': 858993459,
+                         'name': 'testvolume-perfpolicy', 'reserve': 0,
+                         'online': True, 'pool-name': 'default',
+                         'size': 1073741824, 'quota': 1073741824,
+                         'perfpol-name': 'VMware ESX', 'description': '',
+                         'encryptionAttr': {'cipher': 3}},
                 'sid': 'a9b9aba7'})
 
     @mock.patch(NIMBLE_URLLIB2)
@@ -237,6 +338,39 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
             self.driver.create_volume,
             {'name': 'testvolume',
              'size': 1,
+             'volume_type_id': None,
+             'display_name': '',
+             'display_description': ''})
+
+    @mock.patch(NIMBLE_URLLIB2)
+    @mock.patch(NIMBLE_CLIENT)
+    @NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
+        'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
+    def test_create_volume_encryption_negative(self):
+        self.mock_client_service.service.createVol.return_value = \
+            FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE_ENCRYPTION
+        self.assertRaises(
+            exception.VolumeBackendAPIException,
+            self.driver.create_volume,
+            {'name': 'testvolume-encryption',
+             'size': 1,
+             'volume_type_id': None,
+             'display_name': '',
+             'display_description': ''})
+
+    @mock.patch(NIMBLE_URLLIB2)
+    @mock.patch(NIMBLE_CLIENT)
+    @NimbleDriverBaseTestCase.client_mock_decorator(create_configuration(
+        'nimble', 'nimble_pass', '10.18.108.55', 'default', '*'))
+    def test_create_volume_perfpolicy_negative(self):
+        self.mock_client_service.service.createVol.return_value = \
+            FAKE_CREATE_VOLUME_NEGATIVE_RESPONSE_PERFPOLICY
+        self.assertRaises(
+            exception.VolumeBackendAPIException,
+            self.driver.create_volume,
+            {'name': 'testvolume-perfpolicy',
+             'size': 1,
+             'volume_type_id': None,
              'display_name': '',
              'display_description': ''})
 
@@ -328,7 +462,7 @@ class NimbleDriverVolumeTestCase(NimbleDriverBaseTestCase):
     def test_get_volume_stats(self):
         self.mock_client_service.service.getGroupConfig.return_value = \
             FAKE_POSITIVE_GROUP_CONFIG_RESPONSE
-        expected_res = {'driver_version': '1.0',
+        expected_res = {'driver_version': '1.1.0',
                         'total_capacity_gb': 7466.30419921875,
                         'QoS_support': False,
                         'reserved_percentage': 0,
old mode 100644 (file)
new mode 100755 (executable)
index 99ff7b5..0bd4bb8
@@ -33,9 +33,16 @@ from suds import client
 from cinder import exception
 from cinder.i18n import _, _LE, _LI
 from cinder.volume.drivers.san import san
+from cinder.volume import volume_types
 
 
-DRIVER_VERSION = '1.0'
+DRIVER_VERSION = '1.1.0'
+AES_256_XTS_CIPHER = 2
+DEFAULT_CIPHER = 3
+EXTRA_SPEC_ENCRYPTION = 'nimble:encryption'
+EXTRA_SPEC_PERF_POLICY = 'nimble:perfpol-name'
+DEFAULT_PERF_POLICY_SETTING = 'default'
+DEFAULT_ENCRYPTION_SETTING = 'no'
 VOL_EDIT_MASK = 4 + 16 + 32 + 64 + 512
 SOAP_PORT = 5391
 SM_ACL_APPLY_TO_BOTH = 3
@@ -74,6 +81,7 @@ class NimbleISCSIDriver(san.SanISCSIDriver):
 
     Version history:
         1.0 - Initial driver
+        1.1.0 - Added Extra Spec Capability
 
     """
 
@@ -412,6 +420,7 @@ class NimbleAPIExecutor(object):
         self.sid = None
         self.username = kwargs['username']
         self.password = kwargs['password']
+
         wsdl_url = 'https://%s/wsdl/NsGroupManagement.wsdl' % (kwargs['ip'])
         LOG.debug('Using Nimble wsdl_url: %s', wsdl_url)
         self.err_string_dict = self._create_err_code_to_str_mapper(wsdl_url)
@@ -469,6 +478,23 @@ class NimbleAPIExecutor(object):
         response = self._execute_get_netconfig(name)
         return response['config']
 
+    def _get_volumetype_extraspecs(self, volume):
+        specs = {}
+
+        type_id = volume['volume_type_id']
+        if type_id is not None:
+            specs = volume_types.get_volume_type_extra_specs(type_id)
+        return specs
+
+    def _get_extra_spec_values(self, extra_specs):
+        """Nimble specific extra specs."""
+        perf_policy_name = extra_specs.get(EXTRA_SPEC_PERF_POLICY,
+                                           DEFAULT_PERF_POLICY_SETTING)
+        encryption = extra_specs.get(EXTRA_SPEC_ENCRYPTION,
+                                     DEFAULT_ENCRYPTION_SETTING)
+
+        return perf_policy_name, encryption
+
     @_connection_checker
     @_response_checker
     def _execute_create_vol(self, volume, pool_name, reserve):
@@ -482,26 +508,40 @@ class NimbleAPIExecutor(object):
         # Limit description size to 254 characters
         description = description[:254]
 
-        LOG.info(_LI('Creating a new volume=%(vol)s size=%(size)s'
-                     ' reserve=%(reserve)s in pool=%(pool)s'
-                     ' description=%(description)s'),
-                 {'vol': volume['name'],
-                  'size': volume_size,
-                  'reserve': reserve,
-                  'pool': pool_name,
-                  'description': description})
+        specs = self._get_volumetype_extraspecs(volume)
+        perf_policy_name, encrypt = self._get_extra_spec_values(specs)
+        # default value of cipher for encryption
+        cipher = DEFAULT_CIPHER
+        if encrypt.lower() == 'yes':
+            cipher = AES_256_XTS_CIPHER
+
+        LOG.debug('Creating a new volume=%(vol)s size=%(size)s'
+                  ' reserve=%(reserve)s in pool=%(pool)s'
+                  ' description=%(description)s with Extra Specs'
+                  ' perfpol-name=%(perfpol-name)s'
+                  ' encryption=%(encryption)s cipher=%(cipher)s',
+                  {'vol': volume['name'],
+                   'size': volume_size,
+                   'reserve': reserve,
+                   'pool': pool_name,
+                   'description': description,
+                   'perfpol-name': perf_policy_name,
+                   'encryption': encrypt,
+                   'cipher': cipher})
+
         return self.client.service.createVol(
             request={'sid': self.sid,
                      'attr': {'name': volume['name'],
                               'description': description,
                               'size': volume_size,
-                              'perfpol-name': 'default',
                               'reserve': reserve_size,
                               'warn-level': int(volume_size * WARN_LEVEL),
                               'quota': volume_size,
                               'snap-quota': volume_size,
                               'online': True,
-                              'pool-name': pool_name}})
+                              'pool-name': pool_name,
+                              'perfpol-name': perf_policy_name,
+                              'encryptionAttr': {'cipher': cipher}}})
 
     def create_vol(self, volume, pool_name, reserve):
         """Execute createVol API."""