X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FHoststackUtil.py;h=35acdd70ee5c592e1877c6fd7695be66887fc9b7;hb=86138e3eb1fbaad89eb1f91937ae6bd6ba55da37;hp=d184b5af6dfefd9c03589d7012b955b813285f51;hpb=5570bf3ab49301201dd7607bb4f8de67fd8f16dc;p=csit.git diff --git a/resources/libraries/python/HoststackUtil.py b/resources/libraries/python/HoststackUtil.py index d184b5af6d..35acdd70ee 100644 --- a/resources/libraries/python/HoststackUtil.py +++ b/resources/libraries/python/HoststackUtil.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 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.""" @@ -35,7 +38,6 @@ class HoststackUtil(): 'args' - command arguments. :rtype: dict """ - # TODO: Use a python class instead of dictionary for the return type proto = vpp_echo_attributes[u"uri_protocol"] addr = vpp_echo_attributes[u"uri_ip4_addr"] port = vpp_echo_attributes[u"uri_port"] @@ -71,7 +73,6 @@ class HoststackUtil(): 'args' - command arguments. :rtype: dict """ - # TODO: Use a python class instead of dictionary for the return type iperf3_cmd = {} iperf3_cmd[u"env_vars"] = f"VCL_CONFIG={Constants.REMOTE_FW_DIR}/" \ f"{Constants.RESOURCES_TPL_VCL}/" \ @@ -100,6 +101,13 @@ class HoststackUtil(): if u"time" in iperf3_attributes: iperf3_cmd[u"args"] += \ f" --time {iperf3_attributes[u'time']}" + if iperf3_attributes[u"udp"]: + iperf3_cmd[u"args"] += u" --udp" + iperf3_cmd[u"args"] += \ + f" --bandwidth {iperf3_attributes[u'bandwidth']}" + if iperf3_attributes[u"length"] > 0: + iperf3_cmd[u"args"] += \ + f" --length {iperf3_attributes[u'length']}" return iperf3_cmd @staticmethod @@ -164,6 +172,39 @@ class HoststackUtil(): message=f"Get {program_name} stderr log failed!") return stdout_log, stderr_log + @staticmethod + def get_nginx_command(nginx_attributes, nginx_version, nginx_ins_dir): + """Construct the NGINX command using the specified attributes. + + :param nginx_attributes: NGINX test program attributes. + :param nginx_version: NGINX version. + :param nginx_ins_dir: NGINX install dir. + :type nginx_attributes: dict + :type nginx_version: str + :type nginx_ins_dir: str + :returns: Command line components of the NGINX command + 'env_vars' - environment variables + 'name' - program name + 'args' - command arguments. + 'path' - program path. + :rtype: dict + """ + nginx_cmd = dict() + nginx_cmd[u"env_vars"] = f"VCL_CONFIG={Constants.REMOTE_FW_DIR}/" \ + f"{Constants.RESOURCES_TPL_VCL}/" \ + f"{nginx_attributes[u'vcl_config']}" + if nginx_attributes[u"ld_preload"]: + nginx_cmd[u"env_vars"] += \ + f" LD_PRELOAD={Constants.VCL_LDPRELOAD_LIBRARY}" + if nginx_attributes[u'transparent_tls']: + nginx_cmd[u"env_vars"] += u" LDP_ENV_TLS_TRANS=1" + + nginx_cmd[u"name"] = u"nginx" + nginx_cmd[u"path"] = f"{nginx_ins_dir}nginx-{nginx_version}/sbin/" + nginx_cmd[u"args"] = f"-c {nginx_ins_dir}/" \ + f"nginx-{nginx_version}/conf/nginx.conf" + return nginx_cmd + @staticmethod def start_hoststack_test_program(node, namespace, core_list, program): """Start the specified HostStack test program. @@ -194,9 +235,13 @@ class HoststackUtil(): env_vars = f"{program[u'env_vars']} " if u"env_vars" in program else u"" args = program[u"args"] - cmd = f"nohup {shell_cmd} \'{env_vars}taskset --cpu-list {core_list} " \ - f"{program_name} {args} >/tmp/{program_name}_stdout.log " \ - f"2>/tmp/{program_name}_stderr.log &\'" + program_path = program.get(u"path", u"") + # NGINX used `worker_cpu_affinity` in configuration file + taskset_cmd = u"" if program_name == u"nginx" else \ + f"taskset --cpu-list {core_list}" + cmd = f"nohup {shell_cmd} \'{env_vars}{taskset_cmd} " \ + f"{program_path}{program_name} {args} >/tmp/{program_name}_" \ + f"stdout.log 2>/tmp/{program_name}_stderr.log &\'" try: exec_cmd_no_error(node, cmd, sudo=True) return DUTSetup.get_pid(node, program_name)[0] @@ -246,7 +291,6 @@ class HoststackUtil(): cmd = f"sh -c 'strace -qqe trace=none -p {program_pid}'" exec_cmd(node, cmd, sudo=True) # 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 @@ -289,9 +333,9 @@ class HoststackUtil(): program_cmd = f"{env_vars}{program_name} {program[u'args']}" test_results = f"Test Results of '{program_cmd}':\n" - if nsim_attr[u"output_feature_enable"] or \ - nsim_attr[u"cross_connect_feature_enable"]: - if nsim_attr[u"output_feature_enable"]: + if nsim_attr[u"output_nsim_enable"] or \ + nsim_attr[u"xc_nsim_enable"]: + if nsim_attr[u"output_nsim_enable"]: feature_name = u"output" else: feature_name = u"cross-connect" @@ -299,11 +343,10 @@ class HoststackUtil(): f"NSIM({feature_name}): delay " \ f"{nsim_attr[u'delay_in_usec']} usecs, " \ f"avg-pkt-size {nsim_attr[u'average_packet_size']}, " \ - f"bandwidth {nsim_attr[u'bandwidth_in_bits_per_second']} " \ + f"bandwidth {nsim_attr[u'bw_in_bits_per_second']} " \ 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" @@ -321,11 +364,13 @@ 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=program_json["time"] + ) else: test_results += u"Invalid test data output!\n" + program_stdout return (True, test_results) @@ -333,6 +378,11 @@ class HoststackUtil(): test_results += program_stdout iperf3_json = json.loads(program_stdout) program_json = iperf3_json[u"intervals"][0][u"sum"] + export_hoststack_results( + bandwidth=program_json["bits_per_second"], + duration=program_json["seconds"], + retransmits=program_json["retransmits"] + ) else: test_results += u"Unknown HostStack Test Program!\n" + \ program_stdout @@ -350,3 +400,18 @@ class HoststackUtil(): :rtype: bool """ return server_defer_fail and client_defer_fail + + @staticmethod + def log_vpp_hoststack_data(node): + """Retrieve and log VPP HostStack data. + + :param node: DUT node. + :type node: dict + :raises RuntimeError: If node subtype is not a DUT or startup failed. + """ + + if node[u"type"] != u"DUT": + raise RuntimeError(u"Node type is not a DUT!") + + PapiSocketExecutor.run_cli_cmd(node, u"show error") + PapiSocketExecutor.run_cli_cmd(node, u"show interface")