use XML::Simple;
use Data::Dumper;
use Sys::Hostname;
use Tk;
use Tk::DialogBox;
use Tk::ColorEditor;
use Tk::BrowseEntry;
use Tk::LabEntry;
use Tk::Pane;
use threads;
use threads::shared;
use Thread::Semaphore;
use Thread::Queue;
my $running : shared = 1;
my $xs = new XML::Simple(keeproot=>1, forcearray=>1);
my $SYSTEMJOB = $xs->XMLin("");
my $sourcepath = "c:\\eyerobot\\";
my $reportpath = $sourcepath."Report\\";
my $matrixnanotestcount = "72";
my $matrixnanoruntime = "3600";
#start threads
my $discovered = Thread::Queue->new();
my $addsys = Thread::Queue->new();
my $test_start = Thread::Queue->new();
my $test_done = Thread::Queue->new();
my $writelog = Thread::Semaphore->new();
threads->create("executejob")->detach(); #dequeue Discovery
threads->create("formsystemlist")->detach(); #dequeue Discovery
for (my $x = 1; $x <= 1; $x++) {
$discovered->enqueue(mkip()); #Made up IP address for testing
}
#user interface
my @systems;
testControl();
MainLoop();
$running = 0;
exit 0;
#THREADS
sub formsystemlist {
$SIG{__DIE__} = sub{ tcrash(threads->tid()); };
while (my $ip = $discovered->dequeue() and $running) {
my $newsys = $xs->XMLin("");
my $system = $newsys->{system}->[0];
my $passwd = "password";
my $license = "none";
my $tag = "Global";
my $config = "unknown";
my $raidtype = "unknown";
my $serial = "unknown";
my $servicekey = "unknown";
$serial = int(rand(899999999999999))+100000000000000; #TESTING VALUES
$servicekey = int(rand(899999999999999))+100000000000000; #TESTING VALUES
my $hardware = "unknown";
my $macaddr1 = "unknown";
my $macaddr2 = "unknown";
#create XML structure
$system->{ip}->[0] = $ip;
$system->{hardware}->[0] = $hardware;
$system->{volume}->[0] = "";
$system->{status}->[0] = "proceed"; #proceed, success, failure
$system->{state}->[0] = "new"; #new, starting, running, paused, complete, inaccessible
$system->{reportpath}->[0] = "$reportpath";
$system->{health}->[0] = "unknown";
$system->{events}->[0] = "unknown";
$system->{serial}->[0] = $serial;
$system->{servicekey}->[0] = $servicekey;
$system->{createtime}->[0] = time;
$system->{filename}->[0] = "unknown";
$system->{mac}->[0] = $macaddr1;
$system->{mac}->[1] = $macaddr2;
$system->{reasonforfailure}->[0] = "unknown";
$system->{password}->[0] = $passwd;
$system->{license}->[0]->{option}->[0] = $license;
$system->{license}->[0]->{result}->[0] = "unknown";
$system->{license}->[0]->{tag}->[0] = $tag;
$system->{license}->[0]->{capacity}->[0] = "$cap";
$system->{license}->[0]->{jbods}->[0] = "$e";
$system->{raidtype}->[0] = "$raidtype";
$system->{customerConfig}->[0] = "$config";
$system->{customerConfig}->[1] = "unknown";
$system->{job}->[0]->{step}->[0] = "cleanupconfig";
$system->{job}->[0]->{step}->[1] = "PrintHardwareConfig";
$system->{job}->[0]->{nextjob}->[0] = "0:0"; #step:iteration (only matrixnano has iterations)
$system->{job}->[0]->{status}->[0] = "ready"; #ready, running, complete
$system->{job}->[0]->{matrixnanoiterations}->[0] = "$matrixnanotestcount";
$system->{job}->[0]->{matrixnanoruntime}->[0] = "$matrixnanoruntime";
$system->{gui}->[0]->{but_ctl_1}->[0] = "Start";
$system->{gui}->[0]->{but_ctl_2}->[0] = "Pause";
$system->{gui}->[0]->{but_test_param}->[0] = "normal";
$system->{gui}->[0]->{progress}->[0] = "Not running";
$addsys->enqueue($newsys);
}
}
sub executejob {
$SIG{__DIE__} = sub{ tcrash(threads->tid()); };
while ($running) {
#START AND DETACH TEST
while ($test_start->pending() > 0) {
my $system = $test_start->dequeue();
if ($system->{state}->[0] eq "running") {
if ($system->{job}->[0]->{status}->[0] eq "ready") {
$system->{job}->[0]->{status}->[0] = "running";
$system->{job}->[0]->{nextjob}->[0] =~ m/(\d+):(\d+)/;
my $test = $1;
my $iteration = $2;
my $testname = $system->{job}->[0]->{step}->[$test];
#print "Starting test [$testname]\n";
threads->create(\&{$testname}, $system)->detach(); #test
}
}
}
}
sleep 1;
}
#GUI
sub testControl {
my $mainwindow = MainWindow->new();
$mainwindow->title("DIAG Test Control");
$mainwindow->configure(-background=> 'LightYellow');
$mainwindow->protocol('WM_DELETE_WINDOW',sub{$mainwindow->messageBox(-message=>"Window cannot be closed this way.", -title=>"Disabled");return;});
$mainwindow->Label(-text=>"Select license option to set on unit. Will automaticaly continue after $mins minutes.", -background=>'tan', -foreground=>'darkgreen', -font=>['courier', '14', 'bold'])->pack(-side => 'top');
my $lic_grid = $mainwindow->Scrolled('Frame', -background=> 'LightYellow', -scrollbars=>'se', -height=>'500', -width=>'1150', -padx=>'10')->pack(-side => 'top');
$lic_grid->Label(-text=>"IP Address")->grid(-row=>1, -column=>0, -sticky=>"nsew");
$lic_grid->Label(-text=>"Serial Number")->grid(-row=>1, -column=>1, -sticky=>"nsew");
$lic_grid->Label(-text=>"License")->grid(-row=>1, -column=>2, -sticky=>"nsew");
$lic_grid->Label(-text=>"Configuration")->grid(-row=>1, -column=>3, -sticky=>"nsew");
$lic_grid->Label(-text=>"Blink")->grid(-row=>1, -column=>4, -sticky=>"nsew");
$lic_grid->Label(-text=>"Matrixnano\nIterations")->grid(-row=>1, -column=>5, -columnspan=>3, -sticky=>"nsew");
$lic_grid->Label(-text=>"Matrixnano Run Time")->grid(-row=>1, -column=>8, -columnspan=>9, -sticky=>"nsew");
$lic_grid->Label(-text=>"Test Time")->grid(-row=>1, -column=>17, -sticky=>"nsew");
$lic_grid->Label(-text=>"System\nStatus")->grid(-row=>1, -column=>18, -sticky=>"nsew");
$lic_grid->Label(-text=>"System\nStatus")->grid(-row=>1, -column=>19, -sticky=>"nsew");
$lic_grid->Label(-text=>"Controls")->grid(-row=>1, -column=>20, -columnspan=>2, -sticky=>"nsew");
$lic_grid->Label(-text=>"Progress")->grid(-row=>1, -column=>22, -sticky=>"nsew");
my $loop_running = $mainwindow->repeat(5000, sub {
if ($running == 0) {
$mainwindow->destroy;
}
});
my $loop_collect = $mainwindow->repeat(1000, sub {
#PROCESS COMPLETED TEST RESULTS
while ($test_done->pending() > 0) {
print "Getting results of test. Have [".$test_done->pending()."] to process.\n";
my $results = $test_done->dequeue();
for (my $count = 0; $count < @{$SYSTEMJOB->{systemlist}->[0]->{system}}; $count++) {
my $system = $SYSTEMJOB->{systemlist}->[0]->{system}->[$count];
if ($system->{servicekey}->[0] eq $results->{servicekey}->[0]) {
#receive results
if ($results->{status}->[0] !~ m/fail/i) {
#stop/pause
if ($system->{state}->[0] eq "stopping") {
$results->{state}->[0] = "stopped";
$results->{job}->[0]->{nextjob}->[0] = "0:0";
} elsif ($system->{state}->[0] eq "pausing") {
$results->{state}->[0] = "paused";
}
#set next test
my ($test, $iteration) = split(":", $results->{job}->[0]->{nextjob}->[0]);
print "Finished [$test]\n";
if ($results->{job}->[0]->{step}->[$test] eq "domatrixnano") {
$iteration++;
if ($iteration > $results->{job}->[0]->{matrixnanoiterations}->[0]) {
$test++;
$iteration=0;
}
} else {
$test++;
$iteration=0;
}
print "Next test is [$test] out of a total of [".@{$results->{job}->[0]->{step}}."] tests.\n";
if ($test >= @{$results->{job}->[0]->{step}}) {
print "DONE\n";
$results->{job}->[0]->{nextjob}->[0] = "DONE";
$results->{job}->[0]->{status}->[0] = "complete";
$results->{state}->[0] = "complete";
} else {
print "NEXT\n";
$results->{job}->[0]->{nextjob}->[0] = "$test:$iteration";
$results->{job}->[0]->{status}->[0] = "ready";
}
} else {
$results->{job}->[0]->{status}->[0] = "complete";
}
$system = $results;
print "System State: ".$system->{state}->[0]."\n";
$test_start->enqueue($system);
last;
}
}
$mainwindow->update();
}
});
my $loop_addsys = $mainwindow->repeat(1000, sub{
while ($addsys->pending() > 0 and @{$SYSTEMJOB->{systemlist}->[0]->{system}} < 125) { #Reserve some DATA IPs for DIAG controller
#ADD NEW SYSTEM TO GUI
my @test_cfg_options;
my $newsys = $addsys->dequeue();
push(@{$SYSTEMJOB->{systemlist}->[0]->{system}}, $newsys->{system}->[0]);
my $system = $SYSTEMJOB->{systemlist}->[0]->{system}->[@{$SYSTEMJOB->{systemlist}->[0]->{system}} - 1];
$system->{ip}->[1] = find_free_ip();
if (defined $system->{canister}) {
$system->{alias}->[0] = find_free_ip();
}
my $row = @{$SYSTEMJOB->{systemlist}->[0]->{system}} + 2;
my $bgcolor="cornsilk";
if ($row % 2 == 0) {
$bgcolor="LemonChiffon";
}
$lic_grid->Label(-text=>$system->{ip}->[0], -background=>$bgcolor."1")->grid(-row=>$row, -column=>0, -sticky=>"nsew");
push(@test_cfg_options, $lic_grid->Entry(-textvariable=>\$system->{serial}->[0], -background=>$bgcolor."2", -width=>16, -highlightthickness=>2, -highlightcolor=>'blue')->grid(-row=>$row, -column=>1, -sticky=>"nsew"));
$lic_grid->Button(-text=>"Set License", -background=>$bgcolor."3", -command=>[\&LicenseOptions, $system->{license}->[0]])->grid(-row=>$row, -column=>2, -sticky=>"nsew");
$lic_grid->Optionmenu(-variable=>\$system->{customerConfig}->[0], -background=>$bgcolor."3", -options=>\@config_options)->grid(-row=>$row, -column=>3, -sticky=>"nsew");
my $but_blink = $lic_grid->Button(-text=>"Blink Unit", -background=>$bgcolor."4", -command=>sub{
async{
if ($system->{raidtype}->[0] =~ m/software/i or $system->{raidtype}->[0] =~ m/unknown/i) {
my $output = qx"wincuri 2 $system->{ip}->[0] \"$CLI blink -t ld -l /dev/md255 raid\"";
}
if ($system->{raidtype}->[0] =~ m/hardware/i or $system->{raidtype}->[0] =~ m/unknown/i) {
my $output = qx"wincuri 2 $system->{ip}->[0] \"$CLI blink -t ld -l /dev/sda raid\"";
}
};
})->grid(-row=>$row, -column=>4);
if ($system->{raidtype}->[0] =~ m/none/i) {
$but_blink->configure(-state => 'disabled');
}
$lic_grid->Label(-text=>$system->{job}->[0]->{matrixnanoiterations}->[0], -background=>$bgcolor."2", -width => 3)->grid(-row=>$row, -column=>5, -sticky=>"nsew");
push(@test_cfg_options, $lic_grid->Button(-text => "+", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoiterations}->[0]++;})->grid(-row=>$row, -column=>6, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "-", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoiterations}->[0]--;})->grid(-row=>$row, -column=>7, -sticky=>"nsew"));
$lic_grid->Label(-text=>$system->{job}->[0]->{matrixnanoruntime}->[0], -background=>$bgcolor."2", -width=>8)->grid(-row=>$row, -column=>8, -sticky=>"nsew");
push(@test_cfg_options, $lic_grid->Button(-text => "+1D", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]+=86400;})->grid(-row=>$row, -column=>9, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "-1D", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]-=86400;if ($system->{job}->[0]->{matrixnanoruntime}->[0] < 0) {$system->{job}->[0]->{matrixnanoruntime}->[0] = 0;};})->grid(-row=>$row, -column=>10, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "+1H", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]+=3600;})->grid(-row=>$row, -column=>11, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "-1H", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]-=3600;if ($system->{job}->[0]->{matrixnanoruntime}->[0] < 0) {$system->{job}->[0]->{matrixnanoruntime}->[0] = 0;};})->grid(-row=>$row, -column=>12, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "+5M", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]+=300;})->grid(-row=>$row, -column=>13, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "-5M", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]-=300;if ($system->{job}->[0]->{matrixnanoruntime}->[0] < 0) {$system->{job}->[0]->{matrixnanoruntime}->[0] = 0;};})->grid(-row=>$row, -column=>14, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "+5S", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]+=5;})->grid(-row=>$row, -column=>15, -sticky=>"nsew"));
push(@test_cfg_options, $lic_grid->Button(-text => "-5S", -background=>$bgcolor."3", -command => sub{$system->{job}->[0]->{matrixnanoruntime}->[0]-=5;if ($system->{job}->[0]->{matrixnanoruntime}->[0] < 0) {$system->{job}->[0]->{matrixnanoruntime}->[0] = 0;};})->grid(-row=>$row, -column=>16, -sticky=>"nsew"));
$lic_grid->Label(-textvariable=>\$system->{status}->[0], -background=>$bgcolor."1")->grid(-row=>$row, -column=>18, -sticky=>"nsew"); #PROBLEM
$lic_grid->Label(-textvariable=>\$system->{state}->[0], -background=>$bgcolor."1")->grid(-row=>$row, -column=>19, -sticky=>"nsew"); #PROBLEM
my $but_ctl_1 = $lic_grid->Button(-text=>"Start", -background=>$bgcolor."3", -state=>"normal", -foreground=>"black", -background=>"green", -activeforeground=>"green", -activebackground=>"black")->grid(-row=>$row, -column=>20, -sticky=>"nsew");
my $but_ctl_2 = $lic_grid->Button(-text=>"Pause", -background=>$bgcolor."3", -state=>"disabled", -foreground=>"black", -background=>"yellow", -activeforeground=>"yellow", -activebackground=>"black")->grid(-row=>$row, -column=>21, -sticky=>"nsew");
$lic_grid->Label(-textvariable=>\$system->{gui}->[0]->{progress}->[0], -background=>$bgcolor."2", -width => 40)->grid(-row=>$row, -column=>22, -sticky=>"nsew"); #PROBLEM
$but_ctl_1->configure(-command=>sub{
my $state = $system->{state}->[0];
if ($state eq "new" or $state eq "stopped") {
my @buttoncolor=("red","yellow");
$system->{state}->[0]="running";
foreach my $button (@test_cfg_options) {
$button->configure(-state=>"disabled");
}
$but_ctl_1->configure(-text=>"Stop", -foreground=>"black", -background=>$buttoncolor[0], -activeforeground=>$buttoncolor[0], -activebackground=>"black");
$but_ctl_2->configure(-state=>"normal", -text=>"Pause", -foreground=>"black", -background=>$buttoncolor[1], -activeforeground=>$buttoncolor[1], -activebackground=>"black");
$test_start->enqueue($system);
} elsif ($state eq "paused") {
my @buttoncolor=("green","yellow");
$system->{state}->[0]="stopped";
foreach my $button (@test_cfg_options) {
$button->configure(-state=>"normal");
}
$but_ctl_1->configure(-text=>"Start", -foreground=>"black", -background=>$buttoncolor[0], -activeforeground=>$buttoncolor[0], -activebackground=>"black");
$but_ctl_2->configure(-state=>"disabled", -text=>"Pause",-foreground=>"black", -background=>$buttoncolor[1], -activeforeground=>$buttoncolor[1], -activebackground=>"black");
} elsif ($state eq "running" or $state eq "pausing") {
$mainwindow->messageBox(-message=>"Please wait for the system to fully stop before making changes to the test paramaters.", -title=>"Please Wait");
my @buttoncolor=("green","yellow");
$system->{state}->[0]="stopping";
foreach my $button (@test_cfg_options) {
$button->configure(-state=>"normal");
}
$but_ctl_1->configure(-text=>"Start", -foreground=>"black", -background=>$buttoncolor[0], -activeforeground=>$buttoncolor[0], -activebackground=>"black");
$but_ctl_2->configure(-state=>"disabled", -text=>"Pause",-foreground=>"black", -background=>$buttoncolor[1], -activeforeground=>$buttoncolor[1], -activebackground=>"black");
} elsif ($state eq "stopping") {
$mainwindow->messageBox(-message=>"Please wait for the system to fully stop. Once stopped you may make changes to the test paramaters.", -title=>"Please Wait");
}
$mainwindow->update();
});
$but_ctl_2->configure(-command=>sub{
my $state = $system->{state}->[0];
if ($state eq "running") {
my @buttoncolor=("red","green");
$system->{state}->[0]="pausing";
$but_ctl_1->configure(-text=>"Stop", -foreground=>"black", -background=>$buttoncolor[0], -activeforeground=>$buttoncolor[0], -activebackground=>"black");
$but_ctl_2->configure(-text=>"Resume", -foreground=>"black", -background=>$buttoncolor[1], -activeforeground=>$buttoncolor[1], -activebackground=>"black");
} elsif ($state eq "paused") {
my @buttoncolor=("red","yellow");
$system->{state}->[0]="running";
$but_ctl_1->configure(-text=>"Stop", -foreground=>"black", -background=>$buttoncolor[0], -activeforeground=>$buttoncolor[0], -activebackground=>"black");
$but_ctl_2->configure(-text=>"Pause", -foreground=>"black", -background=>$buttoncolor[1], -activeforeground=>$buttoncolor[1], -activebackground=>"black");
$test_start->enqueue($system);
} elsif ($state eq "pausing") {
my @buttoncolor=("red","yellow");
$system->{state}->[0]="running";
$but_ctl_1->configure(-text=>"Stop", -foreground=>"black", -background=>$buttoncolor[0], -activeforeground=>$buttoncolor[0], -activebackground=>"black");
$but_ctl_2->configure(-text=>"Pause", -foreground=>"black", -background=>$buttoncolor[1], -activeforeground=>$buttoncolor[1], -activebackground=>"black");
#race handle
sleep 3;
if ($system->{state}->[0] eq "paused") {
$system->{state}->[0]="running";
$test_start->enqueue($system);
}
}
$mainwindow->update();
});
}
});
$mainwindow->Button(-text=>"Finished", -background=>'tan', -command=>sub {$mainwindow->destroy;})->pack(-side => 'top');
#$mainwindow->Button(-text=>"Finished", -background=>'tan', -command=>sub {quit();mainwindow->destroy;})->pack(-side => 'top');
}
#SUBS
sub convert_time ($) {
my $time = $_[0];
my $days = int($time / 86400);
$time -= ($days * 86400);
my $hours = int($time / 3600);
$time -= ($hours * 3600);
my $minutes = int($time / 60);
$time -= ($hours * 60);
my $seconds = $time % 60;
$days = $days .'d ';
$hours = $hours .'h ';
$minutes = $minutes . 'm ';
return "$days $hours $minutes ${seconds}s";
}
sub find_free_ip {
for (my $ip = 2; $ip < 255; $ip++) { #0.1 is controller
my $used = 0;
for (my $s = 0; $s < @{$SYSTEMJOB->{systemlist}->[0]->{system}}; $s++) {
my $addr = $SYSTEMJOB->{systemlist}->[0]->{system}->[$s]->{ip}->[1];
my $alias = -1;
if (defined $SYSTEMJOB->{systemlist}->[0]->{system}->[$s]->{alias}) {
$alias = $SYSTEMJOB->{systemlist}->[0]->{system}->[$s]->{alias}->[0];
}
if ($ip == $addr or $ip == $alias) {
$used = 1;
last;
}
}
if ($used == 0) {
last;
}
}
return "192.168.0.".$ip;
}
sub mkip {
#Made up IP address for testing
return int(rand(253)+1).".".int(rand(253)+1).".".int(rand(253)+1).".".int(rand(253)+1);
}
sub tcrash {
debugLogFunctionNameLineNum((caller(0))[2],(caller(1))[3]);
my $tid = $_[0];
my $thr = threads->object($tid);
my $error = $thr->error();
print "THR $tid $thr $error\n";
logLine("Thread ". (caller(1))[3] ." died at ". (caller(0))[2] ." due to error ". $thr->error());
$running = 0;
}
sub debugLogFunctionNameLineNum {
# Print sub header and caller info
#debugLogFunctionNameLineNum((caller(0))[2],(caller(1))[3]);
my ($callerline, $caller) = @_;
unless ($caller) {
$caller = "MAIN";
}
if ($caller =~ m/eval/) {
$caller = "Tk call";
$callerline = "Unknown";
}
my $LineNumber = (caller(0))[2];
my $FunctionName = (caller(1))[3];
my $time = localtime time;
unless ($FunctionName) {
$FunctionName = "MAIN";
}
logLine("$FunctionName, $LineNumber: Called from [$caller] at [$callerline].");
}
sub logLine {
#Write only to log file
my ($text) =@_;
my ($package, $filename, $line) = caller;
my $time = localtime time;
$writelog->down();
print "$filename, $line, $time: $text\n";
#open (LOG, ">>log.txt");
#print LOG "$filename, $line, $time: $text\n";
#close (LOG);
$writelog->up();
}
sub printLog {
#Write to log file and print to screen
my ($text) =@_;
my ($package, $filename, $line) = caller;
my $time = localtime time;
$writelog->down();
print "$filename, $line, $time: $text\n";
#open (LOG, ">>log.txt");
#print LOG "$filename, $line, $time: $text\n";
#close (LOG);
$writelog->up();
}
#TESTS
sub cleanupconfig {
my $subroutine = (caller(0))[3];
my $system = $_[0];
my $testtime = int(rand(30))+10;
print "Running [$subroutine] [".$system->{state}->[0]."] for $testtime\n";
sleep $testtime;
print "[$subroutine] complete\n";
$test_done->enqueue($system);
}
sub PrintHardwareConfig {
my $subroutine = (caller(0))[3];
my $system = $_[0];
my $testtime = int(rand(30))+5;
print "Running [$subroutine] [".$system->{state}->[0]."] for $testtime\n";
sleep $testtime;
print "[$subroutine] complete\n";
$test_done->enqueue($system);
}