From a47925b0f936440aad572c53d62cf483e6cac022 Mon Sep 17 00:00:00 2001 From: Jeegn Chen Date: Thu, 2 Apr 2015 16:42:08 +0800 Subject: [PATCH] VNX Cinder Driver should report 0 free_capacity_gb in some scenarios 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 | 60 ++++++++++++++++++--- cinder/volume/drivers/emc/emc_vnx_cli.py | 68 +++++++++++++++--------- 2 files changed, 95 insertions(+), 33 deletions(-) diff --git a/cinder/tests/test_emc_vnxdirect.py b/cinder/tests/test_emc_vnxdirect.py index e1ed1a6c6..efc64d759 100644 --- a/cinder/tests/test_emc_vnxdirect.py +++ b/cinder/tests/test_emc_vnxdirect.py @@ -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)) diff --git a/cinder/volume/drivers/emc/emc_vnx_cli.py b/cinder/volume/drivers/emc/emc_vnx_cli.py index 54750e382..aa915d809 100644 --- a/cinder/volume/drivers/emc/emc_vnx_cli.py +++ b/cinder/volume/drivers/emc/emc_vnx_cli.py @@ -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), -- 2.45.2