diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/automation/regression/cfg/global_regression_cfg.yaml | 19 | ||||
-rw-r--r-- | scripts/automation/regression/trex.py | 421 | ||||
-rwxr-xr-x | scripts/automation/regression/trex_unit_test.py | 23 |
3 files changed, 40 insertions, 423 deletions
diff --git a/scripts/automation/regression/cfg/global_regression_cfg.yaml b/scripts/automation/regression/cfg/global_regression_cfg.yaml new file mode 100755 index 00000000..4bb9fb54 --- /dev/null +++ b/scripts/automation/regression/cfg/global_regression_cfg.yaml @@ -0,0 +1,19 @@ +#------------------------------------------- +# Various global parameters of regression +#------------------------------------------- + + +########## Reporting results ######### + +elk: + server: sceasr-b20 + port: 9200 + +google: + id: UA-75220362-3 + queue_size: 100 + timeout: 5 + blocking: 0 + + + diff --git a/scripts/automation/regression/trex.py b/scripts/automation/regression/trex.py index 4f5eba60..36e204af 100644 --- a/scripts/automation/regression/trex.py +++ b/scripts/automation/regression/trex.py @@ -11,6 +11,8 @@ from CProgressDisp import TimedProgressBar from stateful_tests.tests_exceptions import TRexInUseError import datetime import copy +import outer_packages +import yaml class CTRexScenario: modes = set() # list of modes of this setup: loopback, virtual etc. @@ -44,6 +46,7 @@ class CTRexScenario: json_verbose = False elk = None elk_info = None + global_cfg = None def copy_elk_info (): assert(CTRexScenario.elk_info) @@ -53,420 +56,12 @@ def copy_elk_info (): d['timestamp']=timestamp.strftime("%Y-%m-%d %H:%M:%S") return(d) - +global_cfg = 'cfg/global_regression_cfg.yaml' +if not os.path.exists(global_cfg): + raise Exception('Global configuration file %s is missing' % global_cfg) +with open(global_cfg) as f: + CTRexScenario.global_cfg = yaml.safe_load(f.read()) -class CTRexRunner: - """This is an instance for generating a CTRexRunner""" - def __init__ (self, config_dict, yaml): - self.trex_config = config_dict#misc_methods.load_config_file(config_file) - self.yaml = yaml - - - def get_config (self): - """ get_config() -> dict - - Returns the stored configuration of the TRex server of the CTRexRunner instance as a dictionary - """ - return self.trex_config - - def set_yaml_file (self, yaml_path): - """ update_yaml_file (self, yaml_path) -> None - - Defines the yaml file to be used by the TRex. - """ - self.yaml = yaml_path - - - def generate_run_cmd (self, multiplier, cores, duration, nc = True, export_path="/tmp/trex.txt", **kwargs): - """ generate_run_cmd(self, multiplier, duration, export_path) -> str - - Generates a custom running command for the kick-off of the TRex traffic generator. - Returns a command (string) to be issued on the trex server - - Parameters - ---------- - multiplier : float - Defines the TRex multiplier factor (platform dependant) - duration : int - Defines the duration of the test - export_path : str - a full system path to which the results of the trex-run will be logged. - - """ - fileName, fileExtension = os.path.splitext(self.yaml) - if self.yaml == None: - raise ValueError('TRex yaml file is not defined') - elif fileExtension != '.yaml': - raise TypeError('yaml path is not referencing a .yaml file') - - if 'results_file_path' in kwargs: - export_path = kwargs['results_file_path'] - - trex_cmd_str = './t-rex-64 -c %d -m %f -d %d -f %s ' - - if nc: - trex_cmd_str = trex_cmd_str + ' --nc ' - - trex_cmd = trex_cmd_str % (cores, - multiplier, - duration, - self.yaml) - # self.trex_config['trex_latency']) - - for key, value in kwargs.items(): - tmp_key = key.replace('_','-') - dash = ' -' if (len(key)==1) else ' --' - if value == True: - trex_cmd += (dash + tmp_key) - else: - trex_cmd += (dash + '{k} {val}'.format( k = tmp_key, val = value )) - - print("\nTRex COMMAND: ", trex_cmd) - - cmd = 'sshpass.exp %s %s root "cd %s; %s > %s"' % (self.trex_config['trex_password'], - self.trex_config['trex_name'], - self.trex_config['trex_version_path'], - trex_cmd, - export_path) - - return cmd; - - def generate_fetch_cmd (self, result_file_full_path="/tmp/trex.txt"): - """ generate_fetch_cmd(self, result_file_full_path) -> str - - Generates a custom command for which will enable to fetch the resutls of the TRex run. - Returns a command (string) to be issued on the trex server. - - Example use: fetch_trex_results() - command that will fetch the content from the default log file- /tmp/trex.txt - fetch_trex_results("/tmp/trex_secondary_file.txt") - command that will fetch the content from a custom log file- /tmp/trex_secondary_file.txt - """ - #dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) - script_running_dir = os.path.dirname(os.path.realpath(__file__)) # get the current script working directory so that the sshpass could be accessed. - cmd = script_running_dir + '/sshpass.exp %s %s root "cat %s"' % (self.trex_config['trex_password'], - self.trex_config['trex_name'], - result_file_full_path); - return cmd; - - - - def run (self, multiplier, cores, duration, **kwargs): - """ run(self, multiplier, duration, results_file_path) -> CTRexResults - - Running the TRex server based on the config file. - Returns a CTRexResults object containing the results of the run. - - Parameters - ---------- - multiplier : float - Defines the TRex multiplier factor (platform dependant) - duration : int - Defines the duration of the test - results_file_path : str - a full system path to which the results of the trex-run will be logged and fetched from. - - """ - tmp_path = None - # print kwargs - if 'export_path' in kwargs: - tmp_path = kwargs['export_path'] - del kwargs['export_path'] - cmd = self.generate_run_cmd(multiplier, cores, duration, tmp_path, **kwargs) - else: - cmd = self.generate_run_cmd(multiplier, cores, duration, **kwargs) - -# print 'TRex complete command to be used:' -# print cmd - # print kwargs - - progress_thread = TimedProgressBar(duration) - progress_thread.start() - interrupted = False - try: - start_time = time.time() - start = datetime.datetime.now() - results = subprocess.call(cmd, shell = True, stdout = open(os.devnull, 'wb')) - end_time = time.time() - fin = datetime.datetime.now() - # print "Time difference : ", fin-start - runtime_deviation = abs(( (end_time - start_time)/ (duration+15) ) - 1) - print("runtime_deviation: %2.0f %%" % ( runtime_deviation*100.0)) - if ( runtime_deviation > 0.6 ) : - # If the run stopped immediately - classify as Trex in use or reachability issue - interrupted = True - if ((end_time - start_time) < 2): - raise TRexInUseError ('TRex run failed since TRex is used by another process, or due to reachability issues') - else: - CTRexScenario.trex_crashed = True - # results = subprocess.Popen(cmd, stdout = open(os.devnull, 'wb'), - # shell=True, preexec_fn=os.setsid) - except KeyboardInterrupt: - print("\nTRex test interrupted by user during traffic generation!!") - results.killpg(results.pid, signal.SIGTERM) # Send the kill signal to all the process groups - interrupted = True - raise RuntimeError - finally: - progress_thread.join(isPlannedStop = (not interrupted) ) - - if results!=0: - sys.stderr.write("TRex run failed. Please Contact trex-dev mailer for further details") - sys.stderr.flush() - return None - elif interrupted: - sys.stderr.write("TRex run failed due user-interruption.") - sys.stderr.flush() - return None - else: - - if tmp_path: - cmd = self.generate_fetch_cmd( tmp_path )#**kwargs)#results_file_path) - else: - cmd = self.generate_fetch_cmd() - - try: - run_log = subprocess.check_output(cmd, shell = True) - trex_result = CTRexResult(None, run_log) - trex_result.load_file_lines() - trex_result.parse() - - return trex_result - - except subprocess.CalledProcessError: - sys.stderr.write("TRex result fetching failed. Please Contact trex-dev mailer for further details") - sys.stderr.flush() - return None - -class CTRexResult(): - """This is an instance for generating a CTRexResult""" - def __init__ (self, file, buffer = None): - self.file = file - self.buffer = buffer - self.result = {} - - - def load_file_lines (self): - """ load_file_lines(self) -> None - - Loads into the self.lines the content of self.file - """ - if self.buffer: - self.lines = self.buffer.split("\n") - else: - f = open(self.file,'r') - self.lines = f.readlines() - f.close() - - - def dump (self): - """ dump(self) -> None - - Prints nicely the content of self.result dictionary into the screen - """ - for key, value in self.result.items(): - print("{0:20} : \t{1}".format(key, float(value))) - - def update (self, key, val, _str): - """ update (self, key, val, _str) -> None - - Updates the self.result[key] with a possibly new value representation of val - Example: 15K might be updated into 15000.0 - - Parameters - ---------- - key : - Key of the self.result dictionary of the TRexResult instance - val : float - Key of the self.result dictionary of the TRexResult instance - _str : str - a represntation of the BW (. - - """ - - s = _str.strip() - - if s[0]=="G": - val = val*1E9 - elif s[0]=="M": - val = val*1E6 - elif s[0]=="K": - val = val*1E3 - - if key in self.result: - if self.result[key] > 0: - if (val/self.result[key] > 0.97 ): - self.result[key]= val - else: - self.result[key] = val - else: - self.result[key] = val - - - - def parse (self): - """ parse(self) -> None - - Parse the content of the result file from the TRex test and upload the data into - """ - stop_read = False - d = { - 'total-tx' : 0, - 'total-rx' : 0, - 'total-pps' : 0, - 'total-cps' : 0, - - 'expected-pps' : 0, - 'expected-cps' : 0, - 'expected-bps' : 0, - 'active-flows' : 0, - 'open-flows' : 0 - } - - self.error = "" - - # Parse the output of the test, line by line (each line matches another RegEx and as such - # different rules apply - for line in self.lines: - match = re.match(".*/var/run/.rte_config.*", line) - if match: - stop_read = True - continue - - #Total-Tx : 462.42 Mbps Nat_time_out : 0 ==> we try to parse the next decimal in this case Nat_time_out -# match = re.match("\W*(\w(\w|[-])+)\W*([:]|[=])\W*(\d+[.]\d+)\W*\w+\W+(\w+)\W*([:]|[=])\W*(\d+)(.*)", line); -# if match: -# key = misc_methods.mix_string(match.group(5)) -# val = float(match.group(7)) -# # continue to parse !! we try the second -# self.result[key] = val #update latest - - # check if we need to stop reading - match = re.match(".*latency daemon has stopped.*", line) - if match: - stop_read = True - continue - - match = re.match("\W*(\w(\w|[-])+)\W*([:]|[=])\W*(\d+[.]\d+)(.*ps)\s+(\w+)\W*([:]|[=])\W*(\d+)", line) - if match: - key = misc_methods.mix_string(match.group(1)) - val = float(match.group(4)) - if key in d: - if stop_read == False: - self.update (key, val, match.group(5)) - else: - self.result[key] = val # update latest - key2 = misc_methods.mix_string(match.group(6)) - val2 = int(match.group(8)) - self.result[key2] = val2 # always take latest - - - match = re.match("\W*(\w(\w|[-])+)\W*([:]|[=])\W*(\d+[.]\d+)(.*)", line) - if match: - key = misc_methods.mix_string(match.group(1)) - val = float(match.group(4)) - if key in d: - if stop_read == False: - self.update (key, val, match.group(5)) - else: - self.result[key] = val # update latest - continue - - match = re.match("\W*(\w(\w|[-])+)\W*([:]|[=])\W*(\d+)(.*)", line) - if match: - key = misc_methods.mix_string(match.group(1)) - val = float(match.group(4)) - self.result[key] = val #update latest - continue - - match = re.match("\W*(\w(\w|[-])+)\W*([:]|[=])\W*(OK)(.*)", line) - if match: - key = misc_methods.mix_string(match.group(1)) - val = 0 # valid - self.result[key] = val #update latest - continue - - match = re.match("\W*(Cpu Utilization)\W*([:]|[=])\W*(\d+[.]\d+) %(.*)", line) - if match: - key = misc_methods.mix_string(match.group(1)) - val = float(match.group(3)) - if key in self.result: - if (self.result[key] < val): # update only if larger than previous value - self.result[key] = val - else: - self.result[key] = val - continue - - match = re.match(".*(rx_check\s.*)\s+:\s+(\w+)", line) - if match: - key = misc_methods.mix_string(match.group(1)) - try: - val = int(match.group(2)) - except ValueError: # corresponds with rx_check validation case - val = match.group(2) - finally: - self.result[key] = val - continue - - - def get_status (self, drop_expected = False): - if (self.error != ""): - print(self.error) - return (self.STATUS_ERR_FATAL) - - d = self.result - - # test for latency - latency_limit = 5000 - if ( d['maximum-latency'] > latency_limit ): - self.reason="Abnormal latency measured (higher than %s" % latency_limit - return self.STATUS_ERR_LATENCY - - # test for drops - if drop_expected == False: - if ( d['total-pkt-drop'] > 0 ): - self.reason=" At least one packet dropped " - return self.STATUS_ERR_DROP - - # test for rx/tx distance - rcv_vs_tx = d['total-tx']/d['total-rx'] - if ( (rcv_vs_tx >1.2) or (rcv_vs_tx <0.9) ): - self.reason="rx and tx should be close" - return self.STATUS_ERR_RX_TX_DISTANCE - - # expected measurement - expect_vs_measued=d['total-tx']/d['expected-bps'] - if ( (expect_vs_measued >1.1) or (expect_vs_measued < 0.9) ) : - print(expect_vs_measued) - print(d['total-tx']) - print(d['expected-bps']) - self.reason="measure is not as expected" - return self.STATUS_ERR_BAD_EXPECTED_MEASUREMENT - - if ( d['latency-any-error'] !=0 ): - self.reason=" latency-any-error has error" - return self.STATUS_ERR_LATENCY_ANY_ERROR - - return self.STATUS_OK - - # return types - STATUS_OK = 0 - STATUS_ERR_FATAL = 1 - STATUS_ERR_LATENCY = 2 - STATUS_ERR_DROP = 3 - STATUS_ERR_RX_TX_DISTANCE = 4 - STATUS_ERR_BAD_EXPECTED_MEASUREMENT = 5, - STATUS_ERR_LATENCY_ANY_ERROR = 6 - -def test_TRex_result_parser(): - t=CTRexResult('trex.txt'); - t.load_file_lines() - t.parse() - print(t.result) - - - - -if __name__ == "__main__": - #test_TRex_result_parser(); - pass diff --git a/scripts/automation/regression/trex_unit_test.py b/scripts/automation/regression/trex_unit_test.py index 39984c7d..2a544711 100755 --- a/scripts/automation/regression/trex_unit_test.py +++ b/scripts/automation/regression/trex_unit_test.py @@ -399,16 +399,19 @@ class CTRexTestConfiguringPlugin(Plugin): if not CTRexScenario.trex.check_master_connectivity(): fatal('Could not connect to master daemon') if options.ga and CTRexScenario.setup_name: - CTRexScenario.GAManager = GAmanager_Regression(GoogleID = 'UA-75220362-3', - AnalyticsUserID = CTRexScenario.setup_name, - QueueSize = 100, - Timeout = 3, # seconds - UserPermission = 1, - BlockingMode = 0, - appName = 'TRex', - appVer = CTRexScenario.trex_version) - - CTRexScenario.elk = trex_elk.TRexEs('sceasr-b20',9200); + CTRexScenario.GAManager = GAmanager_Regression( + GoogleID = CTRexScenario.global_cfg['google']['id'], + AnalyticsUserID = CTRexScenario.setup_name, + QueueSize = CTRexScenario.global_cfg['google']['queue_size'], + Timeout = CTRexScenario.global_cfg['google']['timeout'], # seconds + UserPermission = 1, + BlockingMode = CTRexScenario.global_cfg['google']['blocking'], + appName = 'TRex', + appVer = CTRexScenario.trex_version) + + CTRexScenario.elk = trex_elk.TRexEs( + CTRexScenario.global_cfg['elk']['server'], + CTRexScenario.global_cfg['elk']['port']); self.set_cont_elk_info () def set_cont_elk_info (self): |