* Finished converting Remote->call() to use Net::OpenSSH. Also updated all calls to this method to expect the output as a single (sometimes multi-line) string instead of an array reference. Also updated all calles to expect 'output' first, 'error' second.

* Added a 'timeout' parameter to Remote->call() to limit the time that a command on a remote host can run, with a default of '10' (seconds).

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent 559dbafb39
commit c41adb17ff
  1. 9
      Anvil/Tools/Get.pm
  2. 666
      Anvil/Tools/Remote.pm
  3. 91
      Anvil/Tools/Storage.pm
  4. 16
      Anvil/Tools/System.pm
  5. 15
      cgi-bin/striker
  6. 10
      share/words.xml
  7. 8
      tools/anvil-manage-files

@ -148,7 +148,7 @@ else
fi; fi;
"; ";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
shell_call => $shell_call, shell_call => $shell_call,
target => $target, target => $target,
@ -156,9 +156,12 @@ fi;
password => $password, password => $password,
remote_user => $remote_user, remote_user => $remote_user,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
$version = defined $output->[0] ? $output->[0] : ""; $version = defined $output ? $output : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }});
} }
else else

@ -182,12 +182,12 @@ sub add_target_to_known_hosts
=head2 call =head2 call
This does a remote call over SSH. The connection is held open and the file handle for the target is cached and re-used unless a specific ssh_fh is passed or a request to close the connection is received. This does a remote call over SSH. The connection is held open and the file handle for the target is cached and re-used unless a C<< close >> is set to C<< 1 >>.
Example; Example;
# Call 'hostname' on a node. # Call 'hostname' on a node.
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
target => "an-a01n01.alteeve.com", target => "an-a01n01.alteeve.com",
password => "super secret password", password => "super secret password",
remote_user => "admin", remote_user => "admin",
@ -196,7 +196,7 @@ Example;
# Make a call with sensitive data that you want logged only if $anvil->Log->secure is set and close the # Make a call with sensitive data that you want logged only if $anvil->Log->secure is set and close the
# connection when done. # connection when done.
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
target => "an-a01n01.alteeve.com", target => "an-a01n01.alteeve.com",
password => "super secret password", password => "super secret password",
remote_user => "root", remote_user => "root",
@ -207,7 +207,7 @@ Example;
If there is any problem connecting to the target, C<< $error >> will contain a translated string explaining what went wrong. Checking if this is B<< false >> is a good way to verify that the call succeeded. If there is any problem connecting to the target, C<< $error >> will contain a translated string explaining what went wrong. Checking if this is B<< false >> is a good way to verify that the call succeeded.
Any output from the call will be stored in C<< $output >>, which is an array reference with each output line as an array entry. STDERR and STDOUT are merged into the C<< $output >> array reference, with anything from STDERR coming first in the array. Any output from the call will be stored in C<< $output >>. STDERR and STDOUT are merged into the C<< $output >> array reference.
B<NOTE>: By default, a connection to a target will be held open and cached to increase performance for future connections. B<NOTE>: By default, a connection to a target will be held open and cached to increase performance for future connections.
@ -257,6 +257,12 @@ B<NOTE>: If the target matches an entry in '/etc/ssh/ssh_config', the port defin
B<NOTE>: If the C<< target >> is presented in the format C<< target:port >>, the port will be separated from the target and used as the TCP port. If the C<< port >> parameter is set, however, the port split off the C<< target >> will be ignored. B<NOTE>: If the C<< target >> is presented in the format C<< target:port >>, the port will be separated from the target and used as the TCP port. If the C<< port >> parameter is set, however, the port split off the C<< target >> will be ignored.
=head3 timeout (optional, default '10')
B<NOTE>: This is the timeout for the command to return. This is NOT the connection timeout!
If this is set to a numeric whole number, then the called shell command will have the set number of seconds to complete. If this is set to C<< 0 >>, then no timeout will be used.
=cut =cut
sub call sub call
{ {
@ -266,12 +272,15 @@ sub call
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
# Get the target and port so that we can create the ssh_fh key # Get the target and port so that we can create the ssh_fh key
my $port = defined $parameter->{port} ? $parameter->{port} : 22; my $port = defined $parameter->{port} ? $parameter->{port} : 22;
my $target = defined $parameter->{target} ? $parameter->{target} : ""; my $target = defined $parameter->{target} ? $parameter->{target} : "";
my $ssh_fh_key = $target.":".$port; my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $ssh_fh_key = $remote_user."\@".$target.":".$port;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
port => $port, 's1:remote_user' => $remote_user,
target => $target, 's2:target' => $target,
's3:port' => $port,
's4:ssh_fh_key' => $ssh_fh_key,
}}); }});
# This will store the SSH file handle for the given target after the initial connection. # This will store the SSH file handle for the given target after the initial connection.
@ -284,20 +293,19 @@ sub call
my $password = defined $parameter->{password} ? $parameter->{password} : $anvil->data->{sys}{root_password}; my $password = defined $parameter->{password} ? $parameter->{password} : $anvil->data->{sys}{root_password};
my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0; my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0;
my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : ""; my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : "";
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; my $timeout = defined $parameter->{timeout} ? $parameter->{timeout} : 10;
my $start_time = time; my $start_time = time;
my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key}; my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
# NOTE: The shell call might contain sensitive data, so we show '--' if 'secure' is set and $anvil->Log->secure is not. # NOTE: The shell call might contain sensitive data, so we show '--' if 'secure' is set and $anvil->Log->secure is not.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'close' => $close, 'close' => $close,
password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}), password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}),
secure => $secure, secure => $secure,
shell_call => ((not $anvil->Log->secure) && ($secure)) ? $anvil->Words->string({key => "log_0186"}) : $shell_call, shell_call => ((not $anvil->Log->secure) && ($secure)) ? $anvil->Words->string({key => "log_0186"}) : $shell_call,
ssh_fh => $ssh_fh, ssh_fh => $ssh_fh,
start_time => $start_time, start_time => $start_time,
remote_user => $remote_user, port => $port,
port => $port, target => $target,
target => $target,
}}); }});
if (not $shell_call) if (not $shell_call)
@ -317,6 +325,12 @@ sub call
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "remote_user" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "remote_user" }});
return("!!error!!"); return("!!error!!");
} }
if (($timeout) && ($timeout =~ /\D/))
{
# Bad value, should only be digits. Warn and reset to default.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0295", variables => { timeout => $timeout }});
$timeout = 10;
}
# If the user didn't pass a port, but there is an entry in 'hosts::<host>::port', use it. # If the user didn't pass a port, but there is an entry in 'hosts::<host>::port', use it.
if ((not $parameter->{port}) && ($anvil->data->{hosts}{$target}{port})) if ((not $parameter->{port}) && ($anvil->data->{hosts}{$target}{port}))
@ -404,12 +418,21 @@ sub call
# If I don't already have an active SSH file handle, connect now. # If I don't already have an active SSH file handle, connect now.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_fh => $ssh_fh }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_fh => $ssh_fh }});
if ($ssh_fh !~ /^Net::OpenSSH/) if ($ssh_fh =~ /^Net::OpenSSH/)
{ {
my $ssh_fh = ""; # We have an open connection, reusing it.
my $connected = 0; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0296", variables => { connection => $ssh_fh_key }});
foreach (my $i = 0; $i <= 9; $i++) }
else
{
# We're going to try up to 3 times, as sometimes there are transient issues that cause
# connection errors.
my $connected = 0;
my $message_key = "message_0005";
my $last_loop = 2;
foreach (my $i = 0; $i <= $last_loop; $i++)
{ {
last if $connected;
($connect_output) = capture_merged { ($connect_output) = capture_merged {
$ssh_fh = Net::OpenSSH->new($target, $ssh_fh = Net::OpenSSH->new($target,
user => $remote_user, user => $remote_user,
@ -420,19 +443,34 @@ sub call
$connect_output =~ s/\n$//; $connect_output =~ s/\n$//;
$connect_output =~ s/\r$//; $connect_output =~ s/\r$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:target' => $target, 's1:i' => $i,
's2:port' => $port, 's2:target' => $target,
's3:ssh_fh' => $ssh_fh, 's3:port' => $port,
's4:ssh_fh->error' => $ssh_fh->error, 's4:ssh_fh' => $ssh_fh,
's5:connect_output' => $connect_output, 's5:ssh_fh->error' => $ssh_fh->error,
's6:connect_output' => $connect_output,
}}); }});
#print "ssh error: [".$ssh_fh->error."]\n"; # Any fatal issues reaching the target?
#print "output: [".$connect_."]\n"; if ($connect_output =~ /Could not resolve hostname/i)
# print "Results:\n"; print Dumper @result; {
$i = $last_loop;
# If I didn't connect, try again if I have a password. $message_key = "message_0001";
if (($ssh_fh->error) && ($password) && ($connect_output =~ /Permission denied/i)) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { i => $i, message_key => $message_key }});
}
elsif ($connect_output =~ /No route to host/i)
{
$i = $last_loop;
$message_key = "message_0003";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { i => $i, message_key => $message_key }});
}
elsif ($connect_output =~ /Connection refused/i)
{
$i = $last_loop;
$message_key = "message_0002";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { i => $i, message_key => $message_key }});
} # If I didn't connect, try again if I have a password.
elsif (($ssh_fh->error) && ($password) && ($connect_output =~ /Permission denied/i))
{ {
# Try again. # Try again.
#print "Connection without a password failed, trying again with the password.\n"; #print "Connection without a password failed, trying again with the password.\n";
@ -448,22 +486,38 @@ sub call
$connect_output =~ s/\n$//; $connect_output =~ s/\n$//;
$connect_output =~ s/\r$//; $connect_output =~ s/\r$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:target' => $target, 's1:i' => $i,
's2:port' => $port, 's2:target' => $target,
's3:ssh_fh' => $ssh_fh, 's3:port' => $port,
's4:ssh_fh->error' => $ssh_fh->error, 's4:ssh_fh' => $ssh_fh,
's5:connect_output' => $connect_output, 's5:ssh_fh->error' => $ssh_fh->error,
's6:connect_output' => $connect_output,
}}); }});
# If the password is bad, exit the loop.
if ($ssh_fh->error =~ /bad password/i)
{
$i = $last_loop;
$message_key = "message_0006";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
i => $i,
message_key => $message_key,
}});
}
} }
if (not $ssh_fh->error) if (not $ssh_fh->error)
{ {
# Connected! # Connected!
$connected = 1; $connected = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connected => $connected }}); $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = $ssh_fh;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:connected" => $connected,
"s2:cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key},
}});
last; last;
} }
elsif ($i < 9) elsif ($i < $last_loop)
{ {
# Sleep and then try again. # Sleep and then try again.
$connect_output = ""; $connect_output = "";
@ -471,525 +525,83 @@ sub call
} }
} }
# Try ten times. 9 in the loop, last try after.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:connected' => $connected, 's1:connected' => $connected,
's2:ssh_fh->error' => $ssh_fh->error, 's2:ssh_fh->error' => $ssh_fh->error,
}}); }});
if ((not $connected) && ($ssh_fh->error)) my $variables = {
{ target => $target.":".$port,
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", list => { error => $ssh_fh->error,
remote_user => $remote_user, connection => $ssh_fh_key,
target => $target, };
port => $port, if (not $connected)
shell_call => $shell_call,
error => $ssh_fh->error,
}});
# We'll now try to get a more useful message for the user and logs.
my $message_key = "message_0005";
my $variables = {
target => $target,
error => $ssh_fh->error,
};
if (($ssh_fh->error =~ /Bad hostname/i) or ($connect_output =~ /Bad hostname/i))
{
$message_key = "message_0001";
}
elsif (($ssh_fh->error =~ /Connection refused/i) or ($connect_output =~ /Connection refused/i))
{
$message_key = "message_0002";
$variables = {
target => $target,
port => $port,
remote_user => $remote_user,
};
}
elsif (($ssh_fh->error =~ /No route to host/) or ($connect_output =~ /No route to host/i))
{
$message_key = "message_0003";
}
elsif (($ssh_fh->error =~ /timeout/) or ($connect_output =~ /timeout/i))
{
$message_key = "message_0004";
}
$error = $anvil->Words->string({key => $message_key, variables => $variables});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => $message_key, variables => $variables});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => {
error => $error,
ssh_fh => $ssh_fh,
output => $output,
}});
return($error, $output);
}
### TODO: Delete this once we finish converting to Net::OpenSSH
sub call2
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
# Get the target and port so that we can create the ssh_fh key
my $port = defined $parameter->{port} ? $parameter->{port} : 22;
my $target = defined $parameter->{target} ? $parameter->{target} : "";
my $ssh_fh_key = $target.":".$port;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
port => $port,
target => $target,
}});
# This will store the SSH file handle for the given target after the initial connection.
$anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = defined $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} ? $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }});
# Now pick up the rest of the variables.
my $close = defined $parameter->{'close'} ? $parameter->{'close'} : 0;
my $no_cache = defined $parameter->{no_cache} ? $parameter->{no_cache} : 0;
my $password = defined $parameter->{password} ? $parameter->{password} : $anvil->data->{sys}{root_password};
my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0;
my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : "";
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $start_time = time;
my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
# NOTE: The shell call might contain sensitive data, so we show '--' if 'secure' is set and $anvil->Log->secure is not.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'close' => $close,
password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}),
secure => $secure,
shell_call => ((not $anvil->Log->secure) && ($secure)) ? $anvil->Words->string({key => "log_0186"}) : $shell_call,
ssh_fh => $ssh_fh,
start_time => $start_time,
remote_user => $remote_user,
port => $port,
target => $target,
}});
if (not $shell_call)
{
# No shell call
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "shell_call" }});
return("!!error!!");
}
if (not $target)
{
# No target
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "target" }});
return("!!error!!");
}
if (not $remote_user)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->call()", parameter => "remote_user" }});
return("!!error!!");
}
# If the user didn't pass a port, but there is an entry in 'hosts::<host>::port', use it.
if ((not $parameter->{port}) && ($anvil->data->{hosts}{$target}{port}))
{
$port = $anvil->data->{hosts}{$target}{port};
}
# Break out the port, if needed.
my $state = "";
my $error = "";
if ($target =~ /^(.*):(\d+)$/)
{
$target = $1;
$port = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
port => $port,
target => $target,
}});
# If the user passed a port, override this.
if ($parameter->{port} =~ /^\d+$/)
{
$port = $parameter->{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port => $port }});
}
}
else
{
# In case the user is using ports in /etc/ssh/ssh_config, we'll want to check for an entry.
$anvil->System->read_ssh_config();
$anvil->data->{hosts}{$target}{port} = "" if not defined $anvil->data->{hosts}{$target}{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hosts::${target}::port" => $anvil->data->{hosts}{$target}{port} }});
if ($anvil->data->{hosts}{$target}{port} =~ /^\d+$/)
{
$port = $anvil->data->{hosts}{$target}{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port => $port }});
}
}
# Make sure the port is valid.
if ($port eq "")
{
$port = 22;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port => $port }});
}
elsif ($port !~ /^\d+$/)
{
$port = getservbyname($port, 'tcp');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port => $port }});
}
if ((not defined $port) or (($port !~ /^\d+$/) or ($port < 0) or ($port > 65536)))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0058", variables => { port => $port }});
return("!!error!!");
}
# If the target is a host name, convert it to an IP.
if (not $anvil->Validate->is_ipv4({ip => $target}))
{
my $new_target = $anvil->Convert->hostname_to_ip({host_name => $target});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { new_target => $new_target }});
if ($new_target)
{
$target = $new_target;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target }});
}
}
# If the user set 'no_cache', don't use any existing 'ssh_fh'.
if (($no_cache) && ($ssh_fh))
{
# Close the connection.
$ssh_fh->disconnect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "message_0010", variables => { target => $target }});
# For good measure, blank both variables.
$anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = "";
$ssh_fh = "";
}
# These will be merged into a single 'output' array before returning.
my $stdout_output = [];
my $stderr_output = [];
# If I don't already have an active SSH file handle, connect now.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_fh => $ssh_fh }});
if ($ssh_fh !~ /^Net::SSH2/)
{
# use Time::HiRes qw (usleep ualarm gettimeofday tv_interval nanosleep
# clock_gettime clock_getres clock_nanosleep clock
# stat);
### NOTE: Nevermind, timeout isn't supported... >_< Find a newer version if IO::Socket::IP?
### TODO: Make the timeout user-configurable to handle slow connections. Make it
### 'sys::timeout::{all|host} = x'
# my $start_time = [gettimeofday];
$ssh_fh = Net::SSH2->new(timeout => 1000);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:target' => $target,
's2:port' => $port,
's3:ssh_fh' => $ssh_fh,
}});
# Try ten times. 9 in the loop, last try after.
my $connected = 0;
for (1..9)
{ {
if ($ssh_fh->connect($target, $port))
{
$connected = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connected => $connected }});
last;
}
else
{
# Sleep and try once more.
$ssh_fh->disconnect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0101", variables => {
target => $target,
port => $port,
}});
sleep 1;
$ssh_fh = Net::SSH2->new(timeout => 1000);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
's1:target' => $target,
's2:port' => $port,
's3:ssh_fh' => $ssh_fh,
}});
}
}
if ((not $connected) && (not $ssh_fh->connect($target, $port)))
{
# my $connect_time = tv_interval ($start_time, [gettimeofday]);
#print "[".$connect_time."] - Connection failed time to: [$target:$port]\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", list => {
remote_user => $remote_user,
target => $target,
port => $port,
shell_call => $shell_call,
error => $@,
}});
# We'll now try to get a more useful message for the user and logs.
my $message_key = "message_0005";
my $variables = {
target => $target,
error => $@,
};
if ($@ =~ /Bad hostname/i)
{
$message_key = "message_0001";
}
elsif ($@ =~ /Connection refused/i)
{
$message_key = "message_0002";
$variables = {
target => $target,
port => $port,
remote_user => $remote_user,
};
}
elsif ($@ =~ /No route to host/)
{
$message_key = "message_0003";
}
elsif ($@ =~ /timeout/)
{
$message_key = "message_0004";
}
$error = $anvil->Words->string({key => $message_key, variables => $variables}); $error = $anvil->Words->string({key => $message_key, variables => $variables});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => $message_key, variables => $variables}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => $message_key, variables => $variables});
} }
# my $connect_time = tv_interval ($start_time, [gettimeofday]);
#print "[".$connect_time."] - Connect time to: [$target:$port]\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error, ssh_fh => $ssh_fh }});
if (not $error)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
remote_user => $remote_user,
password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}),
}});
if (not $ssh_fh->auth_password($remote_user, $password))
{
### NOTE: Passwordless SSH isn't working.
# Can we log in without a password?
my $user = getpwuid($<);
my $home_directory = $anvil->Get->users_home({debug => 3, user => $user});
my $public_key = $home_directory."/.ssh/id_rsa.pub";
my $private_key = $home_directory."/.ssh/id_rsa";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
user => $user,
home_directory => $home_directory,
public_key => $public_key,
private_key => $private_key,
}});
my $return = $ssh_fh->auth_publickey($user, $public_key, $private_key);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'return' => $return,
'$@' => $@,
}});
if ($return)
{
# We're in! Record the file handle for this target.
$anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = $ssh_fh;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }});
# Log that we got in without a password.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0062", variables => { target => $target }});
}
else
{
# This is for the user
$error = $anvil->Words->string({key => "message_0006", variables => { target => $target }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "message_0006", variables => { target => $target }});
}
}
else
{
# We're in! Record the file handle for this target.
$anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = $ssh_fh;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }});
# Record our success
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "message_0007", variables => { target => $target }});
}
}
} }
### Special thanks to Rafael Kitover (rkitover@gmail.com), maintainer of Net::SSH2, for helping me # If I have a valid handle, try to call our command now. Note that if we're using a cached connection
### sort out the polling and data collection in this section. # that has died, we might fail.
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { ssh_fh => $ssh_fh }});
# Open a channel and make the call. if ($ssh_fh =~ /^Net::OpenSSH/)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
ssh_fh => $ssh_fh,
}});
if (($ssh_fh =~ /^Net::SSH2/) && (not $error))
{ {
# We need to open a channel every time for 'exec' calls. We want to keep blocking off, but we # Make sure the output variables are clean and then make the call.
# need to enable it for the channel() call. $output = "";
$ssh_fh->blocking(1); $error = "";
my $channel = $ssh_fh->channel(); # or $ssh_fh->die_with_error; if ($timeout)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { channel => $channel }});
if (not $channel)
{ {
my $try = 0; # Call with a timeout
my $ok = 0; ($output, $error) = $ssh_fh->capture2({timeout => $timeout}, $shell_call);
until ($ok) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }});
{
sleep 1;
if ($try > 5)
{
### Give up.
# If we're in a web interface, set 'form::error_massage'.
my $message = $anvil->Words->string({key => "striker_warning_0006", variables => {
target => $remote_user."\@".$target,
error => $ssh_fh->error,
} });
$error = $message;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", raw => $message});
if ($anvil->environment eq" html")
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
return($error, []);
}
$channel = $ssh_fh->channel(); # or $ssh_fh->die_with_error;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { channel => $channel }});
if ($channel)
{
$ok = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ok => $ok }});
}
else
{
$try++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { try => $try }});
}
}
} }
$ssh_fh->blocking(0); else
# Make the shell call
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { channel => $channel }});
if (not $channel)
{ {
# ... or not. # Call without a timeout.
$ssh_fh = ""; ($output, $error) = $ssh_fh->capture2($shell_call);
$error = $anvil->Words->string({key => "message_0008", variables => { target => $target }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "message_0008", variables => { target => $target }});
} }
else # Was there a problem?
if ($ssh_fh->error)
{ {
### TODO: Timeout if the call doesn't respond in X seconds, closing the filehandle if hit. # Something went wrong.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { $error = $anvil->Words->string({key => "message_0008", variables => {
channel => $channel,
shell_call => $shell_call, shell_call => $shell_call,
connection => $ssh_fh_key,
error => $ssh_fh->error,
}}); }});
$channel->exec("$shell_call");
# This keeps the connection open when the remote side is slow to return data, like in
# '/etc/init.d/rgmanager stop'.
my @poll = {
handle => $channel,
events => [qw/in err/],
};
# We'll store the STDOUT and STDERR data here.
my $stdout = "";
my $stderr = "";
# Not collect the data.
while(1)
{
$ssh_fh->poll(250, \@poll);
# Read in anything from STDOUT
while($channel->read(my $chunk, 80))
{
$stdout .= $chunk;
}
while ($stdout =~ s/^(.*)\n//)
{
my $line = $1;
$line =~ s/\r//g; # Remove \r from things like output of daemon start/stops.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { "STDOUT:line" => $line }});
push @{$stdout_output}, $line;
}
# Read in anything from STDERR
while($channel->read(my $chunk, 80, 1))
{
$stderr .= $chunk;
}
while ($stderr =~ s/^(.*)\n//)
{
my $line = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { "STDERR:line" => $line }});
push @{$stderr_output}, $line;
}
# Exit when we get the end-of-file.
last if $channel->eof;
}
if ($stdout)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { stdout => $stdout }});
push @{$stdout_output}, $stdout;
}
if ($stderr)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { stderr => $stderr }});
push @{$stderr_output}, $stderr;
}
} }
}
# Merge the STDOUT and STDERR # Take the last new line off.
my $output = []; $output =~ s/\n$//; $output =~ s/\r$//;
$error =~ s/\n$//; $error =~ s/\r$//;
foreach my $line (@{$stderr_output}, @{$stdout_output}) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => {
{ error => $error,
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { line => $line }}); output => $output,
push @{$output}, $line; 'close' => $close,
} }});
# Close the connection if requested. # Have we been asked to close the connection?
if ($close) if ($close)
{
if ($ssh_fh)
{ {
# Close it. # Close it.
$ssh_fh->disconnect(); $ssh_fh->disconnect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "message_0009", variables => { target => $target }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "message_0009", variables => { target => $target }});
}
# For good measure, blank both variables. # For good measure, blank both variables.
$anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = ""; $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = "";
$ssh_fh = ""; $ssh_fh = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }});
}
} }
$error = "" if not defined $error;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => {
error => $error, error => $error,
ssh_fh => $ssh_fh,
output => $output, output => $output,
}}); }});
return($error, $output); return($output, $error);
}; }
# =head3 # =head3
# #

