Skip to content

Commit

Permalink
moving binaries into usr/bin/
Browse files Browse the repository at this point in the history
  • Loading branch information
milkey-mouse committed Apr 28, 2019
1 parent b117065 commit dffc0d3
Show file tree
Hide file tree
Showing 3 changed files with 1,060 additions and 0 deletions.
259 changes: 259 additions & 0 deletions usr/bin/net-hydra
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
#!/usr/bin/perl

# (c) 2017 Jim Salter. Licensed GPLv3. net-hydra --usage for details.

# this software is licensed for use under the Free Software Foundation's GPL v3.0 license, as retrieved
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
# project's Git repository at https://github.com/jimsalterjrs/network-testing/blob/master/LICENSE.

use strict;
use Data::Dumper; # debugging - print contents of hash
use Time::HiRes qw ( usleep );

my %args = getargs(@ARGV);

# If this eval{} succeeds, Config::IniFiles becomes available. If it fails, $inifiles will be false.
my $inifiles = eval {
require Config::IniFiles;
Config::IniFiles->import();
1;
};

if ($args{'usage'}) {
printusage();
exit 0;
}

# friendlier variable names for arguments
my $conf_file = $args{'c'};
my $testname = $args{'testname'};

my $sshcmd = '/usr/bin/ssh';

if (! $inifiles) {
# no Config::IniFiles available. Sadface. Die with honor now.
print "\n";
print "net-hydra requires the Perl library Config::IniFiles. You may install it\n";
print "using CPAN, or (preferably) from your distribution's repositories.\n";
print "\n";
print "On Debian/Ubuntu/derivatives, try:\n";
print " sudo apt install libconfig-inifiles-perl\n";
print "\n";
print "On RedHat/derivatives, try:\n";
print " sudo yum install perl-Config-IniFiles\n";
print "\n";
exit 256;
}

# load test configs from multiclient.conf
tie my %ini, 'Config::IniFiles', ( -file => $conf_file ) or die "FATAL: cannot load $conf_file.";

# populate %clients from $ini{'clients'} for easier access later
my %clients;
my %sockets;
my %directives;
foreach my $client (keys %{ $ini{'clients'} }) {
$clients{$client} = $ini{'clients'}{$client};
}


# establish SSH control sessions for each device
print "Establishing SSH control sessions, and checking clock synchronization on each client...\n";

foreach my $client (sort keys %clients) {
my $socket = "/tmp/multiclient-$client-" . time();
$sockets{$client} = $socket;
print "Establishing control socket for $client...\n";
open FH, "$sshcmd -M -S $socket -o ControlPersist=15m $clients{$client} exit |";
close FH;
}

# establish clock is synced at each device
foreach my $client (sort keys %clients) {
my $cmd = "/bin/date +%s";
print "Checking time synchronization for $client...\n";
my $sync = `$sshcmd -S $sockets{$client} $clients{$client} $cmd`;
my $now = time();
if ( abs($now - $sync) >1 ) {
my $delta = $now-$sync;
print "Device $client at $clients{$client} is $delta seconds off from my clock.\n";
print "Please correct the time at $clients{$client} before attempting to run\n";
print "this job again.\n\n";
exit 255;
}
}

# delay execution for two seconds per directive to execute
my $delay = (scalar keys %{ $ini{'directives'} }) * 2 + 10;
my $when = time()+$delay;

# populate %clients from $ini{'clients'} for easier access later
foreach my $client (keys %{ $ini{'directives'} }) {
$directives{$client} = $ini{'directives'}{$client};
if ($directives{$client} =~ /^\$/) {
# it's an alias, so populate it from the aliases table
$directives{$client} = $ini{'aliases'}{$directives{$client}};
}
# substitute exection time in for special value $when in the directives
$directives{$client} =~ s/\$when/$when/g;
# substitute testname in for special value $testname in the directives
$directives{$client} =~ s/\$testname/$testname/g;
}

# loop through the directives given
foreach my $client (sort keys %directives) {
#print "$client is at $clients{$client} and needs to whenits $when $directives{$client} .\n";
print "Scheduling job on $client...\n";
my $cmd = "$sshcmd -S $sockets{$client} $clients{$client} whenits -d $when $directives{$client}";
#print "$cmd\n";
system $cmd;
}

my $now=time();
print "Executing on client systems in " . ($when-$now) . " seconds...\n";
while ($now < $when) {
$now = time();
# move 1 line up, clear to beginning of that line
print "\e[1F";
print "\e[K";
print "Executing on client systems in " . ($when-$now) . " seconds...\n";
usleep 100000; # sleep 100 milliseconds
}

