]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Disable capabilities based on 3PAR licenses
authorKurt Martin <kurt.f.martin@hpe.com>
Wed, 16 Dec 2015 23:37:45 +0000 (15:37 -0800)
committerKurt Martin <kurt.f.martin@hpe.com>
Sat, 19 Dec 2015 00:15:16 +0000 (16:15 -0800)
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
cinder/volume/drivers/hpe/hpe_3par_common.py
releasenotes/notes/3par-license-check-51a16b5247675760.yaml [new file with mode: 0644]

index 40f10613bf6d4d05dacc756fa14635061d5153db..cb9f647516d5591ab961e582a77c90c9ecadc45b 100644 (file)
@@ -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'])
index 8092b3db555cbd1f8d37e06ac25a8076e84efbf4..b189c011ce038a6af151ef0ab8f223daf8126dc6 100644 (file)
@@ -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 (file)
index 0000000..51b075e
--- /dev/null
@@ -0,0 +1,3 @@
+---
+features:
+  - Disable standard capabilities based on 3PAR licenses.