@ -191,7 +191,7 @@ else
".$anvil->data->{path}{exe}{echo}." 'not found' ".$anvil->data->{path}{exe}{echo}." 'not found'
fi"; fi";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -199,23 +199,27 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
if (not $error) if (not $error)
{ {
# No error. Did the file exist? # No error. Did the file exist?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }});
if ($output->[0] eq "not found") if ($output eq "not found")
{ {
# File doesn't exist. # File doesn't exist.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0151", variables => { source_file => $source_file }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0151", variables => { source_file => $source_file }});
if ($fatal) { $anvil->nice_exit({code => 1}); } if ($fatal) { $anvil->nice_exit({code => 1}); }
} }
elsif ($output->[0] eq "not a file") elsif ($output eq "not a file")
{ {
# Not a file # Not a file
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0153", variables => { source_file => $source_file }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0153", variables => { source_file => $source_file }});
if ($fatal) { $anvil->nice_exit({code => 1}); } if ($fatal) { $anvil->nice_exit({code => 1}); }
} }
elsif ($output->[0] eq "not readable") elsif ($output eq "not readable")
{ {
# Can't read the file. # Can't read the file.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0152", variables => { source_file => $source_file }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0152", variables => { source_file => $source_file }});
@ -682,7 +686,7 @@ else
".$anvil->data->{path}{exe}{echo}." 'target directory not found' ".$anvil->data->{path}{exe}{echo}." 'target directory not found'
fi"; fi";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -690,6 +694,10 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
if ($error) if ($error)
{ {
# Something went wrong. # Something went wrong.
@ -705,11 +713,12 @@ fi";
} }
else else
{ {
my ($line1, $line2) = (split/\n/, $output);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'output->[0]' => $output->[0], line1 => $line1,
'output->[1]' => $output->[1], line2 => $line2,
}}); }});
if ($output->[0] eq "source file not found") if ($line1 eq "source file not found")
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => {
method => "copy_file", method => "copy_file",
@ -717,7 +726,7 @@ fi";
}}); }});
return(1); return(1);
} }
if (($output->[0] eq "source file exists") && (not $overwrite)) if (($line1 eq "source file exists") && (not $overwrite))
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => {
method => "copy_file", method => "copy_file",
@ -726,7 +735,7 @@ fi";
}}); }});
return(1); return(1);
} }
if ($output->[1] eq "target directory not found") if ($line2 eq "target directory not found")
{ {
my $failed = $anvil->Storage->make_directory({ my $failed = $anvil->Storage->make_directory({
debug => $debug, debug => $debug,
@ -745,7 +754,7 @@ fi";
} }
# Now backup the file. # Now backup the file.
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -753,7 +762,10 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $anvil->data->{path}{exe}{'cp'}." -af ".$source_file." ".$target_file, shell_call => $anvil->data->{path}{exe}{'cp'}." -af ".$source_file." ".$target_file,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
} }
} }
else else
@ -1007,7 +1019,7 @@ else
fi; fi;
fi;"; fi;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -1019,7 +1031,7 @@ fi;";
error => $error, error => $error,
output => $output, output => $output,
}}); }});
if ($output->[0] eq "failed to create") if ($output eq "failed to create")
{ {
$failed = 1; $failed = 1;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0167", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0167", variables => {
@ -1199,7 +1211,7 @@ else
".$anvil->data->{path}{exe}{echo}." 'target directory not found' ".$anvil->data->{path}{exe}{echo}." 'target directory not found'
fi"; fi";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -1207,6 +1219,10 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
if ($error) if ($error)
{ {
# Something went wrong. # Something went wrong.
@ -1222,11 +1238,12 @@ fi";
} }
else else
{ {
my ($line1, $line2) = (split/\n/, $output);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'output->[0]' => $output->[0], line1 => $line1,
'output->[1]' => $output->[1], line2 => $line2,
}}); }});
if ($output->[0] eq "source file not found") if ($line1 eq "source file not found")
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => {
method => "move_file", method => "move_file",
@ -1234,7 +1251,7 @@ fi";
}}); }});
return(1); return(1);
} }
if (($output->[0] eq "source file exists") && (not $overwrite)) if (($line1 eq "source file exists") && (not $overwrite))
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => {
method => "move_file", method => "move_file",
@ -1243,7 +1260,7 @@ fi";
}}); }});
return(1); return(1);
} }
if ($output->[1] eq "target directory not found") if ($line2 eq "target directory not found")
{ {
my $failed = $anvil->Storage->make_directory({ my $failed = $anvil->Storage->make_directory({
debug => $debug, debug => $debug,
@ -1262,7 +1279,7 @@ fi";
} }
# Now backup the file. # Now backup the file.
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -1270,7 +1287,10 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $anvil->data->{path}{exe}{mv}." -f ".$source_file." ".$target_file, shell_call => $anvil->data->{path}{exe}{mv}." -f ".$source_file." ".$target_file,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
} }
} }
else else
@ -2673,7 +2693,7 @@ else
".$anvil->data->{path}{exe}{echo}." 'not found'; ".$anvil->data->{path}{exe}{echo}." 'not found';
fi"; fi";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
($error, my $output) = $anvil->Remote->call({ (my $output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
port => $port, port => $port,
@ -2682,11 +2702,14 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
if (not $error) if (not $error)
{ {
# No error. Did the file exist? # No error. Did the file exist?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); if ($output eq "exists")
if ($output->[0] eq "exists")
{ {
if (not $overwrite) if (not $overwrite)
{ {
@ -2720,7 +2743,7 @@ else
".$anvil->data->{path}{exe}{echo}." 'not found'; ".$anvil->data->{path}{exe}{echo}." 'not found';
fi"; fi";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
($error, my $output) = $anvil->Remote->call({ (my $output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -2728,14 +2751,16 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); error => $error,
if ($output->[0] eq "not found") output => $output,
}});
if ($output eq "not found")
{ {
# Create the directory # Create the directory
my $shell_call = $anvil->data->{path}{exe}{'mkdir'}." -p ".$directory; my $shell_call = $anvil->data->{path}{exe}{'mkdir'}." -p ".$directory;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
($error, my $output) = $anvil->Remote->call({ (my $output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
target => $target, target => $target,
user => $remote_user, user => $remote_user,
@ -2743,6 +2768,10 @@ fi";
remote_user => $remote_user, remote_user => $remote_user,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
} }
if (not $error) if (not $error)

@ -380,12 +380,13 @@ sub change_shell_user_password
# Update the password using 'usermod'. NOTE: The single-quotes are crtical! # Update the password using 'usermod'. NOTE: The single-quotes are crtical!
my $output = ""; my $output = "";
my $error = "";
my $shell_call = $anvil->data->{path}{exe}{usermod}." --password '".$new_hash."' ".$user."; ".$anvil->data->{path}{exe}{'echo'}." return_code:\$?"; my $shell_call = $anvil->data->{path}{exe}{usermod}." --password '".$new_hash."' ".$user."; ".$anvil->data->{path}{exe}{'echo'}." return_code:\$?";
if ($target) if ($target)
{ {
# Remote call. # Remote call.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
$output = $anvil->Remote->call({ ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
shell_call => $shell_call, shell_call => $shell_call,
target => $target, target => $target,
@ -393,7 +394,10 @@ sub change_shell_user_password
password => $password, password => $password,
remote_user => $remote_user, remote_user => $remote_user,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
} }
else else
{ {
@ -1986,13 +1990,14 @@ sub ping
last if $pinged; last if $pinged;
my $output = ""; my $output = "";
my $error = "";
# If the 'target' is set, we'll call over SSH unless 'target' is 'local' or our hostname. # If the 'target' is set, we'll call over SSH unless 'target' is 'local' or our hostname.
if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname))
{ {
### Remote calls ### Remote calls
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }});
$output = $anvil->Remote->call({ ($output, $error) = $anvil->Remote->call({
debug => $debug, debug => $debug,
shell_call => $shell_call, shell_call => $shell_call,
target => $target, target => $target,
@ -2000,7 +2005,10 @@ sub ping
password => $password, password => $password,
remote_user => $remote_user, remote_user => $remote_user,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
output => $output,
}});
} }
else else
{ {

@ -1028,12 +1028,15 @@ sub add_sync_peer
my $shell_call = $anvil->data->{path}{exe}{dmidecode}." --string system-uuid"; my $shell_call = $anvil->data->{path}{exe}{dmidecode}." --string system-uuid";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($error, $output) = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
password => $password, password => $password,
target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host, target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host,
shell_call => $shell_call, shell_call => $shell_call,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error => $error }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
}});
if ($error) if ($error)
{ {
# No access # No access
@ -1042,7 +1045,7 @@ sub add_sync_peer
else else
{ {
# We got the peer's UUID. Get the hostname as well. # We got the peer's UUID. Get the hostname as well.
$peer_uuid = lc($output->[0]); $peer_uuid = lc($output);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_uuid => $peer_uuid }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_uuid => $peer_uuid }});
if (not $anvil->Validate->is_uuid({uuid => $peer_uuid})) if (not $anvil->Validate->is_uuid({uuid => $peer_uuid}))
@ -1056,8 +1059,12 @@ sub add_sync_peer
target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host, target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host,
shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static", shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static",
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
}});
$peer_host = $output->[0]; $peer_host = $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host => $peer_host }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host => $peer_host }});
# Lastly, if bi-directional is set, make sure we have a way to talk to it. # Lastly, if bi-directional is set, make sure we have a way to talk to it.

@ -26,13 +26,13 @@ Author: Madison Kelly <mkelly@alteeve.ca>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. --> <!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key> <key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
<key name="message_0002">The connection to: [#!variable!target!#] on port: [#!variable!port!#] as the user: [#!variable!user!#] was refused. If you recently booted the target, it may be just about finished booting. It is normal for the connection to be refused for a brief time during the boot process.</key> <key name="message_0002">The connection to: [#!variable!connection!#] was refused. If you recently booted the target, the network might have started, the ssh daemon might not be running yet.</key>
<key name="message_0003">There is no route to: [#!variable!target!#]. Is the machine in the process of booting up or powering off?</key> <key name="message_0003">There is no route to: [#!variable!target!#]. Is the machine (or the interface) up?</key>
<key name="message_0004">Timed out while waiting for a reply from: [#!variable!target!#]. Is the machine booting up? If so, please wait a minute or two and try again.</key> <key name="message_0004">Timed out while waiting for a reply from: [#!variable!target!#]. Is the machine booting up? If so, please wait a minute or two and try again.</key>
<key name="message_0005">There was an unknown error while connecting to: [#!variable!target!#]. The error was: [#!variable!error!#]</key> <key name="message_0005">There was an unknown error while connecting to: [#!variable!target!#]. The error was: [#!variable!error!#]</key>
<key name="message_0006">We were unable to log in to: [#!variable!target!#]. Please check that the password is correct or that passwordless SSH is configured properly.</key> <key name="message_0006">We were unable to log in to: [#!variable!connection!#]. Please check that the password is correct or that passwordless SSH is configured properly.</key>
<key name="message_0007">An SSH session was successfully opened to: [#!variable!target!#].</key> <key name="message_0007">An SSH session was successfully opened to: [#!variable!target!#].</key>
<key name="message_0008">There was a problem establishing an SSH channel to the target: [#!variable!target!#].</key> <key name="message_0008">The remote shell call: [#!variable!shell_call!#] to: [#!variable!connection!#] failed with the error: [#!variable!error!#].</key>
<key name="message_0009">The SSH session to: [#!variable!target!#] was successfully closed.</key> <key name="message_0009">The SSH session to: [#!variable!target!#] was successfully closed.</key>
<key name="message_0010">The SSH session to: [#!variable!target!#] was closed because 'no_cache' was set and there was an open SSH connection.</key> <key name="message_0010">The SSH session to: [#!variable!target!#] was closed because 'no_cache' was set and there was an open SSH connection.</key>
<key name="message_0011">Wrote the system UUID to the file: [#!variable!file!#] to enable the web based tools to read this system's UUID.</key> <key name="message_0011">Wrote the system UUID to the file: [#!variable!file!#] to enable the web based tools to read this system's UUID.</key>
@ -600,6 +600,8 @@ We will keep looking.</key>
<key name="log_0292">[ Error ] - The requested URL: [#!variable!url!#] failed because the network is unreachable.</key> <key name="log_0292">[ Error ] - The requested URL: [#!variable!url!#] failed because the network is unreachable.</key>
<key name="log_0293">[ Error ] - The requested URL: [#!variable!url!#] failed for an unknown reason.</key> <key name="log_0293">[ Error ] - The requested URL: [#!variable!url!#] failed for an unknown reason.</key>
<key name="log_0294"><![CDATA[[ Error ] - The method Convert->time() was passed the 'time' of: [#!variable!time!#] which does not appear to be a whole number.]]></key> <key name="log_0294"><![CDATA[[ Error ] - The method Convert->time() was passed the 'time' of: [#!variable!time!#] which does not appear to be a whole number.]]></key>
<key name="log_0295"><![CDATA[[ Error ] - The method Remote->call() was passed the 'timeout' of: [#!variable!timeout!#] which does not appear to be a whole number.]]></key>
<key name="log_0296">We have a connection open already to: [#!variable!connection!#], skipping connect stage.</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. --> <!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key> <key name="t_0000">Test</key>

@ -458,13 +458,17 @@ AND
# If the file is found, we'll parse these out. # If the file is found, we'll parse these out.
my $remote_size = 0; my $remote_size = 0;
my $remote_md5sum = ""; my $remote_md5sum = "";
my $output = $anvil->Remote->call({ my ($output, $error) = $anvil->Remote->call({
shell_call => $anvil->data->{path}{exe}{'anvil-file-details'}." --file ".$full_path." --with-md5sum", shell_call => $anvil->data->{path}{exe}{'anvil-file-details'}." --file ".$full_path." --with-md5sum",
remote_user => $remote_user, remote_user => $remote_user,
password => $password, password => $password,
target => $ip, target => $ip,
}); });
foreach my $line (@{$output}) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
error => $error,
output => $output,
}});
foreach my $line (split/\n/, $output)
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /^size: \[(\d+)\]$/) if ($line =~ /^size: \[(\d+)\]$/)

Loading…
Cancel
Save