From: Kurt Martin Date: Wed, 16 Dec 2015 23:37:45 +0000 (-0800) Subject: Disable capabilities based on 3PAR licenses X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=6fddcf6da018c1c394a3d841eede1118d94d4e36;p=openstack-build%2Fcinder-build.git 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 --- 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.