From: Tina Date: Mon, 18 May 2015 01:12:10 +0000 (-0400) Subject: Multiple pools support enhancement in VNX cinder driver X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=2b04acc3ccc4c827f17e351b1a38b068cf11eb9a;p=openstack-build%2Fcinder-build.git Multiple pools support enhancement in VNX cinder driver This introduced a new option "storage_vnx_pool_names" which replaced the existing option "storage_vnx_pool_name". The new option allows user specify more than one pools to be managed by a vnx cinder back end. DocImpact This change will introduce a new configuration option, so that the documentation need to be updated. Change-Id: Id6c3a1ecb32484fbd35dbb5814262103b322249e Closes-Bug: 1456062 --- diff --git a/cinder/tests/unit/test_emc_vnxdirect.py b/cinder/tests/unit/test_emc_vnxdirect.py index 8fb7cdf9b..191081952 100644 --- a/cinder/tests/unit/test_emc_vnxdirect.py +++ b/cinder/tests/unit/test_emc_vnxdirect.py @@ -390,7 +390,7 @@ class EMCVNXCLIDriverTestData(object): def POOL_GET_ALL_RESULT(self, withfastcache=False): if withfastcache: - return ("Pool Name: unit_test_pool1\n" + return ("Pool Name: unit_test_pool\n" "Pool ID: 0\n" "User Capacity (Blocks): 6881061888\n" "User Capacity (GBs): 3281.146\n" @@ -400,7 +400,7 @@ class EMCVNXCLIDriverTestData(object): "FAST Cache: Enabled\n" "State: Ready\n" "\n" - "Pool Name: unit test pool 2\n" + "Pool Name: unit_test_pool2\n" "Pool ID: 1\n" "User Capacity (Blocks): 8598306816\n" "User Capacity (GBs): 4099.992\n" @@ -410,7 +410,7 @@ class EMCVNXCLIDriverTestData(object): "FAST Cache: Disabled\n" "State: Ready\n", 0) else: - return ("Pool Name: unit_test_pool1\n" + return ("Pool Name: unit_test_pool\n" "Pool ID: 0\n" "User Capacity (Blocks): 6881061888\n" "User Capacity (GBs): 3281.146\n" @@ -419,7 +419,7 @@ class EMCVNXCLIDriverTestData(object): "Total Subscribed Capacity (GBs): 536.140\n" "State: Ready\n" "\n" - "Pool Name: unit test pool 2\n" + "Pool Name: unit_test_pool2\n" "Pool ID: 1\n" "User Capacity (Blocks): 8598306816\n" "User Capacity (GBs): 4099.992\n" @@ -428,6 +428,16 @@ class EMCVNXCLIDriverTestData(object): "Total Subscribed Capacity (GBs): 636.240\n" "State: Ready\n", 0) + def POOL_GET_STATE_RESULT(self, pools): + output = [] + for i, po in enumerate(pools): + if i != 0: + output.append("\n") + output.append("Pool Name: %s" % po['pool_name']) + output.append("Pool ID: %s" % i) + output.append("State: %s" % po['state']) + return ("\n".join(output), 0) + def POOL_GET_ALL_STATES_TEST(self, states=['Ready']): output = "" for i, stat in enumerate(states): @@ -828,7 +838,7 @@ State: Ready def LUN_PROPERTY(self, name, is_thin=False, has_snap=False, size=1, state='Ready', faulted='false', operation='None', - lunid=1): + lunid=1, pool_name='unit_test_pool'): return (""" LOGICAL UNIT NUMBER %(lunid)s Name: %(name)s @@ -841,7 +851,7 @@ State: Ready User Capacity (GBs): %(size)d Consumed Capacity (Blocks): 2149576704 Consumed Capacity (GBs): 1024.998 - Pool Name: unit_test_pool + Pool Name: %(pool_name)s Current State: %(state)s Status: OK(0x0) Is Faulted: %(faulted)s @@ -855,6 +865,7 @@ State: Ready 'name': name, 'has_snap': 'FakeSnap' if has_snap else 'N/A', 'size': size, + 'pool_name': pool_name, 'state': state, 'faulted': faulted, 'operation': operation, @@ -1014,7 +1025,7 @@ class DriverTestCaseBase(test.TestCase): self.configuration.initiator_auto_registration = True self.configuration.check_max_pool_luns_threshold = False self.stubs.Set(self.configuration, 'safe_get', - self.fake_safe_get({'storage_vnx_pool_name': + self.fake_safe_get({'storage_vnx_pool_names': 'unit_test_pool', 'volume_backend_name': 'namedbackend'})) @@ -1024,14 +1035,14 @@ class DriverTestCaseBase(test.TestCase): self.configuration.iscsi_initiators = '{"fakehost": ["10.0.0.2"]}' def driverSetup(self, commands=tuple(), results=tuple()): - self.driver = self.generateDriver(self.configuration) + self.driver = self.generate_driver(self.configuration) fake_command_execute = self.get_command_execute_simulator( commands, results) fake_cli = mock.Mock(side_effect=fake_command_execute) self.driver.cli._client.command_execute = fake_cli return fake_cli - def generateDriver(self, conf): + def generate_driver(self, conf): raise NotImplementedError def get_command_execute_simulator(self, commands=tuple(), @@ -1078,6 +1089,10 @@ class DriverTestCaseBase(test.TestCase): def fake_command_execute_for_driver_setup(self, *command, **kwargv): if command == ('connection', '-getport', '-address', '-vlanid'): return self.testData.ALL_PORTS + elif command == ('storagepool', '-list', '-state'): + return self.testData.POOL_GET_STATE_RESULT([ + {'pool_name': self.testData.test_pool_name, 'state': "Ready"}, + {'pool_name': "unit_test_pool2", 'state': "Ready"}]) else: return SUCCEED @@ -1088,7 +1103,7 @@ class DriverTestCaseBase(test.TestCase): class EMCVNXCLIDriverISCSITestCase(DriverTestCaseBase): - def generateDriver(self, conf): + def generate_driver(self, conf): return emc_cli_iscsi.EMCCLIISCSIDriver(configuration=conf) @mock.patch( @@ -1339,9 +1354,9 @@ class EMCVNXCLIDriverISCSITestCase(DriverTestCaseBase): def test_get_volume_stats(self): commands = [self.testData.NDU_LIST_CMD, - self.testData.POOL_PROPERTY_W_FASTCACHE_CMD] + self.testData.POOL_GET_ALL_CMD(True)] results = [self.testData.NDU_LIST_RESULT, - self.testData.POOL_PROPERTY_W_FASTCACHE] + self.testData.POOL_GET_ALL_RESULT(True)] self.driverSetup(commands, results) stats = self.driver.get_volume_stats(True) @@ -1360,11 +1375,11 @@ class EMCVNXCLIDriverISCSITestCase(DriverTestCaseBase): pool_stats = stats['pools'][0] expected_pool_stats = { - 'free_capacity_gb': 3257.851, - 'reserved_percentage': 3, + 'free_capacity_gb': 3105.303, + 'reserved_percentage': 2, 'location_info': 'unit_test_pool|fakeSerial', 'total_capacity_gb': 3281.146, - 'provisioned_capacity_gb': 636.240, + 'provisioned_capacity_gb': 536.14, 'compression_support': 'True', 'deduplication_support': 'True', 'thin_provisioning_support': True, @@ -1379,10 +1394,10 @@ class EMCVNXCLIDriverISCSITestCase(DriverTestCaseBase): def test_get_volume_stats_too_many_luns(self): commands = [self.testData.NDU_LIST_CMD, - self.testData.POOL_PROPERTY_W_FASTCACHE_CMD, + self.testData.POOL_GET_ALL_CMD(True), self.testData.POOL_FEATURE_INFO_POOL_LUNS_CMD()] results = [self.testData.NDU_LIST_RESULT, - self.testData.POOL_PROPERTY_W_FASTCACHE, + self.testData.POOL_GET_ALL_RESULT(True), self.testData.POOL_FEATURE_INFO_POOL_LUNS(1000, 1000)] fake_cli = self.driverSetup(commands, results) @@ -1403,7 +1418,7 @@ class EMCVNXCLIDriverISCSITestCase(DriverTestCaseBase): self.assertTrue(stats['driver_version'] is not None, "driver_version is not returned") self.assertTrue( - pool_stats['free_capacity_gb'] == 3257.851, + pool_stats['free_capacity_gb'] == 3105.303, "free_capacity_gb is incorrect") @mock.patch("cinder.volume.drivers.emc.emc_vnx_cli." @@ -2374,15 +2389,7 @@ Time Remaining: 0 second(s) commands = [lun_rename_cmd] results = [SUCCEED] - self.configuration.storage_vnx_pool_name = \ - self.testData.test_pool_name - self.driver = emc_cli_iscsi.EMCCLIISCSIDriver( - configuration=self.configuration) - assert isinstance(self.driver.cli, emc_vnx_cli.EMCVnxCliPool) - # mock the command executor - fake_command_execute = self.get_command_execute_simulator( - commands, results) - fake_cli = mock.MagicMock(side_effect=fake_command_execute) + fake_cli = self.driverSetup(commands, results) self.driver.cli._client.command_execute = fake_cli self.driver.manage_existing( self.testData.test_volume_with_type, @@ -2395,18 +2402,10 @@ Time Remaining: 0 second(s) '-state', '-userCap', '-owner', '-attachedSnapshot', '-poolName') commands = [get_lun_cmd] - - results = [self.testData.LUN_PROPERTY('lun_name')] invalid_pool_name = "fake_pool" - self.configuration.storage_vnx_pool_name = invalid_pool_name - self.driver = emc_cli_iscsi.EMCCLIISCSIDriver( - configuration=self.configuration) - assert isinstance(self.driver.cli, emc_vnx_cli.EMCVnxCliPool) - # mock the command executor - fake_command_execute = self.get_command_execute_simulator( - commands, results) - fake_cli = mock.MagicMock(side_effect=fake_command_execute) - self.driver.cli._client.command_execute = fake_cli + results = [self.testData.LUN_PROPERTY('lun_name', + pool_name=invalid_pool_name)] + fake_cli = self.driverSetup(commands, results) ex = self.assertRaises( exception.ManageExistingInvalidReference, self.driver.manage_existing_get_size, @@ -2425,19 +2424,7 @@ Time Remaining: 0 second(s) test_size = 2 commands = [get_lun_cmd] results = [self.testData.LUN_PROPERTY('lun_name', size=test_size)] - - self.configuration.storage_vnx_pool_name = \ - self.testData.test_pool_name - self.driver = emc_cli_iscsi.EMCCLIISCSIDriver( - configuration=self.configuration) - assert isinstance(self.driver.cli, emc_vnx_cli.EMCVnxCliPool) - - # mock the command executor - fake_command_execute = self.get_command_execute_simulator( - commands, results) - fake_cli = mock.MagicMock(side_effect=fake_command_execute) - self.driver.cli._client.command_execute = fake_cli - + fake_cli = self.driverSetup(commands, results) get_size = self.driver.manage_existing_get_size( self.testData.test_volume_with_type, self.testData.test_existing_ref) @@ -2966,24 +2953,18 @@ Time Remaining: 0 second(s) 'operation': 'None' } - self.configuration.storage_vnx_pool_name = \ - self.testData.test_pool_name - self.driver = emc_cli_iscsi.EMCCLIISCSIDriver( - configuration=self.configuration) - assert isinstance(self.driver.cli, emc_vnx_cli.EMCVnxCliPool) - cli_helper = self.driver.cli._client cli_helper.command_execute = fake_cli cli_helper.get_lun_by_name = mock.Mock(return_value=lun_info) cli_helper.get_enablers_on_array = mock.Mock(return_value="-FASTCache") - cli_helper.get_pool = mock.Mock(return_value={ + cli_helper.get_pool_list = mock.Mock(return_value=[{ 'lun_nums': 1000, 'total_capacity_gb': 10, 'free_capacity_gb': 5, 'provisioned_capacity_gb': 8, 'pool_name': "unit_test_pool", 'fast_cache_enabled': 'True', - 'state': 'Ready'}) + 'state': 'Ready'}]) self.driver.update_volume_stats() self.driver.create_volume(self.testData.test_volume_with_type) @@ -3545,13 +3526,11 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): def setUp(self): super(EMCVNXCLIDArrayBasedDriverTestCase, self).setUp() self.configuration.safe_get = self.fake_safe_get( - {'storage_vnx_pool_name': None, + {'storage_vnx_pool_names': None, 'volume_backend_name': 'namedbackend'}) - def generateDriver(self, conf): + def generate_driver(self, conf): driver = emc_cli_iscsi.EMCCLIISCSIDriver(configuration=conf) - self.assertTrue(isinstance(driver.cli, - emc_vnx_cli.EMCVnxCliArray)) return driver def test_get_volume_stats(self): @@ -3579,7 +3558,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): expected_pool_stats1 = { 'free_capacity_gb': 3105.303, 'reserved_percentage': 2, - 'location_info': 'unit_test_pool1|fakeSerial', + 'location_info': 'unit_test_pool|fakeSerial', 'total_capacity_gb': 3281.146, 'provisioned_capacity_gb': 536.140, 'compression_support': 'True', @@ -3587,7 +3566,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): 'thin_provisioning_support': True, 'thick_provisioning_support': True, 'consistencygroup_support': 'True', - 'pool_name': 'unit_test_pool1', + 'pool_name': 'unit_test_pool', 'max_over_subscription_ratio': 20.0, 'fast_cache_enabled': 'True', 'fast_support': 'True'} @@ -3597,7 +3576,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): expected_pool_stats2 = { 'free_capacity_gb': 3984.768, 'reserved_percentage': 2, - 'location_info': 'unit test pool 2|fakeSerial', + 'location_info': 'unit_test_pool2|fakeSerial', 'total_capacity_gb': 4099.992, 'provisioned_capacity_gb': 636.240, 'compression_support': 'True', @@ -3605,7 +3584,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): 'thin_provisioning_support': True, 'thick_provisioning_support': True, 'consistencygroup_support': 'True', - 'pool_name': 'unit test pool 2', + 'pool_name': 'unit_test_pool2', 'max_over_subscription_ratio': 20.0, 'fast_cache_enabled': 'False', 'fast_support': 'True'} @@ -3625,7 +3604,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): expected_pool_stats1 = { 'free_capacity_gb': 3105.303, 'reserved_percentage': 2, - 'location_info': 'unit_test_pool1|fakeSerial', + 'location_info': 'unit_test_pool|fakeSerial', 'total_capacity_gb': 3281.146, 'provisioned_capacity_gb': 536.140, 'compression_support': 'False', @@ -3633,7 +3612,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): 'thin_provisioning_support': False, 'thick_provisioning_support': True, 'consistencygroup_support': 'False', - 'pool_name': 'unit_test_pool1', + 'pool_name': 'unit_test_pool', 'max_over_subscription_ratio': 20.0, 'fast_cache_enabled': 'False', 'fast_support': 'False'} @@ -3643,7 +3622,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): expected_pool_stats2 = { 'free_capacity_gb': 3984.768, 'reserved_percentage': 2, - 'location_info': 'unit test pool 2|fakeSerial', + 'location_info': 'unit_test_pool2|fakeSerial', 'total_capacity_gb': 4099.992, 'provisioned_capacity_gb': 636.240, 'compression_support': 'False', @@ -3651,7 +3630,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): 'thin_provisioning_support': False, 'thick_provisioning_support': True, 'consistencygroup_support': 'False', - 'pool_name': 'unit test pool 2', + 'pool_name': 'unit_test_pool2', 'max_over_subscription_ratio': 20.0, 'fast_cache_enabled': 'False', 'fast_support': 'False'} @@ -3663,6 +3642,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): (['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, @@ -3834,7 +3814,7 @@ class EMCVNXCLIDArrayBasedDriverTestCase(DriverTestCaseBase): class EMCVNXCLIDriverFCTestCase(DriverTestCaseBase): - def generateDriver(self, conf): + def generate_driver(self, conf): return emc_cli_fc.EMCCLIFCDriver(configuration=conf) @mock.patch( @@ -4015,9 +3995,9 @@ class EMCVNXCLIDriverFCTestCase(DriverTestCaseBase): def test_get_volume_stats(self): commands = [self.testData.NDU_LIST_CMD, - self.testData.POOL_PROPERTY_W_FASTCACHE_CMD] + self.testData.POOL_GET_ALL_CMD(True)] results = [self.testData.NDU_LIST_RESULT, - self.testData.POOL_PROPERTY_W_FASTCACHE] + self.testData.POOL_GET_ALL_RESULT(True)] self.driverSetup(commands, results) stats = self.driver.get_volume_stats(True) @@ -4036,11 +4016,11 @@ class EMCVNXCLIDriverFCTestCase(DriverTestCaseBase): pool_stats = stats['pools'][0] expected_pool_stats = { - 'free_capacity_gb': 3257.851, - 'reserved_percentage': 3, + 'free_capacity_gb': 3105.303, + 'reserved_percentage': 2, 'location_info': 'unit_test_pool|fakeSerial', 'total_capacity_gb': 3281.146, - 'provisioned_capacity_gb': 636.24, + 'provisioned_capacity_gb': 536.14, 'compression_support': 'True', 'deduplication_support': 'True', 'thin_provisioning_support': True, @@ -4055,13 +4035,12 @@ class EMCVNXCLIDriverFCTestCase(DriverTestCaseBase): def test_get_volume_stats_too_many_luns(self): commands = [self.testData.NDU_LIST_CMD, - self.testData.POOL_PROPERTY_W_FASTCACHE_CMD, + self.testData.POOL_GET_ALL_CMD(True), self.testData.POOL_FEATURE_INFO_POOL_LUNS_CMD()] results = [self.testData.NDU_LIST_RESULT, - self.testData.POOL_PROPERTY_W_FASTCACHE, + self.testData.POOL_GET_ALL_RESULT(True), self.testData.POOL_FEATURE_INFO_POOL_LUNS(1000, 1000)] fake_cli = self.driverSetup(commands, results) - self.driver.cli.check_max_pool_luns_threshold = True stats = self.driver.get_volume_stats(True) pool_stats = stats['pools'][0] @@ -4079,7 +4058,7 @@ class EMCVNXCLIDriverFCTestCase(DriverTestCaseBase): self.assertTrue(stats['driver_version'] is not None, "driver_version is incorrect") self.assertTrue( - pool_stats['free_capacity_gb'] == 3257.851, + pool_stats['free_capacity_gb'] == 3105.303, "free_capacity_gb is incorrect") def test_deregister_initiator(self): @@ -4263,3 +4242,69 @@ Message : Error occurred because of time out""" + FAKE_COMMAND), check_exit_code=True)] mock_utils.assert_has_calls(expected) + + +class EMCVNXCLIDMultiPoolsTestCase(DriverTestCaseBase): + + def generate_driver(self, conf): + driver = emc_cli_iscsi.EMCCLIISCSIDriver(configuration=conf) + return driver + + def fake_command_execute_for_driver_setup(self, *command, **kwargv): + if command == ('connection', '-getport', '-address', '-vlanid'): + return self.testData.ALL_PORTS + elif command == ('storagepool', '-list', '-state'): + return self.testData.POOL_GET_STATE_RESULT([ + {'pool_name': self.testData.test_pool_name, 'state': "Ready"}, + {'pool_name': "unit_test_pool2", 'state': "Ready"}, + {'pool_name': "unit_test_pool3", 'state': "Ready"}, + {'pool_name': "unit_text_pool4", 'state': "Ready"}]) + else: + return SUCCEED + + def test_storage_pool_names_option(self): + self.configuration.safe_get = self.fake_safe_get( + {'storage_vnx_pool_names': "unit_test_pool, unit_test_pool3", + 'volume_backend_name': 'namedbackend'}) + + driver = self.generate_driver(self.configuration) + self.assertEqual(set(["unit_test_pool", "unit_test_pool3"]), + driver.cli.storage_pools) + + self.configuration.safe_get = self.fake_safe_get( + {'storage_vnx_pool_names': "unit_test_pool2,", + 'volume_backend_name': 'namedbackend'}) + driver = self.generate_driver(self.configuration) + self.assertEqual(set(["unit_test_pool2"]), + driver.cli.storage_pools) + + self.configuration.safe_get = self.fake_safe_get( + {'storage_vnx_pool_names': "unit_test_pool3", + 'volume_backend_name': 'namedbackend'}) + driver = self.generate_driver(self.configuration) + self.assertEqual(set(["unit_test_pool3"]), + driver.cli.storage_pools) + + def test_configured_pool_does_not_exist(self): + self.configuration.safe_get = self.fake_safe_get( + {'storage_vnx_pool_names': "unit_test_pool2, unit_test_pool_none2", + 'volume_backend_name': 'namedbackend'}) + driver = self.generate_driver(self.configuration) + self.assertEqual(set(["unit_test_pool2"]), + driver.cli.storage_pools) + + self.configuration.safe_get = self.fake_safe_get( + {'storage_vnx_pool_names': "unit_test_pool_none1", + "unit_test_pool_none2" + 'volume_backend_name': 'namedbackend'}) + self.assertRaises(exception.VolumeBackendAPIException, + self.generate_driver, + self.configuration) + + def test_no_storage_pool_is_configured(self): + self.configuration.safe_get = self.fake_safe_get( + {'storage_vnx_pool_names': None, + 'volume_backend_name': 'namedbackend'}) + driver = self.generate_driver(self.configuration) + self.assertEqual(set(), + driver.cli.storage_pools) diff --git a/cinder/volume/drivers/emc/emc_cli_fc.py b/cinder/volume/drivers/emc/emc_cli_fc.py index 69c15bdaf..88ebda3e1 100644 --- a/cinder/volume/drivers/emc/emc_cli_fc.py +++ b/cinder/volume/drivers/emc/emc_cli_fc.py @@ -56,6 +56,7 @@ class EMCCLIFCDriver(driver.FibreChannelDriver): 5.3.0 - Consistency group modification support 6.0.0 - Over subscription support Create consistency group from cgsnapshot support + Multiple pools support enhancement """ def __init__(self, *args, **kwargs): diff --git a/cinder/volume/drivers/emc/emc_cli_iscsi.py b/cinder/volume/drivers/emc/emc_cli_iscsi.py index 72b0e946a..909d495b8 100644 --- a/cinder/volume/drivers/emc/emc_cli_iscsi.py +++ b/cinder/volume/drivers/emc/emc_cli_iscsi.py @@ -54,6 +54,7 @@ class EMCCLIISCSIDriver(driver.ISCSIDriver): 5.3.0 - Consistency group modification support 6.0.0 - Over subscription support Create consistency group from cgsnapshot support + Multiple pools support enhancement """ def __init__(self, *args, **kwargs): diff --git a/cinder/volume/drivers/emc/emc_vnx_cli.py b/cinder/volume/drivers/emc/emc_vnx_cli.py index 75bae5798..2f98454e9 100644 --- a/cinder/volume/drivers/emc/emc_vnx_cli.py +++ b/cinder/volume/drivers/emc/emc_vnx_cli.py @@ -69,9 +69,10 @@ loc_opts = [ cfg.StrOpt('naviseccli_path', default='', help='Naviseccli Path.'), - cfg.StrOpt('storage_vnx_pool_name', + cfg.StrOpt('storage_vnx_pool_names', default=None, - help='Storage pool name.'), + deprecated_name='storage_vnx_pool_name', + help='Comma-separated list of storage pool names to be used.'), cfg.StrOpt('san_secondary_ip', default=None, help='VNX secondary SP IP Address.'), @@ -1699,6 +1700,8 @@ class EMCVnxCliBase(object): "Please register initiator manually.")) self.hlu_set = set(xrange(1, self.max_luns_per_sg + 1)) self._client = CommandLineHelper(self.configuration) + conf_pools = self.configuration.safe_get("storage_vnx_pool_names") + self.storage_pools = self._get_managed_storage_pools(conf_pools) self.array_serial = None if self.protocol == 'iSCSI': self.iscsi_targets = self._client.get_iscsi_targets(poll=True) @@ -1710,8 +1713,34 @@ class EMCVnxCliBase(object): self.max_over_subscription_ratio = ( self.configuration.max_over_subscription_ratio) - def get_target_storagepool(self, volume, source_volume=None): - raise NotImplementedError + def _get_managed_storage_pools(self, pools): + storage_pools = set() + if pools: + storage_pools = set([po.strip() for po in pools.split(",")]) + array_pools = self._client.get_pool_list( + [self._client.POOL_STATE], False) + array_pools = set([po['pool_name'] for po in array_pools]) + un_exist_pools = storage_pools.difference(array_pools) + storage_pools.difference_update(un_exist_pools) + if not storage_pools: + msg = _("All the specified storage pools to be managed " + "do not exist. Please check your configuration. " + "Non-existent pools: %s") % ",".join(un_exist_pools) + raise exception.VolumeBackendAPIException(data=msg) + if un_exist_pools: + LOG.warning(_LW("The following specified storage pools " + "do not exist: %(unexist)s. " + "This host will only manage the storage " + "pools: %(exist)s"), + {'unexist': ",".join(un_exist_pools), + 'exist': ",".join(storage_pools)}) + else: + LOG.debug("This host will manage the storage pools: %s.", + ",".join(storage_pools)) + else: + LOG.debug("No storage pool is configured. This host will " + "manage all the pools on the VNX system.") + return storage_pools def get_array_serial(self): if not self.array_serial: @@ -2091,7 +2120,7 @@ class EMCVnxCliBase(object): return False return True - def _build_pool_stats(self, pool): + def _build_pool_stats(self, pool, pool_feature=None): pool_stats = {} pool_stats['pool_name'] = pool['pool_name'] pool_stats['total_capacity_gb'] = pool['total_capacity_gb'] @@ -2119,7 +2148,7 @@ class EMCVnxCliBase(object): (min(reserved, 100))) if self.check_max_pool_luns_threshold: pool_feature = self._client.get_pool_feature_properties( - poll=False) + poll=False) if not pool_feature else pool_feature if (pool_feature['max_pool_luns'] <= pool_feature['total_pool_luns']): LOG.warning(_LW("Maximum number of Pool LUNs, %s, " @@ -2156,9 +2185,8 @@ class EMCVnxCliBase(object): return pool_stats - @log_enter_exit - def update_volume_stats(self): - """Gets the common stats shared by pool and array backend.""" + def update_enabler_in_volume_stats(self): + """Updates the enabler information in stats.""" if not self.determine_all_enablers_exist(self.enablers): self.enablers = self._client.get_enablers_on_array() @@ -2177,9 +2205,6 @@ class EMCVnxCliBase(object): self.stats['consistencygroup_support'] = ( 'True' if '-VNXSnapshots' in self.enablers else 'False') - if self.protocol == 'iSCSI': - self.iscsi_targets = self._client.get_iscsi_targets(poll=False) - return self.stats def create_snapshot(self, snapshot): @@ -3130,55 +3155,13 @@ class EMCVnxCliBase(object): return None, volume_model_updates - -@decorate_all_methods(log_enter_exit) -class EMCVnxCliPool(EMCVnxCliBase): - - def __init__(self, prtcl, configuration): - super(EMCVnxCliPool, self).__init__(prtcl, configuration=configuration) - self.storage_pool = configuration.storage_vnx_pool_name.strip() - self._client.get_pool(self.storage_pool) - - def get_target_storagepool(self, - volume, - source_volume=None): - return self.storage_pool - - def update_volume_stats(self): - """Retrieves stats info.""" - super(EMCVnxCliPool, self).update_volume_stats() - if '-FASTCache' in self.enablers: - properties = [self._client.POOL_FREE_CAPACITY, - self._client.POOL_TOTAL_CAPACITY, - self._client.POOL_FAST_CACHE, - self._client.POOL_STATE, - self._client.POOL_SUBSCRIBED_CAPACITY] - else: - properties = [self._client.POOL_FREE_CAPACITY, - self._client.POOL_TOTAL_CAPACITY, - self._client.POOL_STATE, - self._client.POOL_SUBSCRIBED_CAPACITY] - - pool = self._client.get_pool(self.storage_pool, - properties=properties, - poll=False) - self.stats['pools'] = [self._build_pool_stats(pool)] - return self.stats - - -@decorate_all_methods(log_enter_exit) -class EMCVnxCliArray(EMCVnxCliBase): - - def __init__(self, prtcl, configuration): - super(EMCVnxCliArray, self).__init__(prtcl, - configuration=configuration) - def get_target_storagepool(self, volume, source_volume=None): pool = vol_utils.extract_host(volume['host'], 'pool') - # For new created volume that is not from snapshot or cloned, + # For new created volume that is not from snapshot or cloned + # or the pool is the managed pool, # just use the pool selected by scheduler - if not source_volume: + if not source_volume or pool in self.storage_pools: return pool # For volume created from snapshot or cloned from volume, the pool to @@ -3188,11 +3171,9 @@ class EMCVnxCliArray(EMCVnxCliBase): # use the pool selected by scheduler provider_location = source_volume.get('provider_location') - if (provider_location and - self._extract_provider_location_for_lun(provider_location, - 'version')): - return pool - else: + if (not provider_location or + not self._extract_provider_location_for_lun(provider_location, + 'version')): LOG.warning(_LW("The source volume is a legacy volume. " "Create volume in the pool where the source " "volume %s is created."), @@ -3205,11 +3186,23 @@ class EMCVnxCliArray(EMCVnxCliBase): % source_volume['name']) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) - return data[self._client.LUN_POOL.key] + pool = data[self._client.LUN_POOL.key] + + if self.storage_pools and pool not in self.storage_pools: + msg = (_("The source volume %s is not in the pool which " + "is managed by the current host.") + % source_volume['name']) + LOG.error(msg) + raise exception.VolumeBackendAPIException(data=msg) + return pool def update_volume_stats(self): """Retrieves stats info.""" - super(EMCVnxCliArray, self).update_volume_stats() + self.update_enabler_in_volume_stats() + + if self.protocol == 'iSCSI': + self.iscsi_targets = self._client.get_iscsi_targets(poll=False) + if '-FASTCache' in self.enablers: properties = [self._client.POOL_FREE_CAPACITY, self._client.POOL_TOTAL_CAPACITY, @@ -3223,19 +3216,20 @@ class EMCVnxCliArray(EMCVnxCliBase): self._client.POOL_SUBSCRIBED_CAPACITY] pool_list = self._client.get_pool_list(properties, False) - self.stats['pools'] = map(lambda pool: self._build_pool_stats(pool), - pool_list) + if self.storage_pools: + pool_list = filter(lambda a: a['pool_name'] in self.storage_pools, + pool_list) + pool_feature = (self._client.get_pool_feature_properties(poll=False) + if self.check_max_pool_luns_threshold else None) + self.stats['pools'] = map( + lambda pool: self._build_pool_stats(pool, pool_feature), pool_list) + return self.stats def getEMCVnxCli(prtcl, configuration=None): configuration.append_config_values(loc_opts) - pool_name = configuration.safe_get("storage_vnx_pool_name") - - if pool_name is None or len(pool_name.strip()) == 0: - return EMCVnxCliArray(prtcl, configuration=configuration) - else: - return EMCVnxCliPool(prtcl, configuration=configuration) + return EMCVnxCliBase(prtcl, configuration=configuration) class CreateSMPTask(task.Task):