From 6fddcf6da018c1c394a3d841eede1118d94d4e36 Mon Sep 17 00:00:00 2001 From: Kurt Martin Date: Wed, 16 Dec 2015 15:37:45 -0800 Subject: [PATCH] Disable capabilities based on 3PAR licenses The 3PAR firmware is now reporting which licenses are enabled on the storage array. The 3PAR drivers will now use this information to enable/disable standard stat reporting for thin provisioning, QoS support and replication DocImpact Implements: blueprint 3par-license-check Change-Id: Ib5fb06b1c029d026f6f38fa3fdf7d62c2005c06e --- cinder/tests/unit/test_hpe3par.py | 22 +++++++++- cinder/volume/drivers/hpe/hpe_3par_common.py | 43 +++++++++++++++++-- .../3par-license-check-51a16b5247675760.yaml | 3 ++ 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/3par-license-check-51a16b5247675760.yaml diff --git a/cinder/tests/unit/test_hpe3par.py b/cinder/tests/unit/test_hpe3par.py index 40f10613b..cb9f64751 100644 --- a/cinder/tests/unit/test_hpe3par.py +++ b/cinder/tests/unit/test_hpe3par.py @@ -5211,9 +5211,15 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): config.goodness_function = GOODNESS_FUNCTION mock_client = self.setup_driver(config=config) mock_client.getCPG.return_value = self.cpgs[0] + # Purposely left out the Priority Optimization license in + # getStorageSystemInfo to test that QoS_support returns False. mock_client.getStorageSystemInfo.return_value = { 'id': self.CLIENT_ID, - 'serialNumber': '1234' + 'serialNumber': '1234', + 'licenseInfo': { + 'licenses': [{'name': 'Remote Copy'}, + {'name': 'Thin Provisioning (102400G)'}] + } } # cpg has no limit @@ -5243,6 +5249,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): self.assertEqual('FC', stats['storage_protocol']) self.assertTrue(stats['pools'][0]['thin_provisioning_support']) self.assertTrue(stats['pools'][0]['thick_provisioning_support']) + self.assertFalse(stats['pools'][0]['QoS_support']) self.assertEqual(86.0, stats['pools'][0]['provisioned_capacity_gb']) self.assertEqual(24.0, stats['pools'][0]['total_capacity_gb']) @@ -5285,6 +5292,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): self.assertEqual('FC', stats['storage_protocol']) self.assertTrue(stats['pools'][0]['thin_provisioning_support']) self.assertTrue(stats['pools'][0]['thick_provisioning_support']) + self.assertFalse(stats['pools'][0]['QoS_support']) self.assertEqual(86.0, stats['pools'][0]['provisioned_capacity_gb']) self.assertEqual(24.0, stats['pools'][0]['total_capacity_gb']) @@ -5316,6 +5324,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): self.assertEqual('FC', stats['storage_protocol']) self.assertTrue(stats['pools'][0]['thin_provisioning_support']) self.assertTrue(stats['pools'][0]['thick_provisioning_support']) + self.assertFalse(stats['pools'][0]['QoS_support']) total_capacity_gb = 8192 * const self.assertEqual(total_capacity_gb, stats['pools'][0]['total_capacity_gb']) @@ -5364,9 +5373,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): config.goodness_function = GOODNESS_FUNCTION mock_client = self.setup_driver(config=config, wsapi_version=wsapi) mock_client.getCPG.return_value = self.cpgs[0] + # Purposely left out the Thin Provisioning license in + # getStorageSystemInfo to test that thin_provisioning_support returns + # False. mock_client.getStorageSystemInfo.return_value = { 'id': self.CLIENT_ID, - 'serialNumber': '1234' + 'serialNumber': '1234', + 'licenseInfo': { + 'licenses': [{'name': 'Remote Copy'}, + {'name': 'Priority Optimization'}] + } } # cpg has no limit @@ -5383,6 +5399,8 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase): stats = self.driver.get_volume_stats(True) self.assertEqual('FC', stats['storage_protocol']) + self.assertFalse(stats['pools'][0]['thin_provisioning_support']) + self.assertTrue(stats['pools'][0]['QoS_support']) self.assertEqual(24.0, stats['pools'][0]['total_capacity_gb']) self.assertEqual(3.0, stats['pools'][0]['free_capacity_gb']) self.assertEqual(87.5, stats['pools'][0]['capacity_utilization']) diff --git a/cinder/volume/drivers/hpe/hpe_3par_common.py b/cinder/volume/drivers/hpe/hpe_3par_common.py index 8092b3db5..b189c011c 100644 --- a/cinder/volume/drivers/hpe/hpe_3par_common.py +++ b/cinder/volume/drivers/hpe/hpe_3par_common.py @@ -218,10 +218,11 @@ class HPE3PARCommon(object): 3.0.4 - Adds v2 managed replication support 3.0.5 - Adds v2 unmanaged replication support 3.0.6 - Adding manage/unmanage snapshot support + 3.0.7 - Enable standard capabilities based on 3PAR licenses """ - VERSION = "3.0.6" + VERSION = "3.0.7" stats = {} @@ -245,6 +246,11 @@ class HPE3PARCommon(object): EXTRA_SPEC_REP_SYNC_PERIOD = "replication:sync_period" RC_ACTION_CHANGE_TO_PRIMARY = 7 + # License values for reported capabilities + PRIORITY_OPT_LIC = "Priority Optimization" + THIN_PROV_LIC = "Thin Provisioning" + REMOTE_COPY_LIC = "Remote Copy" + # Valid values for volume type extra specs # The first value in the list is the default value valid_prov_values = ['thin', 'full', 'dedup'] @@ -1148,6 +1154,21 @@ class HPE3PARCommon(object): pools = [] info = self.client.getStorageSystemInfo() + qos_support = True + thin_support = True + remotecopy_support = True + if 'licenseInfo' in info: + if 'licenses' in info['licenseInfo']: + valid_licenses = info['licenseInfo']['licenses'] + qos_support = self._check_license_enabled( + valid_licenses, self.PRIORITY_OPT_LIC, + "QoS_support") + thin_support = self._check_license_enabled( + valid_licenses, self.THIN_PROV_LIC, + "Thin_provisioning_support") + remotecopy_support = self._check_license_enabled( + valid_licenses, self.REMOTE_COPY_LIC, + "Replication") for cpg_name in self.config.hpe3par_cpg: try: @@ -1210,8 +1231,8 @@ class HPE3PARCommon(object): 'total_capacity_gb': total_capacity, 'free_capacity_gb': free_capacity, 'provisioned_capacity_gb': provisioned_capacity, - 'QoS_support': True, - 'thin_provisioning_support': True, + 'QoS_support': qos_support, + 'thin_provisioning_support': thin_support, 'thick_provisioning_support': True, 'max_over_subscription_ratio': ( self.config.safe_get('max_over_subscription_ratio')), @@ -1234,7 +1255,8 @@ class HPE3PARCommon(object): 'consistencygroup_support': True, } - if hpe3parclient.version >= MIN_REP_CLIENT_VERSION: + if (hpe3parclient.version >= MIN_REP_CLIENT_VERSION + and remotecopy_support): pool['replication_enabled'] = self._replication_enabled pool['replication_type'] = ['sync', 'periodic'] pool['replication_count'] = len(self._replication_targets) @@ -1247,6 +1269,19 @@ class HPE3PARCommon(object): 'volume_backend_name': None, 'pools': pools} + def _check_license_enabled(self, valid_licenses, + license_to_check, capability): + """Check a license against valid licenses on the array.""" + if valid_licenses: + for license in valid_licenses: + if license_to_check in license.get('name'): + return True + LOG.debug(("'%(capability)s' requires a '%(license)s' " + "license which is not installed.") % + {'capability': capability, + 'license': license_to_check}) + return False + def _get_vlun(self, volume_name, hostname, lun_id=None, nsp=None): """find a VLUN on a 3PAR host.""" vluns = self.client.getHostVLUNs(hostname) diff --git a/releasenotes/notes/3par-license-check-51a16b5247675760.yaml b/releasenotes/notes/3par-license-check-51a16b5247675760.yaml new file mode 100644 index 000000000..51b075ecc --- /dev/null +++ b/releasenotes/notes/3par-license-check-51a16b5247675760.yaml @@ -0,0 +1,3 @@ +--- +features: + - Disable standard capabilities based on 3PAR licenses. -- 2.45.2