From cef3aa2eebf5eb9f7aaf294954ed808a9dcccdfa Mon Sep 17 00:00:00 2001 From: Michael Price Date: Thu, 24 Sep 2015 14:29:30 -0500 Subject: [PATCH] NetApp: E-Series driver using invalid host-types The NetApp E-Series driver is using a dict of hard-coded host-type values, some of which are no longer valid. There is a list of updated host-types that are valid, but they must be validated against what the storage array reports as supported. This patch removes invalid or unnecessary host-types from library.py, and adds a verification using the host-types API to ensure that the host-type selected by the user is valid for the storage-array. Closes-Bug: #1555946 Change-Id: I94090eb6b2d9c7965577a462f5e70033926fa27d --- .../volume/drivers/netapp/eseries/fakes.py | 102 ++++++++++++++++-- .../drivers/netapp/eseries/test_driver.py | 13 --- .../drivers/netapp/eseries/test_library.py | 45 ++++++++ .../volume/drivers/netapp/eseries/library.py | 44 ++++---- 4 files changed, 160 insertions(+), 44 deletions(-) diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py b/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py index a522bdc87e1..9f7bdae05b0 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py @@ -1217,25 +1217,105 @@ class FakeEseriesClient(object): def list_host_types(self): return [ { - 'id': '4', - 'code': 'AIX', - 'name': 'AIX', - 'index': 4 + 'name': 'FactoryDefault', + 'index': 0, + 'code': 'FactoryDefault', }, { - 'id': '5', - 'code': 'IRX', - 'name': 'IRX', - 'index': 5 + 'name': 'Windows 2000/Server 2003/Server 2008 Non-Clustered', + 'index': 1, + 'code': 'W2KNETNCL', + }, + { + 'name': 'Solaris', + 'index': 2, + 'code': 'SOL', + }, + { + 'name': 'ONTAP_RDAC', + 'index': 4, + 'code': 'ONTAP_RDAC', + }, + { + 'name': 'AVT_4M', + 'index': 5, + 'code': 'AVT_4M', + }, + { + 'name': 'Linux', + 'index': 6, + 'code': 'LNX', }, { - 'id': '6', - 'code': 'LnxALUA', 'name': 'LnxALUA', - 'index': 6 + 'index': 7, + 'code': 'LnxALUA', + }, + { + 'name': 'Windows 2000/Server 2003/Server 2008 Clustered', + 'index': 8, + 'code': 'W2KNETCL', + }, + { + 'name': 'AIX MPIO', + 'index': 9, + 'code': 'AIX MPIO', + }, + { + 'name': 'VmwTPGSALUA', + 'index': 10, + 'code': 'VmwTPGSALUA', + }, + { + 'name': 'HP-UX TPGS', + 'index': 15, + 'code': 'HPXTPGS', + }, + { + 'name': 'SolTPGSALUA', + 'index': 17, + 'code': 'SolTPGSALUA', + }, + { + 'name': 'SVC', + 'index': 18, + 'code': 'SVC', + }, + { + 'name': 'MacTPGSALUA', + 'index': 22, + 'code': 'MacTPGSALUA', + }, + { + 'name': 'WinTPGSALUA', + 'index': 23, + 'code': 'WinTPGSALUA', + }, + { + 'name': 'LnxTPGSALUA', + 'index': 24, + 'code': 'LnxTPGSALUA', + }, + { + 'name': 'LnxTPGSALUA_PM', + 'index': 25, + 'code': 'LnxTPGSALUA_PM', + }, + { + 'name': 'ONTAP_ALUA', + 'index': 26, + 'code': 'ONTAP_ALUA', + }, + { + 'name': 'LnxTPGSALUA_SF', + 'index': 27, + 'code': 'LnxTPGSALUA_SF', } ] + def update_host_type(self, *args, **kwargs): + pass + def list_hardware_inventory(self): return HARDWARE_INVENTORY diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/test_driver.py b/cinder/tests/unit/volume/drivers/netapp/eseries/test_driver.py index b4910152668..f2dcfa5022f 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/test_driver.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/test_driver.py @@ -273,19 +273,6 @@ class NetAppESeriesDriverTestCase(object): self.library._get_iscsi_portal_for_vol, vol_nomatch, portals, False) - def test_setup_error_unsupported_host_type(self): - configuration = self._set_config(self.create_configuration()) - configuration.netapp_host_type = 'garbage' - driver = common.NetAppDriver(configuration=configuration) - self.assertRaises(exception.NetAppDriverException, - driver.library.check_for_setup_error) - - def test_check_host_type_default(self): - configuration = self._set_config(self.create_configuration()) - driver = common.NetAppDriver(configuration=configuration) - driver.library._check_host_type() - self.assertEqual('LnxALUA', driver.library.host_type) - def test_do_setup_all_default(self): configuration = self._set_config(self.create_configuration()) driver = common.NetAppDriver(configuration=configuration) diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py b/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py index ff4017c0041..41f50ed70b4 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py @@ -98,6 +98,51 @@ class NetAppEseriesLibraryTestCase(test.TestCase): self.assertTrue(mock_check_flags.called) + @ddt.data('linux_dm_mp', 'linux_atto', 'linux_mpp_rdac', + 'linux_pathmanager', 'linux_sf', 'ontap', 'ontap_rdac', + 'vmware', 'windows_atto', 'windows_clustered', + 'factoryDefault', 'windows', None) + def test_check_host_type(self, host_type): + config = mock.Mock() + default_host_type = self.library.host_type + config.netapp_host_type = host_type + self.mock_object(self.library, 'configuration', config) + + result = self.library._check_host_type() + + self.assertIsNone(result) + if host_type: + self.assertEqual(self.library.HOST_TYPES.get(host_type), + self.library.host_type) + else: + self.assertEqual(default_host_type, self.library.host_type) + + def test_check_host_type_invalid(self): + config = mock.Mock() + config.netapp_host_type = 'invalid' + self.mock_object(self.library, 'configuration', config) + + self.assertRaises(exception.NetAppDriverException, + self.library._check_host_type) + + def test_check_host_type_new(self): + config = mock.Mock() + config.netapp_host_type = 'new_host_type' + expected = 'host_type' + self.mock_object(self.library, 'configuration', config) + host_types = [{ + 'name': 'new_host_type', + 'index': 0, + 'code': expected, + }] + self.mock_object(self.library._client, 'list_host_types', + mock.Mock(return_value=host_types)) + + result = self.library._check_host_type() + + self.assertIsNone(result) + self.assertEqual(expected, self.library.host_type) + @ddt.data(('optimal', True), ('offline', False), ('needsAttn', True), ('neverContacted', False), ('newKey', True), (None, True)) @ddt.unpack diff --git a/cinder/volume/drivers/netapp/eseries/library.py b/cinder/volume/drivers/netapp/eseries/library.py index f98e5678f9c..e185cbdad8d 100644 --- a/cinder/volume/drivers/netapp/eseries/library.py +++ b/cinder/volume/drivers/netapp/eseries/library.py @@ -60,25 +60,18 @@ class NetAppESeriesLibrary(object): REQUIRED_FLAGS = ['netapp_server_hostname', 'netapp_controller_ips', 'netapp_login', 'netapp_password'] SLEEP_SECS = 5 - HOST_TYPES = {'aix': 'AIX MPIO', - 'avt': 'AVT_4M', - 'factoryDefault': 'FactoryDefault', - 'hpux': 'HP-UX TPGS', + HOST_TYPES = {'factoryDefault': 'FactoryDefault', 'linux_atto': 'LnxTPGSALUA', 'linux_dm_mp': 'LnxALUA', - 'linux_mpp_rdac': 'Linux', + 'linux_mpp_rdac': 'LNX', 'linux_pathmanager': 'LnxTPGSALUA_PM', - 'macos': 'MacTPGSALUA', - 'ontap': 'ONTAP', - 'svc': 'SVC', - 'solaris_v11': 'SolTPGSALUA', - 'solaris_v10': 'Solaris', + 'linux_sf': 'LnxTPGSALUA_SF', + 'ontap': 'ONTAP_ALUA', + 'ontap_rdac': 'ONTAP_RDAC', 'vmware': 'VmwTPGSALUA', - 'windows': - 'Windows 2000/Server 2003/Server 2008 Non-Clustered', + 'windows': 'W2KNETNCL', 'windows_atto': 'WinTPGSALUA', - 'windows_clustered': - 'Windows 2000/Server 2003/Server 2008 Clustered' + 'windows_clustered': 'W2KNETCL', } # NOTE(ameade): This maps what is reported by the e-series api to a # consistent set of values that are reported by all NetApp drivers @@ -207,12 +200,23 @@ class NetAppESeriesLibrary(object): self._start_periodic_tasks() def _check_host_type(self): - host_type = (self.configuration.netapp_host_type - or self.DEFAULT_HOST_TYPE) - self.host_type = self.HOST_TYPES.get(host_type) - if not self.host_type: - raise exception.NetAppDriverException( - _('Configured host type is not supported.')) + """Validate that the configured host-type is available for the array. + + Not all host-types are available on every firmware version. + """ + requested_host_type = (self.configuration.netapp_host_type + or self.DEFAULT_HOST_TYPE) + actual_host_type = ( + self.HOST_TYPES.get(requested_host_type, requested_host_type)) + + for host_type in self._client.list_host_types(): + if(host_type.get('code') == actual_host_type or + host_type.get('name') == actual_host_type): + self.host_type = host_type.get('code') + return + exc_msg = _("The host-type '%s' is not supported on this storage " + "system.") + raise exception.NetAppDriverException(exc_msg % requested_host_type) def _check_multipath(self): if not self.configuration.use_multipath_for_image_xfer: