mirror of
				https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
				synced 2025-10-31 02:38:03 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master'
This commit is contained in:
		| @@ -18,11 +18,13 @@ import time | |||||||
| import datetime | import datetime | ||||||
| import subprocess | import subprocess | ||||||
| import re | import re | ||||||
|  | import csv | ||||||
|  | #import operator | ||||||
|  | #import pandas as pd | ||||||
|  |  | ||||||
| class L3VariableTimeLongevity(LFCliBase): | class L3VariableTimeLongevity(LFCliBase): | ||||||
|     def __init__(self, host, port, endp_types, args, tos, side_b, radios, radio_name_list, number_of_stations_per_radio_list, |     def __init__(self, host, port, endp_types, args, tos, side_b, radios, radio_name_list, number_of_stations_per_radio_list, | ||||||
|                  ssid_list, ssid_password_list, ssid_security_list, station_lists, name_prefix, debug_on, |                  ssid_list, ssid_password_list, ssid_security_list, station_lists, name_prefix, debug_on, outfile, | ||||||
|                  side_a_min_rate=56000, side_a_max_rate=0, |                  side_a_min_rate=56000, side_a_max_rate=0, | ||||||
|                  side_b_min_rate=56000, side_b_max_rate=0, |                  side_b_min_rate=56000, side_b_max_rate=0, | ||||||
|                  number_template="00", test_duration="256s", |                  number_template="00", test_duration="256s", | ||||||
| @@ -50,6 +52,14 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|         self.multicast_profile.name_prefix = "MLT-"; |         self.multicast_profile.name_prefix = "MLT-"; | ||||||
|         self.station_profiles = [] |         self.station_profiles = [] | ||||||
|         self.args = args |         self.args = args | ||||||
|  |         self.outfile = outfile | ||||||
|  |         self.csv_started = False | ||||||
|  |         self.ts = int(time.time()) | ||||||
|  |  | ||||||
|  |         # Full spread-sheet data | ||||||
|  |         if self.outfile is not None: | ||||||
|  |             self.csv_file = open(self.outfile, "w")  | ||||||
|  |             self.csv_writer = csv.writer(self.csv_file, delimiter=",") | ||||||
|          |          | ||||||
|         index = 0 |         index = 0 | ||||||
|         for radio in radios: |         for radio in radios: | ||||||
| @@ -73,7 +83,8 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|         self.cx_profile.side_b_max_bps = side_b_max_rate |         self.cx_profile.side_b_max_bps = side_b_max_rate | ||||||
|  |  | ||||||
|     def __get_rx_values(self): |     def __get_rx_values(self): | ||||||
|         endp_list = self.json_get("endp?fields=name,rx+bytes", debug_=True) |         endp_list = self.json_get("endp?fields=name,rx+bytes,rx+drop+%25", debug_=True) | ||||||
|  |         endp_rx_drop_map = {} | ||||||
|         endp_rx_map = {} |         endp_rx_map = {} | ||||||
|         our_endps = {} |         our_endps = {} | ||||||
|         for e in self.multicast_profile.get_mc_names(): |         for e in self.multicast_profile.get_mc_names(): | ||||||
| @@ -87,24 +98,115 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|                         for value_name, value_rx in value.items(): |                         for value_name, value_rx in value.items(): | ||||||
|                             if value_name == 'rx bytes': |                             if value_name == 'rx bytes': | ||||||
|                                 endp_rx_map[item] = value_rx |                                 endp_rx_map[item] = value_rx | ||||||
|         return endp_rx_map |                         for value_name, value_rx_drop in value.items(): | ||||||
|  |                             if value_name == 'rx drop %': | ||||||
|  |                                 endp_rx_drop_map[item] = value_rx_drop | ||||||
|  |  | ||||||
|  |         return endp_rx_map, endp_rx_drop_map | ||||||
|  |  | ||||||
|  |     def __record_rx_dropped_percent(self,rx_drop_percent): | ||||||
|  |  | ||||||
|  |         csv_rx_drop_percent_data = [self.ts,'rx_drop_percent'] | ||||||
|  |         csv_performance_values = [] | ||||||
|  |  | ||||||
|  |         # clean up dictionary for only rx values | ||||||
|  |         for key in [key for key in rx_drop_percent if "mtx" in key]: del rx_drop_percent[key] | ||||||
|  |  | ||||||
|  |         filtered_values = [v for _, v in rx_drop_percent.items() if v !=0] | ||||||
|  |         average_rx_drop_percent = sum(filtered_values) / len(filtered_values) if len(filtered_values) != 0 else 0 | ||||||
|  |  | ||||||
|  |         csv_performance_rx_drop_percent_values=sorted(rx_drop_percent.items(), key=lambda x: (x[1],x[0]), reverse=False) | ||||||
|  |         csv_performance_rx_drop_percent_values=self.csv_validate_list(csv_performance_rx_drop_percent_values,5) | ||||||
|  |         for i in range(5): | ||||||
|  |             csv_rx_drop_percent_data.append(str(csv_performance_rx_drop_percent_values[i]).replace(',',';')) | ||||||
|  |         for i in range(-1,-6,-1): | ||||||
|  |             csv_rx_drop_percent_data.append(str(csv_performance_rx_drop_percent_values[i]).replace(',',';')) | ||||||
|  |  | ||||||
|  |         csv_rx_drop_percent_data.append(average_rx_drop_percent) | ||||||
|  |  | ||||||
|  |         for item, value in rx_drop_percent.items(): | ||||||
|  |             print(item, "rx drop percent: ", rx_drop_percent[item]) | ||||||
|  |             csv_rx_drop_percent_data.append(rx_drop_percent[item]) | ||||||
|  |  | ||||||
|  |         self.csv_add_row(csv_rx_drop_percent_data,self.csv_writer,self.csv_file) | ||||||
|  |  | ||||||
|     def __compare_vals(self, old_list, new_list): |     def __compare_vals(self, old_list, new_list): | ||||||
|         passes = 0 |         passes = 0 | ||||||
|         expected_passes = 0 |         expected_passes = 0 | ||||||
|  |         csv_performance_values = [] | ||||||
|  |         csv_rx_headers = [] | ||||||
|  |         csv_rx_delta_dict = {} | ||||||
|  |  | ||||||
|  |         # this may need to be a list as more monitoring takes place. | ||||||
|  |         csv_rx_row_data = [self.ts,'rx'] | ||||||
|  |         csv_rx_delta_row_data = [self.ts,'rx_delta'] | ||||||
|  |  | ||||||
|  |         for key in [key for key in old_list if "mtx" in key]: del old_list[key] | ||||||
|  |         for key in [key for key in new_list if "mtx" in key]: del new_list[key] | ||||||
|  |  | ||||||
|  |         print("rx (ts:{}): calculating worst, best, average".format(self.ts)) | ||||||
|  |         filtered_values = [v for _, v in new_list.items() if v !=0] | ||||||
|  |         average_rx= sum(filtered_values) / len(filtered_values) if len(filtered_values) != 0 else 0 | ||||||
|  |  | ||||||
|  |         csv_performance_values=sorted(new_list.items(), key=lambda x: (x[1],x[0]), reverse=False) | ||||||
|  |         csv_performance_values=self.csv_validate_list(csv_performance_values,5) | ||||||
|  |         for i in range(5): | ||||||
|  |             csv_rx_row_data.append(str(csv_performance_values[i]).replace(',',';')) | ||||||
|  |         for i in range(-1,-6,-1): | ||||||
|  |             csv_rx_row_data.append(str(csv_performance_values[i]).replace(',',';')) | ||||||
|  |  | ||||||
|  |         csv_rx_row_data.append(average_rx) | ||||||
|  |         #print("rx (ts:{}): worst, best, average {}".format(self.ts,csv_rx_row_data)) | ||||||
|  |  | ||||||
|         if len(old_list) == len(new_list): |         if len(old_list) == len(new_list): | ||||||
|  |             print("rx_delta (ts:{}): calculating worst, best, average".format(self.ts)) | ||||||
|             for item, value in old_list.items(): |             for item, value in old_list.items(): | ||||||
|                 expected_passes +=1 |                 expected_passes +=1 | ||||||
|                 if item.startswith("mtx"): |                 if new_list[item] > old_list[item]: | ||||||
|                     # We ignore the mcast transmitter. |  | ||||||
|                     # This is a hack based on naming and could be improved. |  | ||||||
|                     passes += 1 |                     passes += 1 | ||||||
|  |                     print(item, new_list[item], old_list[item], " Difference: ", new_list[item] - old_list[item]) | ||||||
|                 else: |                 else: | ||||||
|                     if new_list[item] > old_list[item]: |                     print("Failed to increase rx data: ", item, new_list[item], old_list[item]) | ||||||
|                         passes += 1 |                 if not self.csv_started: | ||||||
|                         print(item, new_list[item], old_list[item], " Difference: ", new_list[item] - old_list[item]) |                     csv_rx_headers.append(item) | ||||||
|                     else: |                 csv_rx_delta_dict.update({item:(new_list[item] - old_list[item])}) | ||||||
|                         print("Failed to increase rx data: ", item, new_list[item], old_list[item]) |                  | ||||||
|  |  | ||||||
|  |             if not self.csv_started: | ||||||
|  |                 csv_header = self.csv_generate_column_headers() | ||||||
|  |                 csv_header += csv_rx_headers | ||||||
|  |                 print(csv_header) | ||||||
|  |                 self.csv_add_column_headers(csv_header) | ||||||
|  |                 self.csv_started = True | ||||||
|  |  | ||||||
|  |             # need to generate list first to determine worst and best | ||||||
|  |             filtered_values = [v for _, v in csv_rx_delta_dict.items() if v !=0] | ||||||
|  |             average_rx_delta= sum(filtered_values) / len(filtered_values) if len(filtered_values) != 0 else 0 | ||||||
|  |  | ||||||
|  |             csv_performance_delta_values=sorted(csv_rx_delta_dict.items(), key=lambda x: (x[1],x[0]), reverse=False) | ||||||
|  |             csv_performance_delta_values=self.csv_validate_list(csv_performance_delta_values,5) | ||||||
|  |             for i in range(5): | ||||||
|  |                 csv_rx_delta_row_data.append(str(csv_performance_delta_values[i]).replace(',',';')) | ||||||
|  |             for i in range(-1,-6,-1): | ||||||
|  |                 csv_rx_delta_row_data.append(str(csv_performance_delta_values[i]).replace(',',';')) | ||||||
|  |  | ||||||
|  |             csv_rx_delta_row_data.append(average_rx_delta) | ||||||
|  |             #print("rx_delta (ts:{}): worst, best, average {}".format(self.ts,csv_rx_delta_row_data)) | ||||||
|  |              | ||||||
|  |             for item, value in old_list.items(): | ||||||
|  |                 expected_passes +=1 | ||||||
|  |                 if new_list[item] > old_list[item]: | ||||||
|  |                     passes += 1 | ||||||
|  |                     print(item, new_list[item], old_list[item], " Difference: ", new_list[item] - old_list[item]) | ||||||
|  |                 else: | ||||||
|  |                     print("Failed to increase rx data: ", item, new_list[item], old_list[item]) | ||||||
|  |                 if not self.csv_started: | ||||||
|  |                     csv_rx_headers.append(item) | ||||||
|  |                 csv_rx_row_data.append(new_list[item]) | ||||||
|  |                 csv_rx_delta_row_data.append(new_list[item] - old_list[item]) | ||||||
|  |  | ||||||
|  |             self.csv_add_row(csv_rx_row_data,self.csv_writer,self.csv_file) | ||||||
|  |             self.csv_add_row(csv_rx_delta_row_data,self.csv_writer,self.csv_file) | ||||||
|  |  | ||||||
|             if passes == expected_passes: |             if passes == expected_passes: | ||||||
|                 return True |                 return True | ||||||
| @@ -113,7 +215,7 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|         else: |         else: | ||||||
|             print("Old-list length: %i  new: %i does not match in compare-vals."%(len(old_list), len(new_list))) |             print("Old-list length: %i  new: %i does not match in compare-vals."%(len(old_list), len(new_list))) | ||||||
|             print("old-list:",old_list) |             print("old-list:",old_list) | ||||||
|             print("new-list:",old_list) |             print("new-list:",new_list) | ||||||
|             return False |             return False | ||||||
|  |  | ||||||
|     def verify_controller(self): |     def verify_controller(self): | ||||||
| @@ -177,7 +279,7 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|  |  | ||||||
|         cur_time = datetime.datetime.now() |         cur_time = datetime.datetime.now() | ||||||
|         print("Getting initial values.") |         print("Getting initial values.") | ||||||
|         old_rx_values = self.__get_rx_values() |         old_rx_values, rx_drop_percent = self.__get_rx_values() | ||||||
|  |  | ||||||
|         end_time = self.local_realm.parse_time(self.test_duration) + cur_time |         end_time = self.local_realm.parse_time(self.test_duration) + cur_time | ||||||
|  |  | ||||||
| @@ -186,20 +288,23 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|         passes = 0 |         passes = 0 | ||||||
|         expected_passes = 0 |         expected_passes = 0 | ||||||
|         while cur_time < end_time: |         while cur_time < end_time: | ||||||
|             interval_time = cur_time + datetime.timedelta(minutes=1) |             interval_time = cur_time + datetime.timedelta(seconds=60) | ||||||
|             while cur_time < interval_time: |             while cur_time < interval_time: | ||||||
|                 cur_time = datetime.datetime.now() |                 cur_time = datetime.datetime.now() | ||||||
|                 time.sleep(1) |                 time.sleep(1) | ||||||
|              |              | ||||||
|             new_rx_values = self.__get_rx_values() |             self.ts = int(time.time()) | ||||||
|  |             new_rx_values, rx_drop_percent = self.__get_rx_values() | ||||||
|  |  | ||||||
|             expected_passes += 1 |             expected_passes += 1 | ||||||
|             if self.__compare_vals(old_rx_values, new_rx_values): |             if self.__compare_vals(old_rx_values, new_rx_values): | ||||||
|                 passes += 1 |                 passes += 1 | ||||||
|             else: |             else: | ||||||
|                 self._fail("FAIL: Not all stations increased traffic", print_fail) |                 self._fail("FAIL: Not all stations increased traffic", print_fail) | ||||||
|                 break |  | ||||||
|             old_rx_values = new_rx_values |             old_rx_values = new_rx_values | ||||||
|  |  | ||||||
|  |             self.__record_rx_dropped_percent(rx_drop_percent) | ||||||
|  |  | ||||||
|             cur_time = datetime.datetime.now() |             cur_time = datetime.datetime.now() | ||||||
|  |  | ||||||
|         if passes == expected_passes: |         if passes == expected_passes: | ||||||
| @@ -212,6 +317,7 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|             for station_name in station_list: |             for station_name in station_list: | ||||||
|                 self.local_realm.admin_down(station_name) |                 self.local_realm.admin_down(station_name) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def pre_cleanup(self): |     def pre_cleanup(self): | ||||||
|         self.cx_profile.cleanup_prefix() |         self.cx_profile.cleanup_prefix() | ||||||
|         self.multicast_profile.cleanup_prefix() |         self.multicast_profile.cleanup_prefix() | ||||||
| @@ -242,16 +348,8 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|             station_profile.cleanup() |             station_profile.cleanup() | ||||||
|                                          |                                          | ||||||
|     def build(self): |     def build(self): | ||||||
|         # This is too fragile and limitted, let outside logic configure the upstream port as needed. |         index = 0 | ||||||
|         #try: |         total_endp = []  | ||||||
|         #    eid = self.local_realm.name_to_eid(self.side_b) |  | ||||||
|         #    data = LFUtils.port_dhcp_up_request(eid[1], eid[2]) |  | ||||||
|         #    self.json_post("/cli-json/set_port", data) |  | ||||||
|         #except: |  | ||||||
|         #    print("LFUtils.port_dhcp_up_request didn't complete ") |  | ||||||
|         #    print("or the json_post failed either way {} did not set up dhcp so test may not pass data ".format(self.side_b)) |  | ||||||
|          |  | ||||||
|         index = 0  |  | ||||||
|         for station_profile in self.station_profiles: |         for station_profile in self.station_profiles: | ||||||
|             station_profile.use_security(station_profile.security, station_profile.ssid, station_profile.ssid_pass) |             station_profile.use_security(station_profile.security, station_profile.ssid, station_profile.ssid_pass) | ||||||
|             station_profile.set_number_template(station_profile.number_template) |             station_profile.set_number_template(station_profile.number_template) | ||||||
| @@ -269,9 +367,35 @@ class L3VariableTimeLongevity(LFCliBase): | |||||||
|                     for _tos in self.tos: |                     for _tos in self.tos: | ||||||
|                         print("Creating connections for endpoint type: %s TOS: %s"%(etype, _tos)) |                         print("Creating connections for endpoint type: %s TOS: %s"%(etype, _tos)) | ||||||
|                         self.cx_profile.create(endp_type=etype, side_a=station_profile.station_names, side_b=self.side_b, sleep_time=0, tos=_tos) |                         self.cx_profile.create(endp_type=etype, side_a=station_profile.station_names, side_b=self.side_b, sleep_time=0, tos=_tos) | ||||||
|  |          | ||||||
|  |          | ||||||
|         self._pass("PASS: Stations build finished") |         self._pass("PASS: Stations build finished") | ||||||
|  |  | ||||||
|  |     def csv_generate_column_headers(self): | ||||||
|  |         csv_rx_headers = ['Time epoch','Monitor'] | ||||||
|  |         for i in range(1,6): | ||||||
|  |             csv_rx_headers.append("least_rx_data {}".format(i)) | ||||||
|  |         for i in range(1,6): | ||||||
|  |             csv_rx_headers.append("most_rx_data_{}".format(i)) | ||||||
|  |         csv_rx_headers.append("average_rx_data") | ||||||
|  |         return csv_rx_headers | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def csv_add_column_headers(self,headers): | ||||||
|  |         if self.csv_file is not None: | ||||||
|  |             self.csv_writer.writerow(headers) | ||||||
|  |             self.csv_file.flush() | ||||||
|  |  | ||||||
|  |     def csv_validate_list(self, csv_list, length): | ||||||
|  |         if len(csv_list) < length: | ||||||
|  |             csv_list = csv_list + [('no data','no data')] * (length - len(csv_list)) | ||||||
|  |         return csv_list | ||||||
|  |  | ||||||
|  |     def csv_add_row(self,row,writer,csv_file): | ||||||
|  |         if self.csv_file is not None: | ||||||
|  |             writer.writerow(row) | ||||||
|  |             csv_file.flush() | ||||||
|  |  | ||||||
| def valid_endp_types(_endp_type): | def valid_endp_types(_endp_type): | ||||||
|     etypes = _endp_type.split() |     etypes = _endp_type.split() | ||||||
|     for endp_type in etypes: |     for endp_type in etypes: | ||||||
| @@ -294,7 +418,7 @@ def main(): | |||||||
|         epilog='''\ |         epilog='''\ | ||||||
|         Useful Information: |         Useful Information: | ||||||
|             1. Polling interval for checking traffic is fixed at 1 minute |             1. Polling interval for checking traffic is fixed at 1 minute | ||||||
|             2. The test will exit when traffic has not changed on a station for 1 minute |             2. The test will generate csv file  | ||||||
|             3. The tx/rx rates are fixed at 256000 bits per second |             3. The tx/rx rates are fixed at 256000 bits per second | ||||||
|             4. Maximum stations per radio is 64 |             4. Maximum stations per radio is 64 | ||||||
|             ''', |             ''', | ||||||
| @@ -364,6 +488,7 @@ Note:   multiple --radio switches may be entered up to the number of radios avai | |||||||
|     parser.add_argument('-t', '--endp_type', help='--endp_type <types of traffic> example --endp_type \"lf_udp lf_tcp mc_udp\"  Default: lf_udp , options: lf_udp, lf_udp6, lf_tcp, lf_tcp6, mc_udp, mc_udp6', |     parser.add_argument('-t', '--endp_type', help='--endp_type <types of traffic> example --endp_type \"lf_udp lf_tcp mc_udp\"  Default: lf_udp , options: lf_udp, lf_udp6, lf_tcp, lf_tcp6, mc_udp, mc_udp6', | ||||||
|                         default='lf_udp', type=valid_endp_types) |                         default='lf_udp', type=valid_endp_types) | ||||||
|     parser.add_argument('-u', '--upstream_port', help='--upstream_port <cross connect upstream_port> example: --upstream_port eth1',default='eth1') |     parser.add_argument('-u', '--upstream_port', help='--upstream_port <cross connect upstream_port> example: --upstream_port eth1',default='eth1') | ||||||
|  |     parser.add_argument('-o','--outfile', help="Output file for csv data", default='longevity_results') | ||||||
|  |  | ||||||
|     requiredNamed = parser.add_argument_group('required arguments') |     requiredNamed = parser.add_argument_group('required arguments') | ||||||
|     requiredNamed.add_argument('-r', '--radio', action='append', nargs=5, metavar=('<wiphyX>', '<number last station>', '<ssid>', '<ssid password>', 'security'), |     requiredNamed.add_argument('-r', '--radio', action='append', nargs=5, metavar=('<wiphyX>', '<number last station>', '<ssid>', '<ssid password>', 'security'), | ||||||
| @@ -386,7 +511,13 @@ Note:   multiple --radio switches may be entered up to the number of radios avai | |||||||
|  |  | ||||||
|     if args.radio: |     if args.radio: | ||||||
|         radios = args.radio |         radios = args.radio | ||||||
|      |  | ||||||
|  |     if args.outfile != None: | ||||||
|  |         current_time = time.strftime("%m_%d_%Y_%H_%M", time.localtime()) | ||||||
|  |         outfile = "{}_{}.csv".format(args.outfile,current_time) | ||||||
|  |         print("csv output file : {}".format(outfile)) | ||||||
|  |          | ||||||
|  |  | ||||||
|     radio_offset = 0 |     radio_offset = 0 | ||||||
|     number_of_stations_offset = 1 |     number_of_stations_offset = 1 | ||||||
|     ssid_offset = 2 |     ssid_offset = 2 | ||||||
| @@ -444,7 +575,7 @@ Note:   multiple --radio switches may be entered up to the number of radios avai | |||||||
|                                    ssid_list=ssid_list, |                                    ssid_list=ssid_list, | ||||||
|                                    ssid_password_list=ssid_password_list, |                                    ssid_password_list=ssid_password_list, | ||||||
|                                    ssid_security_list=ssid_security_list, test_duration=test_duration, |                                    ssid_security_list=ssid_security_list, test_duration=test_duration, | ||||||
|                                    side_a_min_rate=256000, side_b_min_rate=256000, debug_on=debug_on) |                                    side_a_min_rate=256000, side_b_min_rate=256000, debug_on=debug_on, outfile=outfile) | ||||||
|  |  | ||||||
|     ip_var_test.pre_cleanup() |     ip_var_test.pre_cleanup() | ||||||
|  |  | ||||||
| @@ -458,7 +589,7 @@ Note:   multiple --radio switches may be entered up to the number of radios avai | |||||||
|     if not ip_var_test.passes(): |     if not ip_var_test.passes(): | ||||||
|         print("stop test failed") |         print("stop test failed") | ||||||
|         print(ip_var_test.get_fail_message()) |         print(ip_var_test.get_fail_message()) | ||||||
|         exit(1)  |           | ||||||
|  |  | ||||||
|     print("Pausing 30 seconds after run for manual inspection before we clean up.") |     print("Pausing 30 seconds after run for manual inspection before we clean up.") | ||||||
|     time.sleep(30) |     time.sleep(30) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Logan Lipke
					Logan Lipke