print "\e[1F";
print "\e[K";
print "Client systems executing now.\n";

exit 0;


##########################################################################################################


sub printusage {
print "Usage: net-hydra -c {configfile} [--testname {testname}]\n";
print "\n";
print "net-hydra requires a config file specifying [clients], [directives], and optionally\n";
print "[aliases], which it uses to schedule jobs to run simultaneously in the very near future\n";
print "on multiple client machines.\n";
print qq^
# sample nethydra.conf
[clients]
# list each client device here, by name and as SSH will connect to them.
#
local0 = root\@127.0.0.1
local1 = root\@127.0.0.2
[directives]
# These are the command(s) to be run on each client device. Directives
# beginning with \$ reference lines from the [aliases] section. Any use
# of \$when, either here or in [aliases], will be replaced with the
# scheduled execution time, in Unix epoch seconds; \$testname is replaced
# with the --testname argument passed to net-hydra on the command-line.
#
local0 = \$4kstream
local1 = /usr/bin/touch /tmp/test-\$testname-\$when.txt
[aliases]
# Defining aliases here keeps [directives] cleaner, so you can
# see what you're doing a little more easily.
#
\$4kstream = netburn -u http://127.0.0.1/1M.bin -r 25 -o /tmp/\$testname-\$when.csv
^;
print "\n";
print "net-hydra requires the whenits command to be in the standard path on each client\n";
print "machine, for use precisely scheduling the directives to execute simultaneously.\n";
print "\n";
print "See https://github.com/jimsalterjrs/network-testing for sample configs and more\n";
print "information.\n\n";
exit 256;
}

sub getargs {
my @args = @_;
my %args;

my %novaluearg;
my %validarg;
push my @validargs, ('usage','c','testname');
foreach my $item (@validargs) { $validarg{$item} = 1; }

push my @novalueargs, ('usage');
foreach my $item (@novalueargs) { $novaluearg{$item} = 1; }

push my @mandatoryargs, ('c');

# if user specified no args at all, force --usage on
if (scalar @args == 0) { $args{'usage'}=1; }

while (my $rawarg = shift(@args)) {
my $arg = $rawarg;
my $argvalue = '';
if ($rawarg =~ /=/) {
# user specified the value for a CLI argument with =
# instead of with blank space. separate appropriately.
$argvalue = $arg;
$arg =~ s/=.*$//;
$argvalue =~ s/^.*=//;
}
if ($rawarg =~ /^--/) {
# doubledash arg
$arg =~ s/^--//;
if (! $validarg{$arg}) { die "ERROR: don't understand argument $rawarg.\n"; }
if ($novaluearg{$arg}) {
$args{$arg} = 1;
} else {
# if this CLI arg takes a user-specified value and
# we don't already have it, then the user must have
# specified with a space, so pull in the next value
# from the array as this value rather than as the
# next argument.
if ($argvalue eq '') { $argvalue = shift(@args); }
$args{$arg} = $argvalue;
}
} elsif ($arg =~ /^-/) {
# singledash arg
$arg =~ s/^-//;
if (! $validarg{$arg}) { die "ERROR: don't understand argument $rawarg.\n"; }
if ($novaluearg{$arg}) {
$args{$arg} = 1;
} else {
# if this CLI arg takes a user-specified value and
# we don't already have it, then the user must have
# specified with a space, so pull in the next value
# from the array as this value rather than as the
# next argument.
if ($argvalue eq '') { $argvalue = shift(@args); }
$args{$arg} = $argvalue;
}
} else {
# bare arg
die "ERROR: don't know what to do with bare argument $rawarg.\n";
}
}

# if we aren't checking for usage,
my @missingargs;
if (!defined $args{'usage'}) {
foreach my $mandarg (@mandatoryargs) {
if (! defined $args{$mandarg}) { push @missingargs, $mandarg; }
}
}
if (scalar @missingargs) {
printusage();

my $errortext = "ERROR: missing mandatory arguments ";
foreach my $missingarg (@missingargs) {
$errortext .= "-$missingarg, ";
}
# trim trailing ", " from errortext
$errortext = substr($errortext,0,((length $errortext)-2));
die "$errortext\n";
}

# insert default values for arguments here if necessary
if (! defined $args{'testname'}) { $args{'testname'} = 'null'; }

return %args;
}

Loading

0 comments on commit dffc0d3

Please sign in to comment.