]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
VNX Cinder Driver should report 0 free_capacity_gb in some scenarios
authorJeegn Chen <jeegn.chen@emc.com>
Thu, 2 Apr 2015 08:42:08 +0000 (16:42 +0800)
committerJeegn Chen <jeegn.chen@emc.com>
Fri, 10 Apr 2015 06:36:39 +0000 (14:36 +0800)
When the storage pool is Initializing, Offline or Deleting, no more LUNs
can be created before the pool gets out of the state.
So when a pool is in the 3 states, its free capacity is de facto 0.

This patch is to add logic to report 0 free capacity accordingly.

Change-Id: I4ef56d48e987795a48e6dcb23615e4b2a7580452
Closes-Bug: #1431233

cinder/tests/test_emc_vnxdirect.py
cinder/volume/drivers/emc/emc_vnx_cli.py

index e1ed1a6c6f6800de98c1b87fdd4249783dc93600..efc64d7595098253ad32bd4827e8bddb613228e4 100644 (file)
@@ -381,19 +381,19 @@ class EMCVNXCLIDriverTestData(object):
                '123456789054321': ['1122334455667777']}
 
     POOL_PROPERTY_CMD = ('storagepool', '-list', '-name', 'unit_test_pool',
-                         '-userCap', '-availableCap')
+                         '-userCap', '-availableCap', '-state')
 
     POOL_PROPERTY_W_FASTCACHE_CMD = ('storagepool', '-list', '-name',
                                      'unit_test_pool', '-availableCap',
-                                     '-userCap', '-fastcache')
+                                     '-userCap', '-fastcache', '-state')
 
     def POOL_GET_ALL_CMD(self, withfastcache=False):
         if withfastcache:
             return ('storagepool', '-list', '-availableCap',
-                    '-userCap', '-fastcache')
+                    '-userCap', '-fastcache', '-state')
         else:
             return ('storagepool', '-list', '-availableCap',
-                    '-userCap')
+                    '-userCap', '-state')
 
     def POOL_GET_ALL_RESULT(self, withfastcache=False):
         if withfastcache:
@@ -404,6 +404,7 @@ class EMCVNXCLIDriverTestData(object):
                     "Available Capacity (Blocks):  6512292864\n"
                     "Available Capacity (GBs):  3105.303\n"
                     "FAST Cache:  Enabled\n"
+                    "State: Ready\n"
                     "\n"
                     "Pool Name:  unit test pool 2\n"
                     "Pool ID:  1\n"
@@ -411,7 +412,8 @@ class EMCVNXCLIDriverTestData(object):
                     "User Capacity (GBs):  4099.992\n"
                     "Available Capacity (Blocks):  8356663296\n"
                     "Available Capacity (GBs):  3984.768\n"
