From: Mike Rooney Date: Fri, 4 Dec 2015 17:14:45 +0000 (-0500) Subject: Add serial number to eseries ASUP payload X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=1e4f2e0a443a6489c3ecbee207c20b910b6350ae;p=openstack-build%2Fcinder-build.git Add serial number to eseries ASUP payload Single field added to AutoSupport data key-value pair. AutoSupport is a mechanism that allows NetApp backends to report customer usage metrics. Change-Id: I4c1dae89505767acd579e874fbe541d4617915f2 --- diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py b/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py index 4e49e3ba5..d862984d8 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/fakes.py @@ -595,6 +595,8 @@ VOLUME_MAPPING_TO_MULTIATTACH_GROUP.update( ) STORAGE_SYSTEM = { + 'chassisSerialNumber': 1, + 'fwVersion': '08.10.15.00', 'freePoolSpace': 11142431623168, 'driveCount': 24, 'hostSparesUsed': 0, 'id': @@ -667,7 +669,26 @@ SNAPSHOT_IMAGE = { 'pitSequenceNumber': '19' } +HARDWARE_INVENTORY_SINGLE_CONTROLLER = { + 'controllers': [ + { + 'modelName': '2752', + 'serialNumber': '021436001321' + } + ] +} + HARDWARE_INVENTORY = { + 'controllers': [ + { + 'modelName': '2752', + 'serialNumber': '021436000943' + }, + { + 'modelName': '2752', + 'serialNumber': '021436001321' + } + ], 'iscsiPorts': [ { 'controllerId': @@ -806,7 +827,6 @@ FAKE_POOL_ACTION_PROGRESS = [ }, ] - FAKE_RESOURCE_URL = '/devmgr/v2/devmgr/utils/about' FAKE_APP_VERSION = '2015.2|2015.2.dev59|vendor|Linux-3.13.0-24-generic' FAKE_BACKEND = 'eseriesiSCSI' @@ -840,8 +860,17 @@ FAKE_ASUP_DATA = { 'model': FAKE_CONTROLLERS[0]['modelName'], 'controller2-serial': FAKE_CONTROLLERS[1]['serialNumber'], 'controller1-serial': FAKE_CONTROLLERS[0]['serialNumber'], + 'chassis-serial-number': FAKE_SERIAL_NUMBER[0], 'operating-mode': 'proxy', } + +GET_ASUP_RETURN = { + 'model': FAKE_CONTROLLERS[0]['modelName'], + 'serial_numbers': FAKE_SERIAL_NUMBERS, + 'firmware_version': FAKE_ASUP_DATA['system-version'], + 'chassis_sn': FAKE_ASUP_DATA['chassis-serial-number'], +} + FAKE_POST_INVOKE_DATA = ('POST', '/key-values/%s' % FAKE_KEY, json.dumps(FAKE_ASUP_DATA)) diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/test_client.py b/cinder/tests/unit/volume/drivers/netapp/eseries/test_client.py index 87a854ea1..a14055615 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/test_client.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/test_client.py @@ -26,7 +26,6 @@ from cinder.tests.unit.volume.drivers.netapp.eseries import fakes as \ eseries_fake from cinder.volume.drivers.netapp.eseries import exception as es_exception - from cinder.volume.drivers.netapp.eseries import client from cinder.volume.drivers.netapp import utils as na_utils @@ -346,16 +345,8 @@ class NetAppEseriesClientDriverTestCase(test.TestCase): eseries_fake.FAKE_ASUP_DATA['operating-mode'], eseries_fake.FAKE_ABOUT_RESPONSE['version']))) self.mock_object( - self.my_client, 'get_firmware_version', - mock.Mock( - return_value=eseries_fake.FAKE_ABOUT_RESPONSE['version'])) - self.mock_object( - self.my_client, 'get_serial_numbers', - mock.Mock(return_value=eseries_fake.FAKE_SERIAL_NUMBERS)) - self.mock_object( - self.my_client, 'get_model_name', - mock.Mock( - return_value=eseries_fake.FAKE_CONTROLLERS[0]['modelName'])) + self.my_client, 'get_asup_info', + mock.Mock(return_value=eseries_fake.GET_ASUP_RETURN)) self.mock_object( self.my_client, 'set_counter', mock.Mock(return_value={'value': 1})) @@ -372,38 +363,48 @@ class NetAppEseriesClientDriverTestCase(test.TestCase): mock_invoke.assert_called_with(*eseries_fake.FAKE_POST_INVOKE_DATA) @ddt.data((eseries_fake.FAKE_SERIAL_NUMBERS, - eseries_fake.FAKE_CONTROLLERS), - (eseries_fake.FAKE_DEFAULT_SERIAL_NUMBER, []), + eseries_fake.HARDWARE_INVENTORY), + (eseries_fake.FAKE_DEFAULT_SERIAL_NUMBER, {}), (eseries_fake.FAKE_SERIAL_NUMBER, - eseries_fake.FAKE_SINGLE_CONTROLLER)) + eseries_fake.HARDWARE_INVENTORY_SINGLE_CONTROLLER)) @ddt.unpack - def test_get_serial_numbers(self, expected_serial_numbers, controllers): + def test_get_asup_info_serial_numbers(self, expected_serial_numbers, + controllers): self.mock_object( - client.RestClient, '_get_controllers', + client.RestClient, 'list_hardware_inventory', mock.Mock(return_value=controllers)) + self.mock_object( + client.RestClient, 'list_storage_system', + mock.Mock(return_value={})) - serial_numbers = client.RestClient.get_serial_numbers(self.my_client) + sn = client.RestClient.get_asup_info(self.my_client)['serial_numbers'] - self.assertEqual(expected_serial_numbers, serial_numbers) + self.assertEqual(expected_serial_numbers, sn) - def test_get_model_name(self): + def test_get_asup_info_model_name(self): + self.mock_object( + client.RestClient, 'list_hardware_inventory', + mock.Mock(return_value=eseries_fake.HARDWARE_INVENTORY)) self.mock_object( - client.RestClient, '_get_controllers', - mock.Mock(return_value=eseries_fake.FAKE_CONTROLLERS)) + client.RestClient, 'list_storage_system', + mock.Mock(return_value=eseries_fake.STORAGE_SYSTEM)) - model = client.RestClient.get_model_name(self.my_client) + model_name = client.RestClient.get_asup_info(self.my_client)['model'] - self.assertEqual(eseries_fake.FAKE_CONTROLLERS[0]['modelName'], - model) + self.assertEqual(eseries_fake.HARDWARE_INVENTORY['controllers'][0] + ['modelName'], model_name) - def test_get_model_name_empty_controllers_list(self): + def test_get_asup_info_model_name_empty_controllers_list(self): self.mock_object( - client.RestClient, '_get_controllers', - mock.Mock(return_value=[])) + client.RestClient, 'list_hardware_inventory', + mock.Mock(return_value={})) + self.mock_object( + client.RestClient, 'list_storage_system', + mock.Mock(return_value={})) - model = client.RestClient.get_model_name(self.my_client) + model_name = client.RestClient.get_asup_info(self.my_client)['model'] - self.assertEqual(eseries_fake.FAKE_DEFAULT_MODEL, model) + self.assertEqual(eseries_fake.FAKE_DEFAULT_MODEL, model_name) def test_get_eseries_api_info(self): fake_invoke_service = mock.Mock() @@ -699,8 +700,7 @@ class NetAppEseriesClientDriverTestCase(test.TestCase): self.my_client._invoke.assert_called_once_with('DELETE', url, **{'object-id': - fake_volume['id']} - ) + fake_volume['id']}) @ddt.data('00.00.00.00', '01.52.9000.2', '01.52.9001.2', '01.51.9000.3', '01.51.9001.3', '01.51.9010.5', '0.53.9000.3', '0.53.9001.4') @@ -755,7 +755,6 @@ class NetAppEseriesClientDriverTestCase(test.TestCase): @ddt.ddt class TestWebserviceClientTestCase(test.TestCase): - def setUp(self): """sets up the mock tests""" super(TestWebserviceClientTestCase, self).setUp() 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 d163471c8..19c65c3c3 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py @@ -950,16 +950,8 @@ class NetAppEseriesLibraryTestCase(test.TestCase): eseries_fake.FAKE_ASUP_DATA['operating-mode']) self.library._app_version = eseries_fake.FAKE_APP_VERSION self.mock_object( - self.library._client, 'get_firmware_version', - mock.Mock(return_value=( - eseries_fake.FAKE_ASUP_DATA['system-version']))) - self.mock_object( - self.library._client, 'get_serial_numbers', - mock.Mock(return_value=eseries_fake.FAKE_SERIAL_NUMBERS)) - self.mock_object( - self.library._client, 'get_model_name', - mock.Mock( - return_value=eseries_fake.FAKE_CONTROLLERS[0]['modelName'])) + self.library._client, 'get_asup_info', + mock.Mock(return_value=eseries_fake.GET_ASUP_RETURN)) self.mock_object( self.library._client, 'set_counter', mock.Mock(return_value={'value': 1})) diff --git a/cinder/volume/drivers/netapp/eseries/client.py b/cinder/volume/drivers/netapp/eseries/client.py index 60897216b..1709f8f2b 100644 --- a/cinder/volume/drivers/netapp/eseries/client.py +++ b/cinder/volume/drivers/netapp/eseries/client.py @@ -722,17 +722,44 @@ class RestClient(WebserviceClient): path = ('/key-values/%s' % key) self._invoke('POST', path, json.dumps(data)) - def get_firmware_version(self): - """Get firmware version information from the array.""" - return self.list_storage_system()['fwVersion'] - def set_counter(self, key, value): path = ('/counters/%s/setCounter?value=%d' % (key, value)) self._invoke('POST', path) - def _get_controllers(self): - """Get controller information from the array.""" - return self.list_hardware_inventory()['controllers'] + def get_asup_info(self): + """Returns a dictionary of relevant autosupport information. + + Currently returned fields are: + model -- E-series model name + serial_numbers -- Serial number for each controller + firmware_version -- Version of active firmware + chassis_sn -- Serial number for whole chassis + """ + asup_info = {} + + controllers = self.list_hardware_inventory().get('controllers') + if controllers: + asup_info['model'] = controllers[0].get('modelName', 'unknown') + serial_numbers = [value['serialNumber'].rstrip() + for __, value in enumerate(controllers)] + serial_numbers.sort() + for index, value in enumerate(serial_numbers): + if not value: + serial_numbers[index] = 'unknown' + asup_info['serial_numbers'] = serial_numbers + else: + asup_info['model'] = 'unknown' + asup_info['serial_numbers'] = ['unknown', 'unknown'] + + system_info = self.list_storage_system() + if system_info: + asup_info['firmware_version'] = system_info['fwVersion'] + asup_info['chassis_sn'] = system_info['chassisSerialNumber'] + else: + asup_info['firmware_version'] = 'unknown' + asup_info['chassis_sn'] = 'unknown' + + return asup_info def get_eseries_api_info(self, verify=False): """Get E-Series API information from the array.""" @@ -750,23 +777,3 @@ class RestClient(WebserviceClient): if mode_is_proxy: api_operating_mode = 'proxy' return api_operating_mode, about_response_dict['version'] - - def get_serial_numbers(self): - """Get the list of Serial Numbers from the array.""" - controllers = self._get_controllers() - if not controllers: - return ['unknown', 'unknown'] - serial_numbers = [value['serialNumber'].rstrip() - for _, value in enumerate(controllers)] - serial_numbers.sort() - for index, value in enumerate(serial_numbers): - if not value: - serial_numbers[index] = 'unknown' - return serial_numbers - - def get_model_name(self): - """Get Model Name from the array.""" - controllers = self._get_controllers() - if not controllers: - return 'unknown' - return controllers[0].get('modelName', 'unknown') diff --git a/cinder/volume/drivers/netapp/eseries/library.py b/cinder/volume/drivers/netapp/eseries/library.py index dc5d0e206..92ccfd82d 100644 --- a/cinder/volume/drivers/netapp/eseries/library.py +++ b/cinder/volume/drivers/netapp/eseries/library.py @@ -1020,12 +1020,14 @@ class NetAppESeriesLibrary(object): LOG.info(msg % self._client.api_version) return - firmware_version = self._client.get_firmware_version() event_source = ("Cinder driver %s" % self.DRIVER_NAME) category = "provisioning" event_description = "OpenStack Cinder connected to E-Series proxy" - model = self._client.get_model_name() - serial_numbers = self._client.get_serial_numbers() + asup_info = self._client.get_asup_info() + model = asup_info.get('model') + firmware_version = asup_info.get('firmware_version') + serial_numbers = asup_info.get('serial_numbers') + chassis_sn = asup_info.get('chassis_sn') key = ("openstack-%s-%s-%s" % (cinder_host, serial_numbers[0], serial_numbers[1])) @@ -1043,6 +1045,7 @@ class NetAppESeriesLibrary(object): 'event-description': event_description, 'controller1-serial': serial_numbers[0], 'controller2-serial': serial_numbers[1], + 'chassis-serial-number': chassis_sn, 'model': model, 'system-version': firmware_version, 'operating-mode': self._client.api_operating_mode