]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Multiple pools support enhancement in VNX cinder driver
authorTina <tina.tang@emc.com>
Mon, 18 May 2015 01:12:10 +0000 (21:12 -0400)
committerTina <tina.tang@emc.com>
Fri, 29 May 2015 04:22:20 +0000 (00:22 -0400)
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

cinder/tests/unit/test_emc_vnxdirect.py
cinder/volume/drivers/emc/emc_cli_fc.py
cinder/volume/drivers/emc/emc_cli_iscsi.py
cinder/volume/drivers/emc/emc_vnx_cli.py

index 8fb7cdf9b17f3c95d4a05e213886f54ae8cbc9d1..1910819520feca58e1274994bcc83d5abd606f5b 100644 (file)
@@ -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)
index 69c15bdafa24e4ff4d2756e1857b1b3bc55f8e28..88ebda3e166c4dbed76e1a191804aa88b69d8208 100644 (file)
@@ -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):
index 72b0e946a5a3d57be4ca402f99b09d9289889e3d..909d495b8686e686c1fe24057572b9e1e614fad6 100644 (file)
@@ -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):
index 75bae5798e351d1e7440b767cbc4538ea23be769..2f98454e9d7796acf40815b46c7d92224c657b2f 100644 (file)
@@ -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):