firemod: Fix stats gathering bugs, allow reading data from text file.

The stats gathering thing might introduce other bugs, but at least it
seems to work better than before.  The old regex logic was too complex
for me to follow.
This commit is contained in:
Ben Greear
2018-07-18 18:07:41 -07:00
parent 949578dff6
commit 1931e88f9e

View File

@@ -35,7 +35,7 @@ our $endp_name = "";
our $endp_cmd = "";
our $port_name = "";
our $speed = "-1";
our $action = "show_port";
our $action = "";
our $do_cmd = "NA";
our $lfmgr_host = "localhost";
our $lfmgr_port = 4001;
@@ -63,6 +63,7 @@ our $cx_endps = "";
our $list_cx_name = "all";
our $test_mgr = "default_tm";
our $list_test_mgr = "all";
our $stats_from_file = "";
our $fail_msg = "";
our $manual_check = 0;
@@ -86,6 +87,9 @@ our $usage = "$0 --action { list_ports | show_port
# Special Keys:
# --endp_vals tx_bps (Tx Bytes)
# --endp_vals rx_bps (Rx Bytes)
[--stats_from_file [file-name]
# Read 'show-endp' ouput from a file instead of direct query from LANforge.
# This can save a lot of time if we already have the output available.
[--mgr {host-name | IP}]
[--mgr_port {ip port}]
[--cmd {lf-cli-command text}]
@@ -165,9 +169,10 @@ GetOptions
'endp_name|e=s' => \$::endp_name,
'endp_cmd=s' => \$::endp_cmd,
'endp_vals|o=s' => \$::endp_vals,
'stats_from_file=s' => \$::stats_from_file,
'action|a=s' => \$::action,
'cmd|c=s' => \$::do_cmd,
'mgr|m=s' => \$::lfmgr_host,
'manager|mgr|m=s' => \$::lfmgr_host,
'mgr_port|p=i' => \$::lfmgr_port,
'resource|r=i' => \$::resource,
'port_name=s' => \$::port_name,
@@ -223,6 +228,10 @@ if ($::do_cmd ne "NA") {
our @valid_actions = split(/,/, "show_endp,set_endp,start_endp,stop_endp,delete_endp,create_endp,create_arm,"
."show_port,do_cmd,list_ports,list_endp,create_cx,list_cx,show_cx,delete_cx,delete_cxe" );
if (($::action eq "") && ((defined $::endp_vals) && ("$::endp_vals" ne ""))) {
$::action = "show_endp";
}
if (! (grep {$_ eq $::action} @::valid_actions )) {
die("Invalid action: $::action\n$::usage\n");
}
@@ -238,34 +247,38 @@ if ($::quiet eq "1" ) {
}
# Open connection to the LANforge server.
# Wait up to 60 seconds when requesting info from LANforge.
my $t = new Net::Telnet(Prompt => '/default\@btbits\>\>/',
Timeout => 60);
my $t = undef;
$t->open(Host => $::lfmgr_host,
Port => $::lfmgr_port,
Timeout => 10);
if ($stats_from_file eq "") {
# Wait up to 60 seconds when requesting info from LANforge.
$t = new Net::Telnet(Prompt => '/default\@btbits\>\>/',
Timeout => 60);
$t->max_buffer_length(16 * 1024 * 1000); # 16 MB buffer
$t->waitfor("/btbits\>\>/");
$t->open(Host => $::lfmgr_host,
Port => $::lfmgr_port,
Timeout => 10);
# Configure our utils.
our $utils = new LANforge::Utils();
$::utils->telnet($t); # Set our telnet object.
if ($::utils->isQuiet()) {
if (defined $ENV{'LOG_CLI'} && $ENV{'LOG_CLI'} ne "") {
$::utils->cli_send_silent(0);
$t->max_buffer_length(16 * 1024 * 1000); # 16 MB buffer
$t->waitfor("/btbits\>\>/");
# Configure our utils.
our $utils = new LANforge::Utils();
$::utils->telnet($t); # Set our telnet object.
if ($::utils->isQuiet()) {
if (defined $ENV{'LOG_CLI'} && $ENV{'LOG_CLI'} ne "") {
$::utils->cli_send_silent(0);
}
else {
$::utils->cli_send_silent(1); # Do not show input to telnet
}
$::utils->cli_rcv_silent(1); # Repress output from telnet
}
else {
$::utils->cli_send_silent(1); # Do not show input to telnet
$::utils->cli_send_silent(0); # Show input to telnet
$::utils->cli_rcv_silent(0); # Show output from telnet
}
$::utils->cli_rcv_silent(1); # Repress output from telnet
$::utils->log_cli("# $0 ".`date "+%Y-%m-%d %H:%M:%S"`);
}
else {
$::utils->cli_send_silent(0); # Show input to telnet
$::utils->cli_rcv_silent(0); # Show output from telnet
}
$::utils->log_cli("# $0 ".`date "+%Y-%m-%d %H:%M:%S"`);
if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm,list_endp")) {
$::max_speed = $::speed if( $::max_speed eq "-1");
@@ -315,7 +328,14 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
# options are reformatted
my $i;
my @lines = split(NL, $::utils->doAsyncCmd("nc_show_endp $endp_name"));
my @lines = ();
if ($stats_from_file ne "") {
@lines = split(NL, get_stats_from_file($stats_from_file, $endp_name));
}
else {
@lines = split(NL, $::utils->doAsyncCmd("nc_show_endp $endp_name"));
}
for($i=0; $i<@lines; $i++) {
$lines[$i] = $lines[$i]." #";
}
@@ -323,12 +343,12 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
my @parts;
my @matches = grep( /$matcher/, @lines);
my $match;
#print "MATCHER $matcher".NL;
#print "MATCHER $matcher matches:\n" . join("\n", @matches) . NL;
for my $end_val (split(',', $::endp_vals)) {
my $endval_done = 0;
for $match (@matches) {
last if ($endval_done);
#print "\nM: $end_val> $match\n";
#print "\nMatch-line: $end_val> $match\n";
# no value between colon separated tags can be very
# confusing to parse, let's force a dumb value in if we find that
@@ -343,7 +363,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
if ( $match =~ /Rx (Bytes|Pkts)/ && $end_val =~ /rx_/) {
my $value = 0;
($option) = ($match =~ /(Rx (Bytes|Pkts))/);
#print "Option: $option".NL;
#print "# case 1, Option: $option" . NL;
@parts = ($match =~ m{ Total: (\d+) +Time: \d+s\s+ Cur: (\d+) +(\d+)\/s \#$});
#print "\n RX: ".join(",",@parts)."\n";
if ( defined $option_map{ $option } ) {
@@ -366,6 +386,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
}
elsif ( $match =~ /Cx Detected/) {
my $value = 0;
#print "# case 2\n";
($option) = ($match =~ /(Cx Detected)/);
if ( defined $option_map{ $option } ) {
$value = 0 + ($match =~ /:\s+(\d+)/)[0];
@@ -377,7 +398,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
elsif ( $match =~ /Tx (Bytes|Pkts)/ && $end_val =~ /tx_/) {
my $value = 0;
($option) = ($match =~ /(Tx (Bytes|Pkts))/);
#print "Option: $option".NL;
#print "# case 3, Option: $option" . NL;
@parts = ($match =~ m{ Total: (\d+) +Time: \d+s\s+ Cur: (\d+) +(\d+)\/s \#$});
#print "\n TX: ".join(",",@parts)."\n";
if ( defined $option_map{ $option } ) {
@@ -403,7 +424,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
my $value = 0;
($option) = ($match =~ /([TR][Xx] (((OOO|Duplicate|Failed) (Bytes|Pkts))|Wrong Dev|CRC Failed|Bit Errors|Dropped)|Conn (Established|Timeouts)|TCP Retransmits)/);
@parts = $match =~ m{ Total: (\d+) +Time: \d+s\s+ Cur: (\d+) +(\d+)\/s \#$};
#print "\n TX: ".join(",",@parts)."\n";
#print "\n# case 4 TX: ".join(",",@parts)."\n";
if ( defined $option_map{ $option } ) {
#print "$match\n";
$match =~ s/""/ /g;
@@ -415,6 +436,7 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
elsif ( $match =~ /(Bytes|Packets) (Rcvd|Transmitted)/ ) {
($option) = ($match =~ /((Bytes|Packets) (Rcvd|Transmitted))/);
@parts = ($match =~ m{ Total: (\d+) +Time: \d+s\s+ Cur: (\d+) +(\d+)\/s \#$});
#print "\n# case 5 TX: ".join(",",@parts)."\n";
my $value = 0;
if ( defined $option_map{ $option } ) {
if ($end_val =~ /rx_(bps|pps)/ ) {
@@ -436,6 +458,8 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
}
}
else {
#print "Default case...\n";
# special case
$match =~ s/Shelf: (\d+), /Shelf: $1 /
if ($match =~ /^\s*Shelf:/ );
@@ -458,25 +482,35 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
if ($match =~/CWND: (\d+) /);
# ~specials
@parts = ($match =~ m/( *[^ ]+):( *\S+ [^ #]*)(?! #|\S+:)/g);
for (my $i=0; $i < @parts; $i+=2) {
$option = $parts[$i];
#print " parts[$option] ";
$option =~ s/^\s*(.*)\s*$/$1/;
if ( defined $option_map{ $option } ) {
my $value = $parts[ $i + 1 ];
if ($value =~ /^\s*([^ ]+):\s+/) {
$value = "-";
}
else {
$value =~ s/^\s*(.*)\s*$/$1/;
}
#print "\n D end_val[$end_val] option[$option] now ".$value."\n";
$option_map{ $option } = $value;
$endval_done++;
last;
}
}
#print " match: $match\n";
if ($match =~ /.*$end_val:\s+(\S+)/) {
my $value = $1;
#print " Found value: $value for key: $end_val\n";
$option_map{ $end_val } = $value;
$endval_done++;
}
# This below just does not work right, for instance with L3 endp and these values: RealRxRate,RealTxRate,MinTxRate
# --Ben
#@parts = ($match =~ m/( *[^ ]+):( *\S+ [^ #]*)(?! #|\S+:)/g);
#for (my $i=0; $i < @parts; $i+=2) {
# $option = $parts[$i];
# $option =~ s/^\s*(.*)\s*$/$1/; # Trim whitespace
# print " parts[$option] ";
# if ( defined $option_map{ $option } ) {
# my $value = $parts[ $i + 1 ];
# if ($value =~ /^\s*([^ ]+):\s+/) {
# $value = "-";
# }
# else {
# $value =~ s/^\s*(.*)\s*$/$1/;
# }
# #print "\n D end_val[$end_val] option[$option] now ".$value."\n";
# $option_map{ $option } = $value;
# $endval_done++;
# last;
# }
#}
}
} # ~matches
} # ~endp_vals
@@ -485,7 +519,12 @@ if (grep {$_ eq $::action} split(',', "show_endp,set_endp,create_endp,create_arm
}
}
else {
print $::utils->doAsyncCmd("nc_show_endp $::endp_name");
if ($stats_from_file ne "") {
print get_stats_from_file($stats_from_file, $endp_name);
}
else {
print $::utils->doAsyncCmd("nc_show_endp $::endp_name");
}
}
}
elsif ($::action eq "create_arm") {
@@ -745,3 +784,51 @@ else {
}
exit(0);
sub get_stats_from_file {
my $fname = shift;
my $endp_name = shift;
open(F, "<$fname") or die("Can't open $fname for reading: $!\n");
my $endp_text = "";
my $ep = "";
my @lines = ();
while ( my $line = <F>) {
@lines = (@lines, $line);
}
# Append dummy line to make it easier to terminate the parse logic.
@lines = (@lines, "Endpoint [________] (NOT_RUNNING)\n");
my $i;
for ($i = 0; $i<@lines;$i++) {
my $line = $lines[$i];
chomp($line);
if (($line =~ /Endpoint\s+\[(.*)\]/) ||
($line =~ /WanLink\s+\[(.*)\]/) ||
($line =~ /ArmEndp\s+\[(.*)\]/) ||
# TODO: Layer-4 ?
($line =~ /VoipEndp\s+\[(.*)\]/)) {
my $m1 = $1;
#print "Found starting line: $line name: $m1 endp_name: $endp_name\n";
if ($endp_text ne "") {
# See if existing endp entry matches?
if ($ep eq $endp_name) {
return $endp_text;
}
}
$endp_text = "$line\n";
$ep = $m1;
}
else {
if ($endp_text ne "") {
$endp_text .= "$line\n";
}
}
}
return "";
}