-                    "FAST Cache:  Disabled\n", 0)
+                    "FAST Cache:  Disabled\n"
+                    "State: Ready\n", 0)
         else:
             return ("Pool Name:  unit_test_pool1\n"
                     "Pool ID:  0\n"
@@ -419,13 +421,29 @@ class EMCVNXCLIDriverTestData(object):
                     "User Capacity (GBs):  3281.146\n"
                     "Available Capacity (Blocks):  6512292864\n"
                     "Available Capacity (GBs):  3105.303\n"
+                    "State: Ready\n"
                     "\n"
                     "Pool Name:  unit test pool 2\n"
                     "Pool ID:  1\n"
                     "User Capacity (Blocks):  8598306816\n"
                     "User Capacity (GBs):  4099.992\n"
                     "Available Capacity (Blocks):  8356663296\n"
-                    "Available Capacity (GBs):  3984.768\n", 0)
+                    "Available Capacity (GBs):  3984.768\n"
+                    "State: Ready\n", 0)
+
+    def POOL_GET_ALL_STATES_TEST(self, states=['Ready']):
+        output = ""
+        for i, stat in enumerate(states):
+            out = ("Pool Name:  Pool_" + str(i) + "\n"
+                   "Pool ID:  " + str(i) + "\n"
+                   "User Capacity (Blocks):  8598306816\n"
+                   "User Capacity (GBs):  4099.992\n"
+                   "Available Capacity (Blocks):  8356663296\n"
+                   "Available Capacity (GBs):  3984.768\n"
+                   "FAST Cache:  Enabled\n"
+                   "State: " + stat + "\n\n")
+            output += out
+        return (output, 0)
 
     NDU_LIST_CMD = ('ndu', '-list')
     NDU_LIST_RESULT = ("Name of the software package:   -Compression " +
@@ -653,6 +671,7 @@ User Capacity (Blocks):  6881061888
 User Capacity (GBs):  3281.146
 Available Capacity (Blocks):  6832207872
 Available Capacity (GBs):  3257.851
+State: Ready
 
 """, 0)
 
@@ -663,7 +682,8 @@ Available Capacity (GBs):  3257.851
         "User Capacity (GBs):  3281.146\n"
         "Available Capacity (Blocks):  6832207872\n"
         "Available Capacity (GBs):  3257.851\n"
-        "FAST Cache:  Enabled\n\n", 0)
+        "FAST Cache:  Enabled\n"
+        "State: Ready\n\n", 0)
 
     ALL_PORTS = ("SP:  A\n" +
                  "Port ID:  4\n" +
@@ -2857,7 +2877,8 @@ Time Remaining:  0 second(s)
             'total_capacity_gb': 10,
             'free_capacity_gb': 5,
             'pool_name': "unit_test_pool",
-            'fast_cache_enabled': 'True'})
+            'fast_cache_enabled': 'True',
+            'state': 'Ready'})
 
         self.driver.update_volume_stats()
         self.driver.create_volume(self.testData.test_volume_with_type)
@@ -3313,6 +3334,29 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase):
             'fast_support': 'False'}
         self.assertEqual(expected_pool_stats2, pool_stats2)
 
+    def test_get_volume_stats_storagepool_states(self):
+        commands = [self.testData.POOL_GET_ALL_CMD(False)]
+        results = [self.testData.POOL_GET_ALL_STATES_TEST
+                   (['Initializing', 'Ready', 'Faulted',
+                     'Offline', 'Deleting'])]
+        self.driverSetup(commands, results)
+        stats = self.driver.get_volume_stats(True)
+        self.assertTrue(
+            stats['pools'][0]['free_capacity_gb'] == 0,
+            "free_capacity_gb is incorrect")
+        self.assertTrue(
+            stats['pools'][1]['free_capacity_gb'] != 0,
+            "free_capacity_gb is incorrect")
+        self.assertTrue(
+            stats['pools'][2]['free_capacity_gb'] != 0,
+            "free_capacity_gb is incorrect")
+        self.assertTrue(
+            stats['pools'][3]['free_capacity_gb'] == 0,
+            "free_capacity_gb is incorrect")
+        self.assertTrue(
+            stats['pools'][4]['free_capacity_gb'] == 0,
+            "free_capacity_gb is incorrect")
+
     @mock.patch(
         "eventlet.event.Event.wait",
         mock.Mock(return_value=None))
index 54750e382d342388d91f35d6cf93db9a36689239..aa915d8090957843fb38010ea96cb0bfc475d0d6 100644 (file)
@@ -217,6 +217,10 @@ class CommandLineHelper(object):
     LUN_WITH_POOL = [LUN_STATE, LUN_CAPACITY, LUN_OWNER,
                      LUN_ATTACHEDSNAP, LUN_POOL]
 
+    POOL_STATE = PropertyDescriptor(
+        '-state',
+        'State:\s*(.*)\s*',
+        'state')
     POOL_TOTAL_CAPACITY = PropertyDescriptor(
         '-userCap',
         'User Capacity \(GBs\):\s*(.*)\s*',
@@ -237,7 +241,7 @@ class CommandLineHelper(object):
         'Pool Name:\s*(.*)\s*',
         'pool_name')
 
-    POOL_ALL = [POOL_TOTAL_CAPACITY, POOL_FREE_CAPACITY]
+    POOL_ALL = [POOL_TOTAL_CAPACITY, POOL_FREE_CAPACITY, POOL_STATE]
 
     MAX_POOL_LUNS = PropertyDescriptor(
         '-maxPoolLUNs',
@@ -1652,7 +1656,7 @@ class CommandLineHelper(object):
 class EMCVnxCliBase(object):
     """This class defines the functions to use the native CLI functionality."""
 
-    VERSION = '05.03.05'
+    VERSION = '05.03.06'
     stats = {'driver_version': VERSION,
              'storage_protocol': None,
              'vendor_name': 'EMC',
@@ -2055,25 +2059,35 @@ class EMCVnxCliBase(object):
         pool_stats['pool_name'] = pool['pool_name']
         pool_stats['total_capacity_gb'] = pool['total_capacity_gb']
         pool_stats['reserved_percentage'] = 0
-        pool_stats['free_capacity_gb'] = pool['free_capacity_gb']
-        # Some extra capacity will be used by meta data of pool LUNs.
-        # The overhead is about LUN_Capacity * 0.02 + 3 GB
-        # reserved_percentage will be used to make sure the scheduler
-        # takes the overhead into consideration.
-        # Assume that all the remaining capacity is to be used to create
-        # a thick LUN, reserved_percentage is estimated as follows:
-        reserved = (((0.02 * pool['free_capacity_gb'] + 3) /
-                     (1.02 * pool['total_capacity_gb'])) * 100)
-        pool_stats['reserved_percentage'] = int(math.ceil(min(reserved, 100)))
-        if self.check_max_pool_luns_threshold:
-            pool_feature = self._client.get_pool_feature_properties(poll=False)
-            if (pool_feature['max_pool_luns']
-                    <= pool_feature['total_pool_luns']):
-                LOG.warning(_LW("Maximum number of Pool LUNs, %s, "
-                                "have been created. "
-                                "No more LUN creation can be done."),
-                            pool_feature['max_pool_luns'])
-                pool_stats['free_capacity_gb'] = 0
+
+        # Handle pool state Initializing, Ready, Faulted, Offline or Deleting.
+        if pool['state'] in ('Initializing', 'Offline', 'Deleting'):
+            pool_stats['free_capacity_gb'] = 0
+            LOG.warning(_LW("Storage Pool '%(pool)s' is '%(state)s'."),
+                        {'pool': pool_stats['pool_name'],
+                         'state': pool['state']})
+        else:
+            pool_stats['free_capacity_gb'] = pool['free_capacity_gb']
+            # Some extra capacity will be used by meta data of pool LUNs.
+            # The overhead is about LUN_Capacity * 0.02 + 3 GB
+            # reserved_percentage will be used to make sure the scheduler
+            # takes the overhead into consideration.
+            # Assume that all the remaining capacity is to be used to create
+            # a thick LUN, reserved_percentage is estimated as follows:
+            reserved = (((0.02 * pool['free_capacity_gb'] + 3) /
+                         (1.02 * pool['total_capacity_gb'])) * 100)
+            pool_stats['reserved_percentage'] = int(math.ceil
+                                                    (min(reserved, 100)))
+            if self.check_max_pool_luns_threshold:
+                pool_feature = self._client.get_pool_feature_properties(
+                    poll=False)
+                if (pool_feature['max_pool_luns'] <=
+                        pool_feature['total_pool_luns']):
+                    LOG.warning(_LW("Maximum number of Pool LUNs, %s, "
+                                    "have been created. "
+                                    "No more LUN creation can be done."),
+                                pool_feature['max_pool_luns'])
+                    pool_stats['free_capacity_gb'] = 0
 
         array_serial = self.get_array_serial()
         pool_stats['location_info'] = ('%(pool_name)s|%(array_serial)s' %
@@ -3010,10 +3024,12 @@ class EMCVnxCliPool(EMCVnxCliBase):
         if '-FASTCache' in self.enablers:
             properties = [self._client.POOL_FREE_CAPACITY,
                           self._client.POOL_TOTAL_CAPACITY,
-                          self._client.POOL_FAST_CACHE]
+                          self._client.POOL_FAST_CACHE,
+                          self._client.POOL_STATE]
         else:
             properties = [self._client.POOL_FREE_CAPACITY,
-                          self._client.POOL_TOTAL_CAPACITY]
+                          self._client.POOL_TOTAL_CAPACITY,
+                          self._client.POOL_STATE]
 
         pool = self._client.get_pool(self.storage_pool,
                                      properties=properties,
@@ -3069,10 +3085,12 @@ class EMCVnxCliArray(EMCVnxCliBase):
         if '-FASTCache' in self.enablers:
             properties = [self._client.POOL_FREE_CAPACITY,
                           self._client.POOL_TOTAL_CAPACITY,
-                          self._client.POOL_FAST_CACHE]
+                          self._client.POOL_FAST_CACHE,
+                          self._client.POOL_STATE]
         else:
             properties = [self._client.POOL_FREE_CAPACITY,
-                          self._client.POOL_TOTAL_CAPACITY]
+                          self._client.POOL_TOTAL_CAPACITY,
+                          self._client.POOL_STATE]
         pool_list = self._client.get_pool_list(properties, False)
 
         self.stats['pools'] = map(lambda pool: self._build_pool_stats(pool),