From d48594c9c721e48a20e81e7d40c7f3e9076d635f Mon Sep 17 00:00:00 2001 From: manali-deshmukh Date: Thu, 23 May 2019 02:59:15 +0530 Subject: [PATCH] Fix - Drives request from volume endpoints is failing --- oneview_redfish_toolkit/api/drive.py | 26 ++++++++ oneview_redfish_toolkit/api/volume.py | 38 ++++++----- oneview_redfish_toolkit/blueprints/storage.py | 65 ++++++++++++++----- .../tests/blueprints/test_storage.py | 62 ++++++++++++++++-- 4 files changed, 155 insertions(+), 36 deletions(-) diff --git a/oneview_redfish_toolkit/api/drive.py b/oneview_redfish_toolkit/api/drive.py index 405936f1..5b825acd 100644 --- a/oneview_redfish_toolkit/api/drive.py +++ b/oneview_redfish_toolkit/api/drive.py @@ -102,6 +102,32 @@ def build_for_resource_block(drive, drive_enclosure): return Drive(attrs) + @staticmethod + def build_for_computer_system_volume(drive_id, server_profile, drive): + enclosure_id = server_profile["enclosureUri"].split("/")[-1] + profile_uuid = server_profile["uri"].split("/")[-1] + odata_id = "{}/{}/Storage/1/Drives/{}"\ + .format(ComputerSystem.BASE_URI, profile_uuid, drive_id) + media_type = drive["driveMedia"] + media_type = None if (media_type == "Unknown") else media_type + attrs = { + "Id": drive_id, + "Name": drive["name"], + "Status": status_mapping.STATUS_MAP.get(drive["status"]), + "CapacityBytes": Drive.get_capacity_in_bytes( + drive["capacity"]), + "Protocol": drive["deviceInterface"], + "MediaType": media_type, + "Links": { + "Chassis": { + "@odata.id": "/redfish/v1/Chassis/" + enclosure_id + } + }, + "@odata.id": odata_id + } + + return Drive(attrs) + @staticmethod def get_capacity_in_bytes(capacity_in_gb): size_in_bytes = float(capacity_in_gb) * 1024 * 1024 * 1024 diff --git a/oneview_redfish_toolkit/api/volume.py b/oneview_redfish_toolkit/api/volume.py index ff9fc127..616f4971 100755 --- a/oneview_redfish_toolkit/api/volume.py +++ b/oneview_redfish_toolkit/api/volume.py @@ -108,24 +108,12 @@ def build_volume_details(uuid, volume_id): abort(status.HTTP_404_NOT_FOUND, "Volume {} not found" .format(volume_id)) - sas_Logical_Interconnect_Uri = \ - sas_logical_jbod["sasLogicalInterconnectUri"] - - drivepaths = [] - for logical_Drive_Bay_Uri in sas_logical_jbod["logicalDriveBayUris"]: - drivepath = get_drive_path_from_logical_Drive_Bay_Uri( - logical_Drive_Bay_Uri) - drivepaths.append(drivepath) - - drive_enclosure_uri = \ - get_drive_enclosure_uri_from_sas_Logical_Interconnect( - sas_Logical_Interconnect_Uri) - - drive_enclosure_object = get_drive_enclosure_object( - drive_enclosure_uri) + drive_enclosure_object, drivepaths = \ + get_drive_enclosure_and_drivepaths(sas_logical_jbod) drivebayuris = get_drivebayuris_from_drive_enclosure_object( drivepaths, drive_enclosure_object) + device_slot = get_device_slot_from_sas_logical_jbod_by_volumeid( server_profile, volume_id) raidlevel = get_raidLevel(server_profile, device_slot, volume_id) @@ -196,6 +184,26 @@ def build_external_storage_volume_details(sp_uuid, volume, volume_id): return Volume(attrs) +def get_drive_enclosure_and_drivepaths(sas_logical_jbod): + sas_Logical_Interconnect_Uri = \ + sas_logical_jbod["sasLogicalInterconnectUri"] + + drivepaths = [] + for logical_Drive_Bay_Uri in sas_logical_jbod["logicalDriveBayUris"]: + drivepath = get_drive_path_from_logical_Drive_Bay_Uri( + logical_Drive_Bay_Uri) + drivepaths.append(drivepath) + + drive_enclosure_uri = \ + get_drive_enclosure_uri_from_sas_Logical_Interconnect( + sas_Logical_Interconnect_Uri) + + drive_enclosure_object = get_drive_enclosure_object( + drive_enclosure_uri) + + return drive_enclosure_object, drivepaths + + def get_sas_logical_jbod_by_volumeid(server_profile, volume_id): for logical_jbod in server_profile["localStorage"]["sasLogicalJBODs"]: diff --git a/oneview_redfish_toolkit/blueprints/storage.py b/oneview_redfish_toolkit/blueprints/storage.py index 686385a3..4e2978de 100755 --- a/oneview_redfish_toolkit/blueprints/storage.py +++ b/oneview_redfish_toolkit/blueprints/storage.py @@ -25,6 +25,8 @@ from oneview_redfish_toolkit.api.computer_system import ComputerSystem from oneview_redfish_toolkit.api.drive import Drive from oneview_redfish_toolkit.api.storage import Storage +from oneview_redfish_toolkit.api.volume import \ + get_drive_enclosure_and_drivepaths from oneview_redfish_toolkit.api.volume import Volume from oneview_redfish_toolkit.api.volume_collection import VolumeCollection from oneview_redfish_toolkit.blueprints.util.response_builder import \ @@ -85,27 +87,34 @@ def get_drive(profile_id, drive_id): """ - drive_id_int = None - logical_jbod = None - try: - drive_id_int = int(drive_id) - except ValueError: - abort(status.HTTP_400_BAD_REQUEST, "Drive id should be a integer") - server_profile = g.oneview_client.server_profiles.get(profile_id) sas_logical_jbods = _find_sas_logical_jbods_by(server_profile) - logical_jbod = _get_logical_jbod(drive_id_int, logical_jbod, - sas_logical_jbods) + try: + logical_jbod = None + drive_id_int = int(drive_id) - if logical_jbod is None: - abort(status.HTTP_404_NOT_FOUND, "Drive {} not found" - .format(drive_id)) + logical_jbod = _get_logical_jbod(drive_id_int, logical_jbod, + sas_logical_jbods) + if logical_jbod is None: + abort(status.HTTP_404_NOT_FOUND, "Drive {} not found" + .format(drive_id)) + + drive_details = Drive.build_for_computer_system(drive_id_int, + server_profile, + logical_jbod) + except ValueError: + # if drive id is not a number then check for computer system volume + # drive + drive = _get_drive(sas_logical_jbods, drive_id) - drive_details = Drive.build_for_computer_system(drive_id_int, - server_profile, - logical_jbod) + if drive is None: + abort(status.HTTP_404_NOT_FOUND, "Drive {} not found" + .format(drive_id)) + drive_details = Drive.build_for_computer_system_volume(drive_id, + server_profile, + drive) return ResponseBuilder.success(drive_details) @@ -202,3 +211,29 @@ def _is_volume_id_number(volume_id): return True except ValueError: return False + + +def _get_drive(sas_logical_jbods, drive_id): + drive = None + for sas_logical_jbod in sas_logical_jbods: + drive_enclosure_object, drivepaths = \ + get_drive_enclosure_and_drivepaths(sas_logical_jbod) + drive_bays = _get_drive_bays(drivepaths, drive_enclosure_object) + for drive_bay in drive_bays: + if drive_bay["uri"].split("/")[-1] == drive_id: + drive = drive_bay["drive"] + break + if drive: + break + + return drive + + +def _get_drive_bays(drivepaths, drive_enclosure_object): + drive_bays = [] + for drivebay in drive_enclosure_object["driveBays"]: + for drivepath in drivebay["drive"]["drivePaths"]: + if drivepath in drivepaths: + drive_bays.append(drivebay) + + return drive_bays diff --git a/oneview_redfish_toolkit/tests/blueprints/test_storage.py b/oneview_redfish_toolkit/tests/blueprints/test_storage.py index ab3dbd26..a8e1c726 100755 --- a/oneview_redfish_toolkit/tests/blueprints/test_storage.py +++ b/oneview_redfish_toolkit/tests/blueprints/test_storage.py @@ -310,24 +310,74 @@ def test_get_drive_when_drive_not_found(self): ] ) - def test_get_drive_when_drive_id_is_invalid(self): + @mock.patch.object(volume, "get_drive_path_from_logical_Drive_Bay_Uri") + @mock.patch.object(volume, "get_drive_enclosure_uri_from_sas_Logical_" + "Interconnect") + def test_get_drive_when_drive_id_is_not_int(self, get_drive_enclosure_uri, + get_drive_mock): """Tests when drive id is not a number""" + expected_result = { + "@odata.context": "/redfish/v1/$metadata#Drive.Drive", + "@odata.id": "/redfish/v1/Systems/b425802b-a6a5-4941-8885-" + "aab68dfa2ee2/Storage/1/Drives/" + "5c3e5214-e9fb-469d-a8d5-2159fe2d97d8", + "@odata.type": "#Drive.v1_4_0.Drive", + "CapacityBytes": 107374182400, + "Id": "5c3e5214-e9fb-469d-a8d5-2159fe2d97d8", + "Links": { + "Chassis": { + "@odata.id": "/redfish/v1/Chassis/0000000000A66101" + } + }, + "MediaType": "SSD", + "Name": "Drive 1", + "Protocol": "SATA", + "Status": { + "Health": "OK", + "State": "Enabled" + } + } self.oneview_client.\ server_profiles.get.return_value = self.server_profile self.oneview_client.\ sas_logical_jbods.get.side_effect = self.logical_jbods + get_drive_mock.return_value = "1:1:1" + get_drive_enclosure_uri.return_value = "/rest/drive-enclosures/" + "SN123100" + + self.oneview_client.\ + drive_enclosures.get.return_value = self.drive_enclosures + + response = self.client.get( + "/redfish/v1/Systems/" + "b425802b-a6a5-4941-8885-aab68dfa2ee2/Storage/1/Drives/" + "5c3e5214-e9fb-469d-a8d5-2159fe2d97d8" + ) + + result = json.loads(response.data.decode("utf-8")) + self.assertEqual(result, expected_result) + self.assertEqual("application/json", response.mimetype) + + def test_get_drive_when_drive_id_invalid(self): + self.oneview_client.\ + server_profiles.get.return_value = self.server_profile + self.oneview_client.\ + sas_logical_jbods.get.side_effect = None + response = self.client.get( "/redfish/v1/Systems/" - "b425802b-a6a5-4941-8885-aab68dfa2ee2/Storage/1/Drives/abc" + "b425802b-a6a5-4941-8885-aab68dfa2ee2/Storage/1/Drives/" + "invalid_id" ) - self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) + result = json.loads(response.data.decode("utf-8")) + self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code) + self.assertEqual(result["error"]["message"], + "Drive invalid_id not found") + self.assertEqual("application/json", response.mimetype) - self.assertIn("Drive id should be a integer", str(response.data)) - self.oneview_client.server_profiles.get.assert_not_called() - self.oneview_client.sas_logical_jbods.get.assert_not_called() def test_composed_system_without_drives(self): """Tests Storage when it does not have drives"""