diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index b5db4af6..ea75941e 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -148,7 +148,7 @@ else 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 }}); - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, shell_call => $shell_call, target => $target, @@ -156,9 +156,12 @@ fi; password => $password, 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 }}); } else diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm index c87e2ee6..b9b1f941 100644 --- a/Anvil/Tools/Remote.pm +++ b/Anvil/Tools/Remote.pm @@ -182,12 +182,12 @@ sub add_target_to_known_hosts =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; # Call 'hostname' on a node. - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ target => "an-a01n01.alteeve.com", password => "super secret password", 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 # connection when done. - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ target => "an-a01n01.alteeve.com", password => "super secret password", 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. -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: By default, a connection to a target will be held open and cached to increase performance for future connections. @@ -257,6 +257,12 @@ B: If the target matches an entry in '/etc/ssh/ssh_config', the port defin B: 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: 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 sub call { @@ -266,12 +272,15 @@ sub call 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; + my $port = defined $parameter->{port} ? $parameter->{port} : 22; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + 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 => { - port => $port, - target => $target, + 's1:remote_user' => $remote_user, + '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. @@ -284,20 +293,19 @@ sub call 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 $timeout = defined $parameter->{timeout} ? $parameter->{timeout} : 10; 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, + '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, + port => $port, + target => $target, }}); 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" }}); 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::::port', use it. 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. $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 = ""; - my $connected = 0; - foreach (my $i = 0; $i <= 9; $i++) + # We have an open connection, reusing it. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0296", variables => { connection => $ssh_fh_key }}); + } + 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 { $ssh_fh = Net::OpenSSH->new($target, user => $remote_user, @@ -420,19 +443,34 @@ sub call $connect_output =~ s/\n$//; $connect_output =~ s/\r$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 's1:target' => $target, - 's2:port' => $port, - 's3:ssh_fh' => $ssh_fh, - 's4:ssh_fh->error' => $ssh_fh->error, - 's5:connect_output' => $connect_output, + 's1:i' => $i, + 's2:target' => $target, + 's3:port' => $port, + 's4:ssh_fh' => $ssh_fh, + 's5:ssh_fh->error' => $ssh_fh->error, + 's6:connect_output' => $connect_output, }}); - - #print "ssh error: [".$ssh_fh->error."]\n"; - #print "output: [".$connect_."]\n"; - # print "Results:\n"; print Dumper @result; - - # If I didn't connect, try again if I have a password. - if (($ssh_fh->error) && ($password) && ($connect_output =~ /Permission denied/i)) + + # Any fatal issues reaching the target? + if ($connect_output =~ /Could not resolve hostname/i) + { + $i = $last_loop; + $message_key = "message_0001"; + $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. #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/\r$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 's1:target' => $target, - 's2:port' => $port, - 's3:ssh_fh' => $ssh_fh, - 's4:ssh_fh->error' => $ssh_fh->error, - 's5:connect_output' => $connect_output, + 's1:i' => $i, + 's2:target' => $target, + 's3:port' => $port, + 's4:ssh_fh' => $ssh_fh, + '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) { # Connected! $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; } - elsif ($i < 9) + elsif ($i < $last_loop) { # Sleep and then try again. $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 => { 's1:connected' => $connected, 's2:ssh_fh->error' => $ssh_fh->error, }}); - if ((not $connected) && ($ssh_fh->error)) + my $variables = { + target => $target.":".$port, + error => $ssh_fh->error, + connection => $ssh_fh_key, + }; + if (not $connected) { - $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 => $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::::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+)$/) + # If I have a valid handle, try to call our command now. Note that if we're using a cached connection + # that has died, we might fail. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { ssh_fh => $ssh_fh }}); + if ($ssh_fh =~ /^Net::OpenSSH/) { - $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+$/) + # Make sure the output variables are clean and then make the call. + $output = ""; + $error = ""; + if ($timeout) { - $port = $anvil->data->{hosts}{$target}{port}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port => $port }}); + # Call with a timeout + ($output, $error) = $ssh_fh->capture2({timeout => $timeout}, $shell_call); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }}); } - } - - # 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) + else { - 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, - }}); - } + # Call without a timeout. + ($output, $error) = $ssh_fh->capture2($shell_call); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { 'ssh_fh->error' => $ssh_fh->error }}); } - if ((not $connected) && (not $ssh_fh->connect($target, $port))) + # Was there a problem? + if ($ssh_fh->error) { -# 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 => $@, + # Something went wrong. + $error = $anvil->Words->string({key => "message_0008", variables => { + shell_call => $shell_call, + connection => $ssh_fh_key, + 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 => $@, - }; - 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}); - $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 - ### sort out the polling and data collection in this section. - # - # Open a channel and make the call. - $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 - # need to enable it for the channel() call. - $ssh_fh->blocking(1); - my $channel = $ssh_fh->channel(); # or $ssh_fh->die_with_error; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { channel => $channel }}); - if (not $channel) - { - my $try = 0; - my $ok = 0; - until ($ok) - { - 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); + # Take the last new line off. + $output =~ s/\n$//; $output =~ s/\r$//; + $error =~ s/\n$//; $error =~ s/\r$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { + error => $error, + output => $output, + 'close' => $close, + }}); - # Make the shell call - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { channel => $channel }}); - if (not $channel) - { - # ... or not. - $ssh_fh = ""; - $error = $anvil->Words->string({key => "message_0008", variables => { target => $target }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "message_0008", variables => { target => $target }}); - } - else - { - ### TODO: Timeout if the call doesn't respond in X seconds, closing the filehandle if hit. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { - channel => $channel, - shell_call => $shell_call, - }}); - $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 - my $output = []; - - foreach my $line (@{$stderr_output}, @{$stdout_output}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { line => $line }}); - push @{$output}, $line; - } - - # Close the connection if requested. - if ($close) - { - if ($ssh_fh) + # Have we been asked to close the connection? + if ($close) { # Close it. $ssh_fh->disconnect(); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "message_0009", variables => { target => $target }}); + + # For good measure, blank both variables. + $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} }}); } - - # For good measure, blank both variables. - $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} }}); } - $error = "" if not defined $error; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => $secure, list => { error => $error, - ssh_fh => $ssh_fh, output => $output, }}); - return($error, $output); -}; - + return($output, $error); +} # =head3 # diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index fe933c44..ce8a9d8d 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -191,7 +191,7 @@ else ".$anvil->data->{path}{exe}{echo}." 'not found' 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 }}); - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -199,23 +199,27 @@ fi"; remote_user => $remote_user, shell_call => $shell_call, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); if (not $error) { # No error. Did the file exist? - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); - if ($output->[0] eq "not found") + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output }}); + if ($output eq "not found") { # File doesn't exist. $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}); } } - elsif ($output->[0] eq "not a file") + elsif ($output eq "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 }}); if ($fatal) { $anvil->nice_exit({code => 1}); } } - elsif ($output->[0] eq "not readable") + elsif ($output eq "not readable") { # 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 }}); @@ -682,7 +686,7 @@ else ".$anvil->data->{path}{exe}{echo}." 'target directory not found' 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 }}); - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -690,6 +694,10 @@ fi"; remote_user => $remote_user, shell_call => $shell_call, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); if ($error) { # Something went wrong. @@ -705,11 +713,12 @@ fi"; } else { + my ($line1, $line2) = (split/\n/, $output); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output->[0]' => $output->[0], - 'output->[1]' => $output->[1], + line1 => $line1, + 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 => { method => "copy_file", @@ -717,7 +726,7 @@ fi"; }}); 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 => { method => "copy_file", @@ -726,7 +735,7 @@ fi"; }}); return(1); } - if ($output->[1] eq "target directory not found") + if ($line2 eq "target directory not found") { my $failed = $anvil->Storage->make_directory({ debug => $debug, @@ -745,7 +754,7 @@ fi"; } # Now backup the file. - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -753,7 +762,10 @@ fi"; remote_user => $remote_user, 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 @@ -1007,7 +1019,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 }}); - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -1019,7 +1031,7 @@ fi;"; error => $error, output => $output, }}); - if ($output->[0] eq "failed to create") + if ($output eq "failed to create") { $failed = 1; $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' 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 }}); - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -1207,6 +1219,10 @@ fi"; remote_user => $remote_user, shell_call => $shell_call, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); if ($error) { # Something went wrong. @@ -1222,11 +1238,12 @@ fi"; } else { + my ($line1, $line2) = (split/\n/, $output); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output->[0]' => $output->[0], - 'output->[1]' => $output->[1], + line1 => $line1, + 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 => { method => "move_file", @@ -1234,7 +1251,7 @@ fi"; }}); 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 => { method => "move_file", @@ -1243,7 +1260,7 @@ fi"; }}); return(1); } - if ($output->[1] eq "target directory not found") + if ($line2 eq "target directory not found") { my $failed = $anvil->Storage->make_directory({ debug => $debug, @@ -1262,7 +1279,7 @@ fi"; } # Now backup the file. - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -1270,7 +1287,10 @@ fi"; remote_user => $remote_user, 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 @@ -2673,7 +2693,7 @@ else ".$anvil->data->{path}{exe}{echo}." 'not found'; 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 }}); - ($error, my $output) = $anvil->Remote->call({ + (my $output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, port => $port, @@ -2682,11 +2702,14 @@ fi"; remote_user => $remote_user, shell_call => $shell_call, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); if (not $error) { # No error. Did the file exist? - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); - if ($output->[0] eq "exists") + if ($output eq "exists") { if (not $overwrite) { @@ -2720,7 +2743,7 @@ else ".$anvil->data->{path}{exe}{echo}." 'not found'; 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 }}); - ($error, my $output) = $anvil->Remote->call({ + (my $output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -2728,14 +2751,16 @@ fi"; remote_user => $remote_user, shell_call => $shell_call, }); - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'output->[0]' => $output->[0] }}); - if ($output->[0] eq "not found") + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); + if ($output eq "not found") { # Create the 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 }}); - ($error, my $output) = $anvil->Remote->call({ + (my $output, $error) = $anvil->Remote->call({ debug => $debug, target => $target, user => $remote_user, @@ -2743,6 +2768,10 @@ fi"; remote_user => $remote_user, shell_call => $shell_call, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); } if (not $error) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index a7b13dcd..c2e8cadb 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -380,12 +380,13 @@ sub change_shell_user_password # Update the password using 'usermod'. NOTE: The single-quotes are crtical! my $output = ""; + my $error = ""; my $shell_call = $anvil->data->{path}{exe}{usermod}." --password '".$new_hash."' ".$user."; ".$anvil->data->{path}{exe}{'echo'}." return_code:\$?"; if ($target) { # 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 }}); - $output = $anvil->Remote->call({ + ($output, $error) = $anvil->Remote->call({ debug => $debug, shell_call => $shell_call, target => $target, @@ -393,7 +394,10 @@ sub change_shell_user_password password => $password, 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 { @@ -1986,13 +1990,14 @@ sub ping last if $pinged; my $output = ""; + my $error = ""; # 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)) { ### 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 }}); - $output = $anvil->Remote->call({ + ($output, $error) = $anvil->Remote->call({ debug => $debug, shell_call => $shell_call, target => $target, @@ -2000,7 +2005,10 @@ sub ping password => $password, 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 { diff --git a/cgi-bin/striker b/cgi-bin/striker index 82359c80..0bbb1443 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -1028,12 +1028,15 @@ sub add_sync_peer 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 }}); - my ($error, $output) = $anvil->Remote->call({ + my ($output, $error) = $anvil->Remote->call({ password => $password, target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host, 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) { # No access @@ -1042,7 +1045,7 @@ sub add_sync_peer else { # 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 }}); 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, 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 }}); # Lastly, if bi-directional is set, make sure we have a way to talk to it. diff --git a/share/words.xml b/share/words.xml index 67a4b75b..a4f79be4 100644 --- a/share/words.xml +++ b/share/words.xml @@ -26,13 +26,13 @@ Author: Madison Kelly The host name: [#!variable!target!#] does not resolve to an IP address. - 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. - There is no route to: [#!variable!target!#]. Is the machine in the process of booting up or powering off? + 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. + There is no route to: [#!variable!target!#]. Is the machine (or the interface) up? 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. There was an unknown error while connecting to: [#!variable!target!#]. The error was: [#!variable!error!#] - We were unable to log in to: [#!variable!target!#]. Please check that the password is correct or that passwordless SSH is configured properly. + We were unable to log in to: [#!variable!connection!#]. Please check that the password is correct or that passwordless SSH is configured properly. An SSH session was successfully opened to: [#!variable!target!#]. - There was a problem establishing an SSH channel to the target: [#!variable!target!#]. + The remote shell call: [#!variable!shell_call!#] to: [#!variable!connection!#] failed with the error: [#!variable!error!#]. The SSH session to: [#!variable!target!#] was successfully closed. The SSH session to: [#!variable!target!#] was closed because 'no_cache' was set and there was an open SSH connection. Wrote the system UUID to the file: [#!variable!file!#] to enable the web based tools to read this system's UUID. @@ -600,6 +600,8 @@ We will keep looking. [ Error ] - The requested URL: [#!variable!url!#] failed because the network is unreachable. [ Error ] - The requested URL: [#!variable!url!#] failed for an unknown reason. time() was passed the 'time' of: [#!variable!time!#] which does not appear to be a whole number.]]> + call() was passed the 'timeout' of: [#!variable!timeout!#] which does not appear to be a whole number.]]> + We have a connection open already to: [#!variable!connection!#], skipping connect stage. Test diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index 0e87643d..56839d17 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -458,13 +458,17 @@ AND # If the file is found, we'll parse these out. my $remote_size = 0; 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", remote_user => $remote_user, password => $password, 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 }}); if ($line =~ /^size: \[(\d+)\]$/)