scripts: Initial work for the tos/latency script.

And fixes to lf_firemod for endp creation.
This commit is contained in:
Ben Greear
2020-03-10 13:32:16 -07:00
parent 0a48263e6b
commit 8505273a2e
3 changed files with 522 additions and 19 deletions

View File

@@ -154,10 +154,11 @@ sub normalize_bucket {
}
else {
my @bkts = split(/\s+/, $bks);
@bkts = (@bkts, "0");
my $i;
my $rv = "$min $max $avg ";
#print "bkts len: " . @bkts . "\n";
my @nbkts = (0) x (@bkts + 1);
my @nbkts = (0) x (@bkts);
for ($i = 0; $i<@bkts; $i++) {
# Figure out the bkt range
my $minv = 0;
@@ -177,6 +178,10 @@ sub normalize_bucket {
if ($maxv < (2 ** $z)) {
#print "maxv: $maxv z: $z 2^$z: " . 2 ** $z . + "\n";
$idx = $z;
# Everything else falls in the last bucket
if ($idx >= @bkts) {
$idx = (@bkts - 1);
}
last;
}
}
@@ -188,7 +193,7 @@ sub normalize_bucket {
@nbkts[$idx] = $nv;
}
for ($i = 0; $i<@bkts; $i++) {
for ($i = 0; $i < @nbkts; $i++) {
$rv .= ($nbkts[$i] . " ");
}
return $rv;

View File

@@ -72,7 +72,7 @@ our $fail_msg = "";
our $manual_check = 0;
our @known_endp_types = qw(generic lf_tcp lf_tcp6 lf_udp lf_udp6 mc_udp mc_udp6);
our @known_tos = qw(DONT-SET LOWCOST LOWDELAY RELIABILITY THROUGHPUT);
our @known_tos = qw(DONT-SET LOWCOST LOWDELAY RELIABILITY THROUGHPUT BK BE VI VO);
########################################################################
# Nothing to configure below here, most likely.
@@ -241,6 +241,20 @@ if ($show_help) {
exit 0;
}
# Convert some TOS values that the server likely doesn't understand.
if ($tos eq "BK") {
$tos = 64;
}
elsif ($tos eq "BE") {
$tos = 96;
}
elsif ($tos eq "VI") {
$tos = 128;
}
elsif ($tos eq "VO") {
$tos = 192;
}
if (defined $ENV{DEBUG}) {
use Data::Dumper;
}
@@ -388,7 +402,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- #
## special cases #
## ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- #
if ($match =~ /Latency/) {
if ($end_val =~ /Latency/) {
if ($match =~ /.*Latency:\s+(.*)\s+#/) {
my $val = $1;
#print "val -:$val:-\n";
@@ -397,7 +411,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
$option_map{"Latency-Normalized"} = $::utils->normalize_bucket($val);
}
}
elsif ($match =~ /Pkt-Gaps/) {
elsif ($end_val =~ /Pkt-Gaps/) {
if ($match =~ /.*Pkt-Gaps:\s+(.*)\s+#/) {
my $val = $1;
$option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17);
@@ -405,7 +419,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
$option_map{"Pkt-Gaps-Normalized"} = $::utils->normalize_bucket($val);
}
}
elsif ($match =~ /RX-Silence/) {
elsif ($end_val =~ /RX-Silence/) {
if ($match =~ /.*RX-Silence:\s+(.*)\s+#/) {
my $val = $1;
$option_map{"Normalized-Hdr"} = $::utils->normalize_bucket_hdr(17);
@@ -413,7 +427,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
$option_map{"RX-Silence-Normalized"} = $::utils->normalize_bucket($val);
}
}
elsif ($match =~ /Cx Detected/) {
elsif ($end_val =~ /Cx Detected/) {
my $value = 0;
#print "# case 2\n";
($option) = ($match =~ /(Cx Detected)/);
@@ -424,8 +438,8 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
last;
}
}
elsif (($match =~ /Tx (Bytes|Pkts)/ || $match =~ /tx_(bps|pps)/) ||
( $match =~ /Rx (Bytes|Pkts)/ || $end_val =~ /rx_(bps|pps)/)) {
elsif (($match =~ /Tx (Bytes|Pkts)/ && (($end_val =~ /tx_(bps|pps)/) || ($end_val =~ /Tx (Bytes|Pkts)/) || ($end_val =~ /(Pkts|Bytes) Sent/))) ||
($match =~ /Rx (Bytes|Pkts)/ && (($end_val =~ /rx_(bps|pps)/) || ($end_val =~ /Rx (Bytes|Pkts)/)|| ($end_val =~ /(Pkts|Bytes) Rcvd/)))) {
my $value = 0;
($option) = ($match =~ /([TR]x (Bytes|Pkts))/);
#print "# case 3, Option: $option" . NL;
@@ -553,7 +567,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
$::utils->doCmd($cmd);
}
elsif ($::action eq "create_endp") {
create_endpoint();
create_endp($::endp_name, $::resource, $::port_name, $::endp_type, $::speed, $::max_speed);
}
else {
# Set endp
@@ -756,12 +770,18 @@ sub create_endp {
die("Must choose endpoint protocol type: --endp_type\n$::usage")
if (! defined $::endp_type|| $::endp_type eq "");
$my_endp_type = "lf_tcp" if ($my_endp_type eq "tcp");
$my_endp_type = "lf_udp" if ($my_endp_type eq "udp");
if ($my_endp_type eq "tcp") {
$my_endp_type = "lf_tcp";
}
if ($my_endp_type eq "udp") {
$my_endp_type = "lf_udp";
}
if ($my_endp_type ne "NA") {
die("Endpoint protocol type --endp_type must be among "
.join(', ', @::known_endp_types)."\n".$::usage)
if (! grep {$_ eq $my_endp_type } @::known_endp_types);
}
if ($my_endp_type eq "generic") {
if ($::endp_cmd eq "") {
@@ -809,7 +829,7 @@ sub create_endp {
$cmd = "set_endp_report_timer $::endp_name $::report_timer";
$::utils->doCmd($cmd);
}
elsif (grep { $_ eq $my_endp_type} split(/,/, "lf_udp,lf_tcp,lf_udp6,lf_tcp6")) {
elsif (grep { $_ eq $my_endp_type} split(/,/, "lf_udp,lf_tcp,lf_udp6,lf_tcp6,NA")) {
if ($::use_ports_str ne "NA") {
($::port_name,) = split(',', $::use_ports_str);
}
@@ -851,7 +871,10 @@ sub create_endp {
if ($::tos ne "") {
my($service, $priority) = split(',', $::tos);
$::utils->doCmd($::utils->fmt_cmd("set_endp_tos", $my_endp_name, $service, $priority));
if (!$priority) {
$priority = "NA";
}
$::utils->doCmd("set_endp_tos $my_endp_name $service $priority");
}
}
else {

475
lf_tos_test.py Executable file
View File

@@ -0,0 +1,475 @@
#!/usr/bin/python3
'''
Create connections with different QoS, run them, and report the latency
and other throughput values.
make sure pexpect is installed:
$ sudo yum install python3-pexpect
$ sudo yum install python3-xlsxwriter
You might need to install pexpect-serial using pip:
$ pip3 install pexpect-serial
$ pip3 install XlsxWriter
The user is responsible for setting up the stations oustide of this script, however.
When specifying ports, if the port starts with [Number]., like 1.eth1, then the 1 specifies
the resource ID.
./lf_tos_test.py -d 192.168.100.112 --lfmgr 192.168.100.178 \
--station "1.wlan0 1.wlan1" --tos "BK BE VI VO" --proto udp \
--speed_mbps 1000 --upstream_port 1.eth2 --duration_min 5
'''
# TODO: Maybe HTML output too?
# TODO: Allow selecting tabs or commas for output files
import sys
if sys.version_info[0] != 3:
print("This script requires Python 3")
exit()
import re
import logging
import time
from time import sleep
import pprint
import argparse
import subprocess
import xlsxwriter
NL = "\n"
CR = "\r\n"
Q = '"'
A = "'"
FORMAT = '%(asctime)s %(name)s %(levelname)s: %(message)s'
lfmgr = "127.0.0.1"
lfstation = "1.wlan0"
outfile = "tos_results.xlsx"
upstream_port = "1.eth1"
speed = 1000000000
proto = "udp"
dur = 5 * 60
tos = "BK";
# rssi_adjust = (current_nf - nf_at_calibration)
def usage():
print("$0 ")
print("--outfile: Write results here.")
print("--station: LANforge station names (1.wlan0 1.wlan1 ...)")
print("--upstream_port: LANforge upstream port name (1.eth1)")
print("--lfmgr: LANforge manager IP address")
print("--tos: IP Type of Service: BK BE VI VO")
print("--speed_mbps: Total requested transmit speed, in Mbps")
print("--duration: Duration to run traffic, in minutes")
print("--proto: List of protocols (udp, tcp)")
print("-h|--help")
def main():
global lfmgr
global lfstation
global outfile
global upstream_port
global speed
global proto;
global dur;
global tos;
parser = argparse.ArgumentParser(description="ToS report Script")
parser.add_argument("--upstream_port", type=str, help="LANforge upsteram-port to use (1.eth1, etc)")
parser.add_argument("--station", type=str, help="LANforge stations to use (1.wlan0 1.wlan1 etc)")
parser.add_argument("--lfmgr", type=str, help="LANforge Manager IP address")
parser.add_argument("--outfile", type=str, help="Output file for csv data")
parser.add_argument("--tos", type=str, help="IP Type of Service: BK BE VI VO")
parser.add_argument("--speed_mbps", type=int, help="Total requested transmit speed, in Mbps")
parser.add_argument("--duration", type=float, help="Duration to run traffic, in minutes")
parser.add_argument("--proto", type=str, help="List of protocols (udp tcp)")
args = None
try:
args = parser.parse_args()
if (args.station != None):
lfstation = args.station
if (args.upstream_port != None):
upstream_port = args.upstream_port
if (args.lfmgr != None):
lfmgr = args.lfmgr
if (args.tos != None):
tos = args.tos
if (args.proto != None):
proto = args.proto
if (args.speed_mbps != None):
speed = args.speed_mbps * 1000000
if (args.duration != None):
dur = args.duration * 60
if (args.outfile != None):
outfile = args.outfile
filehandler = None
except Exception as e:
logging.exception(e);
usage()
exit(2);
# XLSX file
workbook = xlsxwriter.Workbook(outfile)
worksheet = workbook.add_worksheet()
bold = workbook.add_format({'bold': True, 'align': 'center'})
dblue_bold = workbook.add_format({'bold': True, 'align': 'center'})
dblue_bold.set_bg_color("#b8cbe4")
dblue_bold.set_border(1)
dtan_bold = workbook.add_format({'bold': True, 'align': 'center'})
dtan_bold.set_bg_color("#dcd8c3")
dtan_bold.set_border(1)
dpeach_bold = workbook.add_format({'bold': True, 'align': 'center'})
dpeach_bold.set_bg_color("#ffd8bb")
dpeach_bold.set_border(1)
dpink_bold = workbook.add_format({'bold': True, 'align': 'center'})
dpink_bold.set_bg_color("#fcc8ca")
dpink_bold.set_border(1)
dyel_bold = workbook.add_format({'bold': True, 'align': 'center'})
dyel_bold.set_bg_color("#ffe699")
dyel_bold.set_border(1)
dgreen_bold = workbook.add_format({'bold': True, 'align': 'center'})
dgreen_bold.set_bg_color("#c6e0b4")
dgreen_bold.set_border(1)
dgreen_bold_left = workbook.add_format({'bold': True, 'align': 'left'})
dgreen_bold_left.set_bg_color("#c6e0b4")
dgreen_bold_left.set_border(1)
center = workbook.add_format({'align': 'center'})
center_blue = workbook.add_format({'align': 'center'})
center_blue.set_bg_color("#dbe5f1")
center_blue.set_border(1)
center_tan = workbook.add_format({'align': 'center'})
center_tan.set_bg_color("#edede1")
center_tan.set_border(1)
center_peach = workbook.add_format({'align': 'center'})
center_peach.set_bg_color("#fce4d6")
center_peach.set_border(1)
center_yel = workbook.add_format({'align': 'center'})
center_yel.set_bg_color("#fdf2cc")
center_yel.set_border(1)
center_yel_red = workbook.add_format({'align': 'center', 'color': 'red'})
center_yel_red.set_bg_color("#fdf2cc")
center_yel_red.set_border(1)
center_pink = workbook.add_format({'align': 'center'})
center_pink.set_bg_color("ffd2d3")
center_pink.set_border(1)
red = workbook.add_format({'color': 'red', 'align': 'center'})
red.set_bg_color("#e0efda")
red.set_border(1)
red_left = workbook.add_format({'color': 'red', 'align': 'left'})
red_left.set_bg_color("#e0efda")
red_left.set_border(1)
green = workbook.add_format({'color': 'green', 'align': 'center'})
green.set_bg_color("#e0efda")
green.set_border(1)
green_left = workbook.add_format({'color': 'green', 'align': 'left'})
green_left.set_bg_color("#e0efda")
green_left.set_border(1)
worksheet.set_row(0, 45) # Set height
worksheet.set_column(0, 0, 10) # Set width
bucket_hdrs = "0-0 1-1 2-3 4-7 8-15 16-31 32-63 64-127 128-255 256-511 512-1023 1024-2047 2048-4095 4096-8191 8192-16383 16384-32767 32768-65535".split()
col = 0
row = 0
worksheet.write(row, col, 'CX-Name', dblue_bold); col += 1
worksheet.write(row, col, 'Station', dblue_bold); col += 1
worksheet.write(row, col, 'Protocol', dblue_bold); col += 1
worksheet.write(row, col, 'ToS', dblue_bold); col += 1
worksheet.write(row, col, 'AP BSSID', dblue_bold); col += 1
worksheet.write(row, col, 'Bandwidth', dblue_bold); col += 1
worksheet.write(row, col, 'Mode', dblue_bold); col += 1
worksheet.write(row, col, 'Last MCS\nRx', dblue_bold); col += 1
worksheet.write(row, col, 'Combined\nRSSI', dpeach_bold); col += 1
worksheet.write(row, col, 'Endpoint\nOffered\nLoad', dblue_bold); col += 1
worksheet.write(row, col, 'Endpoint\n\Rx\nThroughput', dblue_bold); col += 1
worksheet.write(row, col, 'Cx\nOffered\nLoad', dblue_bold); col += 1
worksheet.write(row, col, 'Cx\n\Rx\nThroughput', dblue_bold); col += 1
worksheet.write(row, col, 'Avg\nLatency', dblue_bold); col += 1
worksheet.write(row, col, 'Min\nLatency', dblue_bold); col += 1
worksheet.write(row, col, 'Max\nLatency', dblue_bold); col += 1
for i in range(17):
btitle = "Latency\nRange\n%s"%(bucket_hdrs[i])
worksheet.write(row, col, btitle, dblue_bold); col += 1
worksheet.write(row, col, 'Warnings and Errors', dgreen_bold_left); col += 1
row += 1
# Use subprocess.check_output("Cmd") to utilize existing LF scripts.
lfstations = lfstation.split()
toss = tos.split()
protos = proto.split()
u_name = upstream_port
u_resource = 1
if (upstream_port[0].isdigit()):
tmpa = upstream_port.split(".", 1)
u_resource = tmpa[0]
u_name = tmpa[1]
mcount = len(lfstations) * len(toss) * len(protos);
cx_speed = int(speed / mcount);
opposite_speed = 56000
count = 0
cxnames = []
for sta in lfstations:
e_tot = ""
sta_resource=1
sta_name = sta;
if sta[0].isdigit():
tmpa = sta.split(".", 1);
sta_resource = tmpa[0];
sta_name = tmpa[1];
# Up station
subprocess.run(["./lf_portmod.pl", "--manager", lfmgr, "--card", sta_resource, "--port_name", sta_name,
"--set_ifstate", "up"]);
i = 0
wait_ip_print = False;
wait_assoc_print = False;
# Wait untill LANforge station connects
while True:
port_stats = subprocess.run(["./lf_portmod.pl", "--manager", lfmgr, "--card", sta_resource, "--port_name", sta_name,
"--show_port", "AP,IP,Mode,NSS,Bandwidth,Channel,Signal,Noise,Status,RX-Rate"], capture_output=True);
pss = port_stats.stdout.decode('utf-8', 'ignore');
_status = None
_ip = None
for line in pss.splitlines():
m = re.search('Status:\s+(.*)', line)
if (m != None):
_status = m.group(1)
m = re.search('IP:\s+(.*)', line)
if (m != None):
_ip = m.group(1)
#print("IP %s Status %s"%(_ip, _status))
if (_status == "Authorized"):
if ((_ip != None) and (_ip != "0.0.0.0")):
print("Station is associated with IP address.")
break
else:
if (not wait_ip_print):
print("Waiting for station %s.%s to get IP Address."%(sta_resource, sta_name))
wait_ip_print = True
else:
if (not wait_assoc_print):
print("Waiting up to 180s for station %s.%s to associate."%(sta_resource, sta_name))
wait_assoc_print = True
i += 1
# We wait a fairly long time since AP will take a long time to start on a CAC channel.
if (i > 180):
err = "ERROR: Station did not connect within 180 seconds."
print(err)
e_tot += err
e_tot += " "
if (args.wait_forever):
print("Will continue waiting, you may wish to debug the system...")
i = 0
else:
break
time.sleep(1)
for p in protos:
for t in toss:
e_tot2 = e_tot
# Create connections.
# First, delete any old ones
cxn = "scr-tos-%i"%count
ena = "scr-tos-%i-A"%count
enb = "scr-tos-%i-B"%count
cxnames.append(cxn)
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "do_cmd",
"--cmd", "rm_cx ALL %s"%cxn], capture_output=True);
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "do_cmd",
"--cmd", "rm_endp %s"%ena], capture_output=True);
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "do_cmd",
"--cmd", "rm_endp %s"%enb], capture_output=True);
cx_proto = p;
if (cx_proto == "udp"):
cx_proto = "lf_udp"
if (cx_proto == "tcp"):
cx_proto = "lf_tcp"
# Now, create the new connection
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--resource", "%s"%sta_resource, "--action", "create_endp", "--port_name", sta_name,
"--endp_type", cx_proto, "--endp_name", ena, "--speed", "%s"%opposite_speed, "--report_timer", "1000", "--tos", t])#, capture_output=True);
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--resource", "%s"%u_resource, "--action", "create_endp", "--port_name", u_name,
"--endp_type", cx_proto, "--endp_name", enb, "--speed", "%s"%cx_speed, "--report_timer", "1000", "--tos", t])# capture_output=True);
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "do_cmd", "--cmd",
"add_cx %s default_tm %s %s"%(cxn, ena, enb)])# capture_output=True);
# Start traffic
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--action", "do_cmd",
"--cmd", "set_cx_state all %s RUNNING"%cxn], capture_output=True);
count = count + 1
# Traffic is started, wait requested amount of time
print("Waiting %s seconds to let traffic run for a bit"%(dur))
time.sleep(dur)
# Gather probe results and record data, verify NSS, BW, Channel
count = 0
for sta in lfstations:
sta_resource=1
sta_name = sta;
if sta[0].isdigit():
tmpa = sta.split(".", 1);
sta_resource = tmpa[0];
sta_name = tmpa[1];
port_stats = subprocess.run(["./lf_portmod.pl", "--manager", lfmgr, "--card", sta_resource, "--port_name", sta_name,
"--show_port", "AP,Mode,Bandwidth,Signal,Status,RX-Rate"], capture_output=True);
pss = port_stats.stdout.decode('utf-8', 'ignore');
_ap = None
_bw = None
_mode = None
_rxrate = None
_signal = None
for line in pss.splitlines():
m = re.search('AP:\s+(.*)', line)
if (m != None):
_ap = m.group(1)
m = re.search('Bandwidth:\s+(.*)Mhz', line)
if (m != None):
_bw = m.group(1)
m = re.search('Mode:\s+(.*)', line)
if (m != None):
_mode = m.group(1)
m = re.search('RX-Rate:\s+(.*)', line)
if (m != None):
_rxrate = m.group(1)
m = re.search('Signal:\s+(.*)', line)
if (m != None):
_signal = m.group(1)
for p in protos:
for t in toss:
cxn = cxnames[count]
# Results: tx_bytes, rx_bytes, tx_bps, rx_bps, tx_pkts, rx_pkts, Latency
resultsA = ["0"] * 7
resultsB = ["0"] * 7
ena = "%s-A"%cxn;
enb = "%s-B"%cxn;
enames = [ena, enb]
for ename in enames:
results = [""] * 7
endp_stats = subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--endp_vals", "tx_bps,rx_bps,Tx Bytes,Rx Bytes,Tx Pkts,Rx Pkts,Latency",
"--endp_name", ena], capture_output=True);
pss = endp_stats.stdout.decode('utf-8', 'ignore');
for line in pss.splitlines():
print("probe-line: %s"%(line))
m = re.search('Rx Bytes:\s+(\d+)', line)
if (m != None):
results[1] = int(m.group(1))
if (results[1] == 0):
err = "ERROR: No bytes received by data connection %s, test results may not be valid."%(ename)
e_tot2 += err
e_tot2 += " "
m = re.search('Tx Bytes:\s+(\d+)', line)
if (m != None):
results[0] = int(m.group(1))
if (results[0] == 0):
err = "ERROR: No bytes transmitted by data connection %s, test results may not be valid."%(ename)
e_tot2 += err
e_tot2 += " "
m = re.search('tx_bps:\s+(.*)', line)
if (m != None):
results[2] = m.group(1)
m = re.search('rx_bps:\s+(.*)', line)
if (m != None):
results[3] = m.group(1)
m = re.search('Tx Pkts:\s+(.*)', line)
if (m != None):
results[4] = m.group(1)
m = re.search('Rx Pkts:\s+(.*)', line)
if (m != None):
results[5] = m.group(1)
m = re.search('Latency-Normalized:\s+(.*)', line)
if (m != None):
results[6] = m.group(1)
if (ena == ename):
resultsA = results.copy()
else:
resultsB = results.copy()
for ename in enames:
col = 0
if (ena == ename):
results = resultsA
else:
results = resultsB
lat_cols = results[6].split() # min, max, avg, columns....
worksheet.write(row, col, cxn, center_blue); col += 1
worksheet.write(row, col, ename, center_blue); col += 1
worksheet.write(row, col, "%s.%s"%(sta_resource, sta_name), center_blue); col += 1
worksheet.write(row, col, proto, center_blue); col += 1
worksheet.write(row, col, tos, center_blue); col += 1
worksheet.write(row, col, _ap, center_blue); col += 1
worksheet.write(row, col, _bw, center_blue); col += 1
worksheet.write(row, col, _mode, center_blue); col += 1
worksheet.write(row, col, _rxrate, center_blue); col += 1
worksheet.write(row, col, _signal, center_blue); col += 1
worksheet.write(row, col, results[2], center_blue); col += 1
worksheet.write(row, col, results[3], center_tan); col += 1
worksheet.write(row, col, "%s"%(int(resultsA[2]) + int(resultsB[2])), center_blue); col += 1
worksheet.write(row, col, "%s"%(int(resultsA[3]) + int(resultsB[3])), center_tan); col += 1
worksheet.write(row, col, lat_cols[2], center_tan); col += 1
worksheet.write(row, col, lat_cols[0], center_tan); col += 1
worksheet.write(row, col, lat_cols[1], center_tan); col += 1
for x in range(17):
worksheet.write(row, col, lat_cols[x + 3], center_peach); col += 1
if (e_tot2 == ""):
worksheet.write(row, col, e_tot2, green_left); col += 1
else:
worksheet.write(row, col, e_tot2, red_left); col += 1
row += 1
# Stop traffic
subprocess.run(["./lf_firemod.pl", "--manager", lfmgr, "--resource",
"--cmd", "set_cx_state all %s STOPPED"%cxn], capture_output=True);
workbook.close()
# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
if __name__ == '__main__':
main()
print("Xlsx results stored in %s"%(outfile))
####
####
####