X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FHoststackUtil.py;h=7e6ba569137e54de1c6b3b06f256010766e3d8d9;hp=76c75ee86769f8c8102f974ea1eac33877ba6021;hb=HEAD;hpb=7829fea4a2c8936513fa95215b7d84997f814a69 diff --git a/resources/libraries/python/HoststackUtil.py b/resources/libraries/python/HoststackUtil.py index 76c75ee867..399395d41a 100644 --- a/resources/libraries/python/HoststackUtil.py +++ b/resources/libraries/python/HoststackUtil.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Cisco and/or its affiliates. +# Copyright (c) 2023 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -17,9 +17,12 @@ from time import sleep from robot.api import logger from resources.libraries.python.Constants import Constants -from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error -from resources.libraries.python.PapiExecutor import PapiSocketExecutor from resources.libraries.python.DUTSetup import DUTSetup +from resources.libraries.python.model.ExportResult import ( + export_hoststack_results +) +from resources.libraries.python.PapiExecutor import PapiSocketExecutor +from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error class HoststackUtil(): """Utilities for Host Stack tests.""" @@ -41,7 +44,7 @@ class HoststackUtil(): vpp_echo_cmd = {} vpp_echo_cmd[u"name"] = u"vpp_echo" vpp_echo_cmd[u"args"] = f"{vpp_echo_attributes[u'role']} " \ - f"socket-name {vpp_echo_attributes[u'vpp_api_socket']} " \ + f"socket-name {vpp_echo_attributes[u'app_api_socket']} " \ f"{vpp_echo_attributes[u'json_output']} " \ f"uri {proto}://{addr}/{port} " \ f"nthreads {vpp_echo_attributes[u'nthreads']} " \ @@ -56,6 +59,8 @@ class HoststackUtil(): vpp_echo_cmd[u"args"] += u" rx-results-diff" if vpp_echo_attributes[u"tx_results_diff"]: vpp_echo_cmd[u"args"] += u" tx-results-diff" + if vpp_echo_attributes[u"use_app_socket_api"]: + vpp_echo_cmd[u"args"] += u" use-app-socket-api" return vpp_echo_cmd @staticmethod @@ -151,15 +156,14 @@ class HoststackUtil(): raise @staticmethod - def get_hoststack_test_program_logs(node, program): + def _get_hoststack_test_program_logs(node, program_name): """Get HostStack test program stdout log. :param node: DUT node. - :param program: test program. + :param program_name: test program. :type node: dict - :type program: dict + :type program_name: str """ - program_name = program[u"name"] cmd = f"sh -c \'cat /tmp/{program_name}_stdout.log\'" stdout_log, _ = exec_cmd_no_error(node, cmd, sudo=True, \ message=f"Get {program_name} stdout log failed!") @@ -167,8 +171,29 @@ class HoststackUtil(): cmd = f"sh -c \'cat /tmp/{program_name}_stderr.log\'" stderr_log, _ = exec_cmd_no_error(node, cmd, sudo=True, \ message=f"Get {program_name} stderr log failed!") + return stdout_log, stderr_log + @staticmethod + def get_hoststack_test_program_logs(node, program): + """Get HostStack test program stdout log. + + :param node: DUT node. + :param program: test program. + :type node: dict + :type program: dict + """ + program_name = program[u"name"] + program_stdout_log, program_stderr_log = \ + HoststackUtil._get_hoststack_test_program_logs(node, + program_name) + if len(program_stdout_log) == 0 and len(program_stderr_log) == 0: + logger.trace(f"Retrying {program_name} log retrieval") + program_stdout_log, program_stderr_log = \ + HoststackUtil._get_hoststack_test_program_logs(node, + program_name) + return program_stdout_log, program_stderr_log + @staticmethod def get_nginx_command(nginx_attributes, nginx_version, nginx_ins_dir): """Construct the NGINX command using the specified attributes. @@ -273,22 +298,69 @@ class HoststackUtil(): exec_cmd_no_error(node, cmd, message=errmsg, sudo=True) @staticmethod - def hoststack_test_program_finished(node, program_pid): + def hoststack_test_program_finished(node, program_pid, program, + other_node, other_program): """Wait for the specified HostStack test program process to complete. :param node: DUT node. :param program_pid: test program pid. + :param program: test program + :param other_node: DUT node of other hoststack program + :param other_program: other test program :type node: dict :type program_pid: str + :type program: dict + :type other_node: dict + :type other_program: dict :raises RuntimeError: If node subtype is not a DUT. """ if node[u"type"] != u"DUT": raise RuntimeError(u"Node type is not a DUT!") + if other_node[u"type"] != u"DUT": + raise RuntimeError(u"Other node type is not a DUT!") cmd = f"sh -c 'strace -qqe trace=none -p {program_pid}'" - exec_cmd(node, cmd, sudo=True) + try: + exec_cmd(node, cmd, sudo=True) + except: + sleep(180) + if u"client" in program[u"args"]: + role = u"client" + else: + role = u"server" + program_stdout, program_stderr = \ + HoststackUtil.get_hoststack_test_program_logs(node, program) + if len(program_stdout) > 0: + logger.debug(f"{program[u'name']} {role} stdout log:\n" + f"{program_stdout}") + else: + logger.debug(f"Empty {program[u'name']} {role} stdout log :(") + if len(program_stderr) > 0: + logger.debug(f"{program[u'name']} stderr log:\n" + f"{program_stderr}") + else: + logger.debug(f"Empty {program[u'name']} stderr log :(") + if u"client" in other_program[u"args"]: + role = u"client" + else: + role = u"server" + program_stdout, program_stderr = \ + HoststackUtil.get_hoststack_test_program_logs(other_node, + other_program) + if len(program_stdout) > 0: + logger.debug(f"{other_program[u'name']} {role} stdout log:\n" + f"{program_stdout}") + else: + logger.debug(f"Empty {other_program[u'name']} " + f"{role} stdout log :(") + if len(program_stderr) > 0: + logger.debug(f"{other_program[u'name']} {role} stderr log:\n" + f"{program_stderr}") + else: + logger.debug(f"Empty {other_program[u'name']} " + f"{role} stderr log :(") + raise # Wait a bit for stdout/stderr to be flushed to log files - # TODO: see if sub-second sleep works e.g. sleep(0.1) sleep(1) @staticmethod @@ -322,10 +394,6 @@ class HoststackUtil(): program_name = program[u"name"] program_stdout, program_stderr = \ HoststackUtil.get_hoststack_test_program_logs(node, program) - if len(program_stdout) == 0 and len(program_stderr) == 0: - logger.trace(f"Retrying {program_name} log retrieval") - program_stdout, program_stderr = \ - HoststackUtil.get_hoststack_test_program_logs(node, program) env_vars = f"{program[u'env_vars']} " if u"env_vars" in program else u"" program_cmd = f"{env_vars}{program_name} {program[u'args']}" @@ -345,7 +413,6 @@ class HoststackUtil(): f"bits/sec, pkt-drop-rate {nsim_attr[u'packets_per_drop']} " \ f"pkts/drop\n" - # TODO: Incorporate show error stats into results analysis test_results += \ f"\n{role} VPP 'show errors' on host {node[u'host']}:\n" \ f"{PapiSocketExecutor.run_cli_cmd(node, u'show error')}\n" @@ -363,18 +430,28 @@ class HoststackUtil(): if u"JSON stats" in program_stdout and \ u'"has_failed": "0"' in program_stdout: json_start = program_stdout.find(u"{") - #TODO: Fix parsing once vpp_echo produces valid - # JSON output. Truncate for now. json_end = program_stdout.find(u',\n "closing"') json_results = f"{program_stdout[json_start:json_end]}\n}}" program_json = json.loads(json_results) + export_hoststack_results( + bandwidth=program_json["rx_bits_per_second"], + duration=float(program_json["time"]) + ) else: test_results += u"Invalid test data output!\n" + program_stdout return (True, test_results) elif program[u"name"] == u"iperf3": test_results += program_stdout - iperf3_json = json.loads(program_stdout) - program_json = iperf3_json[u"intervals"][0][u"sum"] + program_json = json.loads(program_stdout)[u"intervals"][0][u"sum"] + try: + retransmits = program_json["retransmits"] + except KeyError: + retransmits = None + export_hoststack_results( + bandwidth=program_json["bits_per_second"], + duration=program_json["seconds"], + retransmits=retransmits + ) else: test_results += u"Unknown HostStack Test Program!\n" + \ program_stdout