Skip to content

Commit

Permalink
Merge pull request #40 from opencomputeproject/developer_nvidia
Browse files Browse the repository at this point in the history
Developer NVIDIA
  • Loading branch information
MeritedHobbit authored Oct 7, 2024
2 parents 4276d2e + c55e620 commit f54165b
Show file tree
Hide file tree
Showing 55 changed files with 490 additions and 189 deletions.
11 changes: 8 additions & 3 deletions ctam/interfaces/comptool_dut.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
from ocptv.output import Dut

from interfaces.uri_builder import UriBuilder
from utils.ssh_tunnel_utils import SSHTunnel
from utils.ssh_tunnel_utils import SSHTunnelWithLibrary, SSHTunnelWithSshpass



class CompToolDut(Dut):
Expand Down Expand Up @@ -93,6 +94,7 @@ def __init__(
self.connection_ip_address
)
self.multipart_form_data = redfish_uri_config.get("GPU", {}).get("MultiPartFormData", False)
self.multipart_force_update = redfish_uri_config.get("GPU", {}).get("MultiPartForceUpdate", False)
self.multipart_push_uri_support = redfish_uri_config.get("GPU", {}).get("MultiPartPushUriSupport", False)
self.binded_port = None
self.SSHTunnelRemoteIPAddress = None
Expand All @@ -105,7 +107,10 @@ def __init__(

self.redfish_ifc = None
self.redfish_auth = config["properties"].get("AuthenticationRequired", {}).get("value", False)
self.ssh_tunnel = SSHTunnel(self.test_info_logger)
if config["properties"].get("SSHTunnelUsingSSHPASS", {}).get("value", False):
self.ssh_tunnel = SSHTunnelWithSshpass(self.test_info_logger)
else:
self.ssh_tunnel = SSHTunnelWithLibrary(self.test_info_logger)

def get_cwd(self):
cwd = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
Expand Down Expand Up @@ -235,7 +240,7 @@ def run_redfish_command(self, uri, mode="GET", body=None, headers=None, timeout=

end_time = time.time()
time_difference_seconds = end_time - start_time
time_difference = datetime.utcfromtimestamp(time_difference_seconds) - datetime.utcfromtimestamp(0)
time_difference = datetime.fromtimestamp(time_difference_seconds) - datetime.fromtimestamp(0)
hours, remainder = divmod(time_difference.seconds, 3600)
minutes, seconds = divmod(remainder, 60)
milliseconds = int(time_difference.microseconds / 1000)
Expand Down
16 changes: 10 additions & 6 deletions ctam/interfaces/functional_ifc.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,11 +554,11 @@ def ctam_activate_ac(self, check_time=False, gpu_check=True, fwupd_hyst_wait=Tru
:param check_time: Check the activation time does not exceed maximum time per spec
:returns: ActivationStatus
:rtype: Bool
:rtype: Bool, string
"""
MyName = __name__ + "." + self.ctam_activate_ac.__qualname__
ActivationStatus = False

status_msg = ""
FwActivationTimeMax = self.dut().dut_config["FwActivationTimeMax"]["value"]
if check_time:
if self.dut().dut_config["PowerOnWaitTime"]["value"] > FwActivationTimeMax:
Expand All @@ -567,7 +567,8 @@ def ctam_activate_ac(self, check_time=False, gpu_check=True, fwupd_hyst_wait=Tru
FwActivationTimeMax = self.dut().dut_config["PowerOnWaitTime"]["value"]

if not self.NodeACReset(): # NodeACReset declaration pending
return ActivationStatus
status_msg = "Error while running power cycle"
return ActivationStatus, status_msg

if gpu_check:
if (check_time):
Expand All @@ -579,7 +580,8 @@ def ctam_activate_ac(self, check_time=False, gpu_check=True, fwupd_hyst_wait=Tru
if ((time.time() - ActivationStartTime) > FwActivationTimeMax):
msg = "GPU showing error"
self.test_run().add_log(LogSeverity.DEBUG, msg)
return ActivationStatus
status_msg = msg
return ActivationStatus, status_msg
msg = "Waiting for GPU to be back up"
self.test_run().add_log(LogSeverity.DEBUG, msg)
time.sleep(30)
Expand All @@ -591,7 +593,8 @@ def ctam_activate_ac(self, check_time=False, gpu_check=True, fwupd_hyst_wait=Tru
if (time.time() - ActivationStartTime) > FwActivationTimeMax:
msg = "GPU still not up, {}".format(
(self.IsGPUReachable())["Status"]["State"])
return ActivationStatus
status_msg = msg + f" Activation is taking longer than the maximum time specified {FwActivationTimeMax} seconds."
return ActivationStatus, status_msg
msg = "Waiting for GPU to be back up, {}".format(
(self.IsGPUReachable())["Status"]["State"])
self.test_run().add_log(LogSeverity.DEBUG, msg)
Expand All @@ -603,6 +606,7 @@ def ctam_activate_ac(self, check_time=False, gpu_check=True, fwupd_hyst_wait=Tru
ActivationStatus = False
msg = f"Activation is taking longer than the maximum time specified {FwActivationTimeMax} seconds."
self.test_run().add_log(LogSeverity.WARNING, msg)
status_msg = msg
else:
ActivationStatus = True

Expand All @@ -614,7 +618,7 @@ def ctam_activate_ac(self, check_time=False, gpu_check=True, fwupd_hyst_wait=Tru
msg = f"Execution is delayed successfully by {IdleWaitTime} seconds."
self.test_run().add_log(LogSeverity.INFO, msg)

return True and ActivationStatus
return ActivationStatus, status_msg

def RedfishTriggerDumpCollection(self, DiagnosticDataType, URI, OEMDiagnosticDataType=None):
"""
Expand Down
93 changes: 53 additions & 40 deletions ctam/interfaces/fw_update_ifc.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ def PLDMComponentVersions(self, image_type):

def ctam_get_fw_version(self, PostInstall=0):
"""
:Description: Get Firmware Version
:param PostInstall: Get Version after install the Firmware or before installing
:Description: Get Firmware Version
:param PostInstall: Get Version after install the Firmware or before installing
:returns: None
:returns: None
"""

MyName = __name__ + "." + self.ctam_get_fw_version.__qualname__
Expand All @@ -100,11 +100,11 @@ def ctam_get_fw_version(self, PostInstall=0):

def ctam_fw_update_precheck(self, image_type="default"):
"""
:Description: Check Firmware before installation
:param image_type: Type of the Firmware image
:Description: Check Firmware before installation
:param image_type: Type of the Firmware image
:returns: VersionsDifferent
:rtype: Bool
:returns: VersionsDifferent
:rtype: Bool
"""
MyName = __name__ + "." + self.ctam_fw_update_precheck.__qualname__
VersionsDifferent = True
Expand All @@ -122,7 +122,7 @@ def ctam_fw_update_precheck(self, image_type="default"):
):
msg = f"Pre Install Details: {element['Id']} : {element['SoftwareId']} : {element.get('Version', 'NA')} : "
if str(element["Updateable"]) == "True":

SoftwareId = str(hex(int(element["SoftwareId"], 16)))
if SoftwareId in BundleComponentIdsAndVersions.keys():

Expand All @@ -138,11 +138,11 @@ def ctam_fw_update_precheck(self, image_type="default"):
msg += f"Update Capable to {Package_Version}"

else:
msg += "Update Not Needed."
msg += "Update Not Needed ."
else:
msg += "SoftwareId not found in PLDM JSON."
self.test_run().add_log(LogSeverity.DEBUG, msg)
status_message = msg
else:
# Not in HttpPushURITargets
pass
Expand All @@ -155,17 +155,18 @@ def ctam_stage_fw(
check_time=False, specific_targets=[]
):
"""
:Description: Stage Firmware
:param partial: Partial
:param image_type: Type of Firmware Image
:param wait_for_stage_completion: Wait for stage completion
:Description: Stage Firmware
:param partial: Partial
:param image_type: Type of Firmware Image
:param wait_for_stage_completion: Wait for stage completion
:param corrupted_component_id: ComponentIdentifier of the component image to be corrupted for specific negative tests
:param corrupted_component_list: List component names (Ids) which are corrupted
:param check_time: Check the staging time does not exceed maximum time per spec
:returns: StageFWOOB_Status, StageFWOOB_Status_message, return_task_id
:rtype: Bool, str, str
:returns: StageFWOOB_Status, StageFWOOB_Status_message, return_task_id
:rtype: Bool, str, str
"""
status_msg = ""
MyName = __name__ + "." + self.ctam_stage_fw.__qualname__
StartTime = time.time()
pushtargets = self.dut().uri_builder.format_uri(redfish_str="{HttpPushUriTargets}", component_type="GPU")
Expand All @@ -174,7 +175,11 @@ def ctam_stage_fw(
JSONFWFilePayload = self.get_JSONFWFilePayload_file(image_type=image_type, corrupted_component_id=corrupted_component_id)
if not JSONFWFilePayload or not os.path.isfile(JSONFWFilePayload):
self.test_run().add_log(LogSeverity.DEBUG, f"Package file not found at path {JSONFWFilePayload}!!!")
return False, "", ""
if corrupted_component_id != None:
status_msg = "Error in creating corrupted component!"
else:
status_msg = f"Package file not found in the workspace !!!"
return False, status_msg, ""
if self.dut().is_debug_mode():
print(JSONFWFilePayload)
update_uri = self.dut().redfish_uri_config.get("GPU", {}).get("UpdateURI", "")
Expand All @@ -188,8 +193,9 @@ def ctam_stage_fw(
status, uri, is_multipart = self.get_update_uri()
if not status:
self.test_run().add_log(LogSeverity.DEBUG, f"Unable to find update uri from UpdateService resource!!!")
return False, "", ""
targets = json.dumps({"Targets" : self.get_target_inventorys(targets=specific_targets)}) if specific_targets else '{}'
status_msg = "Unable to find update uri from UpdateService resource!!!"
return False, status_msg, ""
targets = self.get_target_inventorys(targets=specific_targets) if specific_targets else []
if self.dut().is_debug_mode():
self.test_run().add_log(LogSeverity.DEBUG, f"URI : {uri}")
self.test_run().add_log(LogSeverity.DEBUG, f"Targets : {targets}")
Expand All @@ -213,6 +219,7 @@ def ctam_stage_fw(
msg = f"FW copy operation exceeded the maximum time {FwStagingTimeMax} seconds."
self.test_run().add_log(LogSeverity.DEBUG, msg)
StageFWOOB_Status = False
stage_msg = msg

msg = "{0}: GPU Deployment Time: {1} GPU Update Time: {2} \n Redfish Outcome: {3}".format(
MyName,
Expand All @@ -236,6 +243,8 @@ def ctam_stage_fw(
task_message_list=JSONData["Messages"],
corrupted_component_id=corrupted_component_id
)
if StageFWOOB_Status == False:
stage_msg = "Non corrupt component staging failed!!"
else:
StageFWOOB_Status = True
else:
Expand All @@ -244,6 +253,7 @@ def ctam_stage_fw(
)
self.test_run().add_log(LogSeverity.DEBUG, msg)
StageFWOOB_Status = False
stage_msg = msg
else:
StageFWOOB_Status = True
else:
Expand Down Expand Up @@ -277,21 +287,23 @@ def ctam_stage_fw(
self.test_run().add_log(LogSeverity.DEBUG, msg)

StageFWOOB_Status = False
stage_msg = msg
return StageFWOOB_Status, stage_msg, FwUpdTaskID

def ctam_fw_update_verify(self, image_type="default", corrupted_component_id=None, specific_targets=[], version_check=True):
"""
:Description: Firmware Update verification
:param image_type: Firmware image type
:Description: Firmware Update verification
:param image_type: Firmware image type
:param corrupted_component_id: ComponentIdentifier (in hex format) of the corrupted component image
:returns: Update_Verified
:rtype: Bool
:returns: Update_Verified, string
:rtype: Bool, string
"""
MyName = __name__ + "." + self.ctam_fw_update_verify.__qualname__
Update_Verified = True
update_successful = []
update_failed = []
update_failed = []
status_msg = ""
self.ctam_get_fw_version(PostInstall=1)
msg = json.dumps(self.PostInstallDetails, indent=4)
self.test_run().add_log(LogSeverity.DEBUG, msg)
Expand Down Expand Up @@ -333,6 +345,7 @@ def ctam_fw_update_verify(self, image_type="default", corrupted_component_id=Non
update_failed.append(element['SoftwareId'])
Update_Verified = False
msg += f"Update Failed : Expected {ExpectedVersion}"
status_msg += "\n" + msg

elif negative_case:
# Negative test case, but expected.
Expand All @@ -351,7 +364,7 @@ def ctam_fw_update_verify(self, image_type="default", corrupted_component_id=Non
Update_Verified = False
msg = f"Updated Components count - {len(update_successful)} and Failed Components count - {len(update_failed)}"
self.test_run().add_log(LogSeverity.DEBUG, msg)
return Update_Verified
return Update_Verified, status_msg

def get_target_inventorys(self, targets):
return [
Expand All @@ -365,9 +378,9 @@ def get_target_inventorys(self, targets):

def get_update_uri(self):
"""
:Description: Get supported fwupdate uri, multipart push uri over httpush
:returns: whether uri was found, update uri and if it supports multipart push
:rtype: Bool, Str, Bool
:Description: Get supported fwupdate uri, multipart push uri over httpush
:returns: whether uri was found, update uri and if it supports multipart push
:rtype: Bool, Str, Bool
"""

uri = self.dut().uri_builder.format_uri(
Expand Down Expand Up @@ -415,13 +428,13 @@ def ctam_pushtargets(self, targets=[], is_multipart_uri=False):
print("{} {}".format(MyName, str(targets)))
return PushSuccess

def RedFishFWUpdate(self, BinPath, URI, targets='{}', is_multipart=False):
def RedFishFWUpdate(self, BinPath, URI, targets=[], is_multipart=False):
"""
:Description: It will update system firmware using redfish command.
:param BinPath: Path for the bin
:param URI: URI for creating URL
:param BinPath: Path for the bin
:param URI: URI for creating URL
:returns: JSON data after executing redfish command
:returns: JSON data after executing redfish command
:rtype: JSON Dict
"""
MyName = __name__ + "." + self.RedFishFWUpdate.__qualname__
Expand All @@ -431,7 +444,7 @@ def RedFishFWUpdate(self, BinPath, URI, targets='{}', is_multipart=False):
headers = {"Content-Type": "multipart/form-data"}
body = {
"UpdateFile": (BinPath, open(BinPath, "rb"), "application/octet-stream"),
"UpdateParameters" : ("Targets", targets,'application/json')
"UpdateParameters" : ("Targets", json.dumps({"Targets": targets, "ForceUpdate": True if self.dut().multipart_force_update else False}),'application/json')
}
response = self.dut().run_request_command(uri=URI, mode="POST",files=body, body={})
JSONData = response.json()
Expand All @@ -445,7 +458,7 @@ def RedFishFWUpdate(self, BinPath, URI, targets='{}', is_multipart=False):
else:
headers = {"Content-Type": "application/octet-stream"}
body = open(BinPath, "rb").read()
response = self.dut().run_request_command(uri=URI, mode="POST", files=body, headers=None)
response = self.dut().run_request_command(uri=URI, mode="POST", body=body, headers=headers)
JSONData = response.json()
msg = "{0}: RedFish Input: {1} Result: {2}".format(MyName, BinPath, JSONData)
self.test_run().add_log(LogSeverity.DEBUG, msg)
Expand Down Expand Up @@ -518,7 +531,7 @@ def ctam_get_component_to_be_corrupted(self, VendorProvidedBundle=True):
:param VendorProvidedBundle: Boolean value indicating if the vendor is required to provide a corrupt bundle.
True by default.
:returns: SoftwareID of the component to be corrupted (in hex format)
:returns: SoftwareID of the component to be corrupted (in hex format)
:rtype: str. None in case of failure
"""
MyName = __name__ + "." + self.ctam_get_component_to_be_corrupted.__qualname__
Expand Down Expand Up @@ -555,7 +568,7 @@ def ctam_check_component_fwupd_failure(self, task_message_list, corrupted_compon
:param task_message_list: List of message from the task status response
:param corrupted_component_id: ComponentIdentifier (in hex format) of the corrupted component image
:returns: NonCorruptCompStaging_Success
:returns: NonCorruptCompStaging_Success
:rtype: Bool
"""
MyName = __name__ + "." + self.ctam_check_component_fwupd_failure.__qualname__
Expand All @@ -580,7 +593,7 @@ def ctam_get_component_list(self, component_id):
:param component_id: Component ID / SoftwareID
:returns: List of components with the component ID
:returns: List of components with the component ID
:rtype: list
"""
JSONData = self.ctam_getfi(expanded=1)
Expand All @@ -595,7 +608,7 @@ def ctam_compare_active_components_count(self):
if pre install and post install details are empty. Make sure to
call ctam_get_fw_version method to fill up pre and post install details.
:returns: AllComponentsActive
:returns: AllComponentsActive
:rtype: Bool
"""

Expand All @@ -622,9 +635,9 @@ def ctam_get_version_from_bundle(self, image_type):
:Description: It will check the PLDM bundle json and find FW version
of the component with the specified software id.
:param image_type: image type
:param image_type: image type
:returns: ComponentVersions
:returns: ComponentVersions
:rtype: string
"""

Expand Down
Loading

0 comments on commit f54165b

Please sign in to comment.