diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 5be425c4..de2de911 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -983,6 +983,9 @@ sub _set_defaults subnet => "10.100.0.0", netmask => "255.255.0.0", }, + test => { + domains => ["alteeve.com", "redhat.com", "google.com"], + }, }, template => { html => "alteeve", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index a52f4ce8..deb29624 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -806,7 +806,7 @@ sub connect if ($anvil->data->{database}{$uuid}{ping}) { # Can I ping? - my ($pinged) = $anvil->System->ping({ + my ($pinged) = $anvil->Network->ping({ debug => $debug, ping => $host, count => 1, @@ -833,7 +833,7 @@ sub connect } # Before we try to connect, see if this is a local database and, if so, make sure it's setup. - my $is_local = $anvil->System->is_local({debug => $debug, host => $host}); + my $is_local = $anvil->Network->is_local({debug => $debug, host => $host}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); if ($is_local) { diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index b829014f..1a816432 100755 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -12,10 +12,13 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Network.pm"; ### Methods; +# check_internet # find_matches # get_ips # get_network # is_local +# is_remote +# ping =pod @@ -76,6 +79,123 @@ sub parent # Public methods # ############################################################################################################# +=head2 check_internet + +This method tries to connect to the internet. If successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. + +Paramters; + +=head3 domains (optional, default 'defaults::network::test::domains') + +If passed an array reference, the domains in the array will be checked in the order they are found in the array. As soon as any respond to a ping, the check exits and C<< 1 >> is returned. + +If not passed, C<< defaults::network::test::domains >> are used. + +=head3 password (optional) + +If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail). + +=head3 port (optional, default 22) + +If C<< target >> is set, this is the TCP port number used to connect to the remote machine. + +=head3 remote_user (optional) + +If C<< target >> is set, this is the user account that will be used when connecting to the remote system. + +=head3 target (optional) + +If set, the file will be read from the target machine. This must be either an IP address or a resolvable host name. + +=head3 tries (optional, default 3) + +This is how many times we'll try to ping the target. Pings are done one ping at a time, so that if the first ping succeeds, the test can exit quickly and return success. + +=cut +sub check_internet +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->find_matches()" }}); + + my $access = 0; + my $domains = defined $parameter->{domains} ? $parameter->{domains} : $anvil->data->{defaults}{network}{test}{domains}; + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : 22; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : "local"; + my $tries = defined $parameter->{tries} ? $parameter->{tries} : 3; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + domains => $domains, + password => $anvil->Log->is_secure($password), + port => $port, + remote_user => $remote_user, + target => $target, + tries => $tries, + }}); + + if (ref($domains) eq "ARRAY") + { + my $domain_count = @{$domains}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { domain_count => $domain_count }}); + if (not $domain_count) + { + # Array is empty + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0440", variables => { name => "domain" }}); + return($access); + } + } + else + { + # Domains isn't an array. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0218", variables => { name => "domain", value => $domains }}); + return($access); + } + + if (($tries =~ /\D/) or ($tries < 1)) + { + # Invalid + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0441", variables => { name => "tries", value => $tries }}); + return($access); + } + + foreach my $domain (@{$domains}) + { + # Is the domain valid? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { domain => $domain }}); + + if ((not $anvil->Validate->is_domain_name({debug => $debug, name => $domain})) and + (not $anvil->Validate->is_ipv4({debug => $debug, ip => $domain}))) + { + # Not valid, skip + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0442", variables => { name => $domain }}); + next; + } + + my $pinged = $anvil->Network->ping({ + debug => $debug, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, + ping => $domain, + count => 3, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }}); + if ($pinged) + { + $access = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { access => $access }}); + } + last if $pinged; + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { access => $access }}); + return($access); +} + =head2 find_matches This takes two hash keys from prior C<< Network->get_ips() >> runs and finds which are on the same network. @@ -631,6 +751,59 @@ sub get_network return($network); } +### TODO: Merge the logic with ->is_remote and then make one of them simply invert the output of the other. +=head2 is_local + +This method takes a host name or IP address and looks to see if it matches the local system. If it does, it returns C<< 1 >>. Otherwise it returns C<< 0 >>. + +Parameters; + +=head3 host (required) + +This is the host name (or IP address) to check against the local system. + +=cut +sub is_local +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->_is_local()" }}); + + my $host = $parameter->{host} ? $parameter->{host} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }}); + + my $is_local = 0; + if (($host eq $anvil->_host_name) or + ($host eq $anvil->_short_host_name) or + ($host eq "localhost") or + ($host eq "127.0.0.1")) + { + # It's local + $is_local = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); + } + else + { + # Get the list of current IPs and see if they match. + $anvil->Network->get_ips; + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip} }}); + if ($host eq $anvil->data->{network}{'local'}{interface}{$interface}{ip}) + { + $is_local = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); + last; + } + } + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); + return($is_local); +} + =head2 is_remote This looks at the C<< target >> and determines if it relates to the local system or not. If the C<< target >> is remote, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. @@ -669,6 +842,229 @@ sub is_remote # # =cut +=head2 ping + +This method will attempt to ping a target, by host name or IP, and returns C<< 1 >> if successful, and C<< 0 >> if not. + +Example; + + # Test access to the internet. Allow for three attempts to account for network jitter. + my $pinged = $anvil->Network->ping({ + ping => "google.ca", + count => 3, + }); + + # Test 9000-byte jumbo-frame access to a target over the BCN. + my $jumbo_to_peer = $anvil->Network->ping({ + ping => "an-a01n02.bcn", + count => 1, + payload => 9000, + fragment => 0, + }); + + # Check to see if an Anvil! node has internet access + my $pinged = $anvil->Network->ping({ + target => "an-a01n01.alteeve.com", + port => 22, + password => "super secret", + remote_user => "admin", + ping => "google.ca", + count => 3, + }); + +Parameters; + +=head3 count (optional, default '1') + +This tells the method how many time to try to ping the target. The method will return as soon as any ping attemp succeeds (unlike pinging from the command line, which always pings the requested count times). + +=head3 debug (optional, default '3') + +This is an optional way to alter to level at which this method is logged. Useful when the caller is trying to debug a problem. Generally this can be ignored. + +=head3 fragment (optional, default '1') + +When set to C<< 0 >>, the ping will fail if the packet has to be fragmented. This is meant to be used along side C<< payload >> for testing MTU sizes. + +=head3 password (optional) + +This is the password used to access a remote machine. This is used when pinging from a remote machine to a given ping target. + +=head3 payload (optional) + +This can be used to force the ping packet size to a larger number of bytes. It is most often used along side C<< fragment => 0 >> as a way to test if jumbo frames are working as expected. + +B: The payload will have 28 bytes removed to account for ICMP overhead. So if you want to test an MTU of '9000', specify '9000' here. You do not need to account for the ICMP overhead yourself. + +=head3 port (optional, default '22') + +This is the port used to access a remote machine. This is used when pinging from a remote machine to a given ping target. + +B: See C<< Remote->call >> for additional information on specifying the SSH port as part of the target. + +=head3 remote_user (optional, default root) + +If C<< target >> is set, this is the user we will use to log into the remote machine to run the actual ping. + +=head3 target (optional) + +This is the host name or IP address of a remote machine that you want to run the ping on. This is used to test a remote machine's access to a given ping target. + +=head3 timeout (optional, default '1') + +This is how long we will wait for a ping to return, in seconds. Any real number is allowed (C<< 1 >> (one second), C<< 0.25 >> (1/4 second), etc). If set to C<< 0 >>, we will wait for the ping command to exit without limit. + +=cut +sub ping +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->ping()" }}); + +# my $start_time = [gettimeofday]; +# print "Start time: [".$start_time->[0].".".$start_time->[1]."]\n"; +# +# my $ping_time = tv_interval ($start_time, [gettimeofday]); +# print "[".$ping_time."] - Pinged: [$host]\n"; + + # If we were passed a target, try pinging from it instead of locally + my $count = defined $parameter->{count} ? $parameter->{count} : 1; # How many times to try to ping it? Will exit as soon as one succeeds + my $fragment = defined $parameter->{fragment} ? $parameter->{fragment} : 1; # Allow fragmented packets? Set to '0' to check MTU. + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $payload = defined $parameter->{payload} ? $parameter->{payload} : 0; # The size of the ping payload. Use when checking MTU. + my $ping = defined $parameter->{ping} ? $parameter->{ping} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + my $timeout = defined $parameter->{timeout} ? $parameter->{timeout} : 1; # This sets the 'timeout' delay. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + count => $count, + fragment => $fragment, + payload => $payload, + password => $anvil->Log->is_secure($password), + ping => $ping, + port => $port, + remote_user => $remote_user, + target => $target, + }}); + + # Was timeout specified as a simple integer? + if (($timeout !~ /^\d+$/) && ($timeout !~ /^\d+\.\d+$/)) + { + # The timeout was invalid, switch it to 1 + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { timeout => $timeout }}); + $timeout = 1; + } + + # If the payload was set, take 28 bytes off to account for ICMP overhead. + if ($payload) + { + $payload -= 28; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { payload => $payload }}); + } + + # Build the call. Note that we use 'timeout' because if there is no connection and the host name is + # used to ping and DNS is not available, it could take upwards of 30 seconds time timeout otherwise. + my $shell_call = ""; + if ($timeout) + { + $shell_call = $anvil->data->{path}{exe}{timeout}." $timeout "; + } + $shell_call .= $anvil->data->{path}{exe}{'ping'}." -W 1 -n $ping -c 1"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + if (not $fragment) + { + $shell_call .= " -M do"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + } + if ($payload) + { + $shell_call .= " -s $payload"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + } + $shell_call .= " || ".$anvil->data->{path}{exe}{echo}." timeout"; + + my $pinged = 0; + my $average_ping_time = 0; + foreach my $try (1..$count) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count, try => $try }}); + last if $pinged; + + my $output = ""; + my $error = ""; + + # If the 'target' is set, we'll call over SSH unless 'target' is 'local' or our host name. + if ($anvil->Network->is_remote($target)) + { + ### 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, $error, my $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + return_code => $return_code, + }}); + } + else + { + ### Local calls + ($output, my $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }}); + } + + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + if ($line =~ /(\d+) packets transmitted, (\d+) received/) + { + # This isn't really needed, but might help folks watching the logs. + my $pings_sent = $1; + my $pings_received = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + pings_sent => $pings_sent, + pings_received => $pings_received, + }}); + + if ($pings_received) + { + # Contact! + $pinged = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }}); + } + else + { + # Not yet... Sleep to give time for transient network problems to + # pass. + sleep 1; + } + } + if ($line =~ /min\/avg\/max\/mdev = .*?\/(.*?)\//) + { + $average_ping_time = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { average_ping_time => $average_ping_time }}); + } + } + } + + # 0 == Ping failed + # 1 == Ping success + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + pinged => $pinged, + average_ping_time => $average_ping_time, + }}); + return($pinged, $average_ping_time); +} + ############################################################################################################# # Private functions # ############################################################################################################# diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm index 802664a7..62f06f03 100644 --- a/Anvil/Tools/Remote.pm +++ b/Anvil/Tools/Remote.pm @@ -502,7 +502,7 @@ sub call { my ($state_uuid) = $anvil->Database->insert_or_update_states({ debug => 2, - state_name => "host_key_changed::".$target."::".$user, + state_name => "host_key_changed::".$target, state_note => "file=".$bad_file.",line=".$bad_line, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }}); diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index b2d72fcb..f31d9d88 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -2470,6 +2470,10 @@ The return code indicates success; C<< 0 >> is returns if anything goes wrong. C Parameters; +=head3 backup (optional, default '1') + +If the file needs to be updated, and if this is set to C<< 1 >>, a backup will be make before the file is updated. + =head3 body (optional) This is the new body of the file. It should always be set, of course, but it is optional in case the new file is supposed to be empty. @@ -2506,6 +2510,7 @@ sub update_file my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + my $backup = defined $parameter->{backup} ? $parameter->{backup} : 1; my $body = defined $parameter->{body} ? $parameter->{body} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $password = defined $parameter->{password} ? $parameter->{password} : ""; @@ -2515,6 +2520,7 @@ sub update_file my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; my $update = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { + backup => $backup, body => (not $body) ? $body : $anvil->Log->is_secure($body), file => $file, password => $anvil->Log->is_secure($password), @@ -2569,17 +2575,20 @@ sub update_file $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { update => $update }}); - # Backup the file now. - my $backup_file = $anvil->Storage->backup({ - file => $file, - debug => $debug, - target => $target, - port => $port, - user => $remote_user, - password => $password, - remote_user => $remote_user, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }}); + if ($backup) + { + # Backup the file now. + my $backup_file = $anvil->Storage->backup({ + file => $file, + debug => $debug, + target => $target, + port => $port, + user => $remote_user, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }}); + } } else { @@ -2635,6 +2644,10 @@ Returns C<< 0 >> on success. C<< 1 >> or an error string will be returned otherw Parameters; +=head3 backup (optional, default '1') + +When writing to a file that already exists, and C<< overwrite >> is true, the existing backup will be backed up prior to being rewritten. + =head3 body (optional) This is the contents of the file. If it is blank, an empty file will be created (similar to using 'C<< touch >>' on the command line). @@ -2691,6 +2704,7 @@ sub write_file my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + my $backup = defined $parameter->{backup} ? $parameter->{backup} : 1; my $body = defined $parameter->{body} ? $parameter->{body} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $group = defined $parameter->{group} ? $parameter->{group} : getgrgid($(); @@ -2704,6 +2718,7 @@ sub write_file my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; my $error = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { + backup => $backup, body => (not $secure) ? $body : $anvil->Log->is_secure($body), file => $file, group => $group, @@ -2790,19 +2805,20 @@ fi"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0040", variables => { file => $file }}); $error = 1; } - } - else - { - # Back it up. - my $backup_file = $anvil->Storage->backup({ - file => $file, - debug => $debug, - target => $target, - port => $port, - user => $remote_user, - password => $password, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }}); + + if ($backup) + { + # Back it up. + my $backup_file = $anvil->Storage->backup({ + debug => $debug, + file => $file, + target => $target, + port => $port, + user => $remote_user, + password => $password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }}); + } } # Make sure the directory exists on the remote machine. In this case, we'll use 'mkdir -p' if it isn't. @@ -2893,12 +2909,25 @@ fi"; else { # Local - if ((-e $file) && (not $overwrite)) + if (-e $file) { - # Nope. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0040", variables => { file => $file }}); - $error = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); + if (not $overwrite) + { + # Nope. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0040", variables => { file => $file }}); + $error = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); + } + + if ($backup) + { + # Back it up. + my $backup_file = $anvil->Storage->backup({ + debug => $debug, + file => $file, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }}); + } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 79e4da38..4e372847 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -30,10 +30,8 @@ my $THIS_FILE = "System.pm"; # get_uptime # get_os_type # host_name -# is_local # maintenance_mode # manage_firewall -# ping # read_ssh_config # reload_daemon # reboot_needed @@ -1394,58 +1392,6 @@ sub host_name return($host_name, $descriptive); } -=head2 is_local - -This method takes a host name or IP address and looks to see if it matches the local system. If it does, it returns C<< 1 >>. Otherwise it returns C<< 0 >>. - -Parameters; - -=head3 host (required) - -This is the host name (or IP address) to check against the local system. - -=cut -sub is_local -{ - my $self = shift; - my $parameter = shift; - my $anvil = $self->parent; - my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->_is_local()" }}); - - my $host = $parameter->{host} ? $parameter->{host} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }}); - - my $is_local = 0; - if (($host eq $anvil->_host_name) or - ($host eq $anvil->_short_host_name) or - ($host eq "localhost") or - ($host eq "127.0.0.1")) - { - # It's local - $is_local = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); - } - else - { - # Get the list of current IPs and see if they match. - $anvil->Network->get_ips; - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip} }}); - if ($host eq $anvil->data->{network}{'local'}{interface}{$interface}{ip}) - { - $is_local = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); - last; - } - } - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); - return($is_local); -} - =head2 maintenance_mode This sets, clears or checks if the local system is in maintenance mode. Any system in maintenance mode will not be used by normal Anvil! tasks. @@ -2099,228 +2045,6 @@ sub pids } -=head2 ping - -This method will attempt to ping a target, by host name or IP, and returns C<< 1 >> if successful, and C<< 0 >> if not. - -Example; - - # Test access to the internet. Allow for three attempts to account for network jitter. - my $pinged = $anvil->System->ping({ - ping => "google.ca", - count => 3, - }); - - # Test 9000-byte jumbo-frame access to a target over the BCN. - my $jumbo_to_peer = $anvil->System->ping({ - ping => "an-a01n02.bcn", - count => 1, - payload => 9000, - fragment => 0, - }); - - # Check to see if an Anvil! node has internet access - my $pinged = $anvil->System->ping({ - target => "an-a01n01.alteeve.com", - port => 22, - password => "super secret", - ping => "google.ca", - count => 3, - }); - -Parameters; - -=head3 count (optional, default '1') - -This tells the method how many time to try to ping the target. The method will return as soon as any ping attemp succeeds (unlike pinging from the command line, which always pings the requested count times). - -=head3 debug (optional, default '3') - -This is an optional way to alter to level at which this method is logged. Useful when the caller is trying to debug a problem. Generally this can be ignored. - -=head3 fragment (optional, default '1') - -When set to C<< 0 >>, the ping will fail if the packet has to be fragmented. This is meant to be used along side C<< payload >> for testing MTU sizes. - -=head3 password (optional) - -This is the password used to access a remote machine. This is used when pinging from a remote machine to a given ping target. - -=head3 payload (optional) - -This can be used to force the ping packet size to a larger number of bytes. It is most often used along side C<< fragment => 0 >> as a way to test if jumbo frames are working as expected. - -B: The payload will have 28 bytes removed to account for ICMP overhead. So if you want to test an MTU of '9000', specify '9000' here. You do not need to account for the ICMP overhead yourself. - -=head3 port (optional, default '22') - -This is the port used to access a remote machine. This is used when pinging from a remote machine to a given ping target. - -B: See C<< Remote->call >> for additional information on specifying the SSH port as part of the target. - -=head3 remote_user (optional, default root) - -If C<< target >> is set, this is the user we will use to log into the remote machine to run the actual ping. - -=head3 target (optional) - -This is the host name or IP address of a remote machine that you want to run the ping on. This is used to test a remote machine's access to a given ping target. - -=head3 timeout (optional, default '1') - -This is how long we will wait for a ping to return, in seconds. Any real number is allowed (C<< 1 >> (one second), C<< 0.25 >> (1/4 second), etc). If set to C<< 0 >>, we will wait for the ping command to exit without limit. - -=cut -sub ping -{ - my $self = shift; - my $parameter = shift; - my $anvil = $self->parent; - my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->ping()" }}); - -# my $start_time = [gettimeofday]; -# print "Start time: [".$start_time->[0].".".$start_time->[1]."]\n"; -# -# my $ping_time = tv_interval ($start_time, [gettimeofday]); -# print "[".$ping_time."] - Pinged: [$host]\n"; - - # If we were passed a target, try pinging from it instead of locally - my $count = defined $parameter->{count} ? $parameter->{count} : 1; # How many times to try to ping it? Will exit as soon as one succeeds - my $fragment = defined $parameter->{fragment} ? $parameter->{fragment} : 1; # Allow fragmented packets? Set to '0' to check MTU. - my $password = defined $parameter->{password} ? $parameter->{password} : ""; - my $payload = defined $parameter->{payload} ? $parameter->{payload} : 0; # The size of the ping payload. Use when checking MTU. - my $ping = defined $parameter->{ping} ? $parameter->{ping} : ""; - my $port = defined $parameter->{port} ? $parameter->{port} : ""; - my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; - my $target = defined $parameter->{target} ? $parameter->{target} : ""; - my $timeout = defined $parameter->{timeout} ? $parameter->{timeout} : 1; # This sets the 'timeout' delay. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - count => $count, - fragment => $fragment, - payload => $payload, - password => $anvil->Log->is_secure($password), - ping => $ping, - port => $port, - remote_user => $remote_user, - target => $target, - }}); - - # Was timeout specified as a simple integer? - if (($timeout !~ /^\d+$/) && ($timeout !~ /^\d+\.\d+$/)) - { - # The timeout was invalid, switch it to 1 - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { timeout => $timeout }}); - $timeout = 1; - } - - # If the payload was set, take 28 bytes off to account for ICMP overhead. - if ($payload) - { - $payload -= 28; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { payload => $payload }}); - } - - # Build the call. Note that we use 'timeout' because if there is no connection and the host name is - # used to ping and DNS is not available, it could take upwards of 30 seconds time timeout otherwise. - my $shell_call = ""; - if ($timeout) - { - $shell_call = $anvil->data->{path}{exe}{timeout}." $timeout "; - } - $shell_call .= $anvil->data->{path}{exe}{'ping'}." -W 1 -n $ping -c 1"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - if (not $fragment) - { - $shell_call .= " -M do"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - } - if ($payload) - { - $shell_call .= " -s $payload"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - } - $shell_call .= " || ".$anvil->data->{path}{exe}{echo}." timeout"; - - my $pinged = 0; - my $average_ping_time = 0; - foreach my $try (1..$count) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count, try => $try }}); - last if $pinged; - - my $output = ""; - my $error = ""; - - # If the 'target' is set, we'll call over SSH unless 'target' is 'local' or our host name. - if ($anvil->Network->is_remote($target)) - { - ### 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, $error, my $return_code) = $anvil->Remote->call({ - debug => $debug, - shell_call => $shell_call, - target => $target, - port => $port, - password => $password, - remote_user => $remote_user, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - error => $error, - output => $output, - return_code => $return_code, - }}); - } - else - { - ### Local calls - ($output, my $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }}); - } - - foreach my $line (split/\n/, $output) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - if ($line =~ /(\d+) packets transmitted, (\d+) received/) - { - # This isn't really needed, but might help folks watching the logs. - my $pings_sent = $1; - my $pings_received = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - pings_sent => $pings_sent, - pings_received => $pings_received, - }}); - - if ($pings_received) - { - # Contact! - $pinged = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }}); - } - else - { - # Not yet... Sleep to give time for transient network problems to - # pass. - sleep 1; - } - } - if ($line =~ /min\/avg\/max\/mdev = .*?\/(.*?)\//) - { - $average_ping_time = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { average_ping_time => $average_ping_time }}); - } - } - } - - # 0 == Ping failed - # 1 == Ping success - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - pinged => $pinged, - average_ping_time => $average_ping_time, - }}); - return($pinged, $average_ping_time); -} - =head2 read_ssh_config This reads /etc/ssh/ssh_config and notes hosts with defined ports. When found, the associated port will be automatically used for a given host name or IP address. diff --git a/cgi-bin/striker b/cgi-bin/striker index 8b17f1a2..40f1f04e 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -619,10 +619,9 @@ AND $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_line => $bad_line }}); } } - my ($target, $user) = ($state_name =~ /host_key_changed::(.*)::(.*)$/); + my ($target) = ($state_name =~ /host_key_changed::(.*)$/); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target, - user => $user, bad_file => $bad_file, bad_line => $bad_line, }}); @@ -637,7 +636,6 @@ AND checkbox_name => $checkbox_key, checkbox_checked => $checked, target => $target, - user => $user, file => $bad_file, host => $host_name, }}); @@ -849,21 +847,26 @@ sub process_prep_host_page }}); # If the target is RHEL and it is not registered, offer the user to provide the RH user and password. - my $rh_template = ""; + my $redhat_message = ""; + my $redhat_form = ""; if (($data->{host_os} =~ /^rhel/) && ($data->{os_registered} ne "yes")) { - $rh_template = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat", variables => { + $redhat_message = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat-message"}); + $redhat_form = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat-form", variables => { rh_user => $rh_user, rh_password => $rh_password, }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { rh_template => $rh_template }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + redhat_form => $redhat_form, + redhat_message => $redhat_message, + }}); } - ### NOTE: Left off here. Need to pick up the message from a bad/changed fingerprint when it's the cause of a failed login. Create a button to remove the bad key. + # Did we connect? if (not $connected) { - # Is it because the target's key is bad or has changed? - my $query = "SELECT state_uuid, state_note FROM states WHERE state_name LIKE ".$anvil->Database->quote("host_key_changed::".$host_ip_address."::%").";"; + # Nope. Is it because the target's key is bad or has changed? + my $query = "SELECT state_uuid, state_note FROM states WHERE state_name LIKE ".$anvil->Database->quote("host_key_changed::".$host_ip_address).";"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); @@ -922,11 +925,19 @@ sub process_prep_host_page else { # Connected! Ask th euser to confirm. + my $new_host_name = "#!string!striker_0139!#"; + if ((exists $anvil->data->{cgi}{host_name}) && ($anvil->data->{cgi}{host_name}{value})) + { + $new_host_name = $anvil->data->{cgi}{host_name}{value}; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_host_name => $new_host_name }}); $anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "confirm-initialize-host", variables => { 'package' => $type eq "dr" ? "anvil-dr" : "anvil-node", - redhat => $rh_template, + redhat_message => $redhat_message, + redhat_form => $redhat_form, access => "root\@".$host_ip_address.":".$ssh_port, - host_name => $target_host_name, + current_host_name => $target_host_name, + new_host_name => $new_host_name, host_uuid => $target_host_uuid, default_host_name => $default_host_name, }}); diff --git a/html/skins/alteeve/anvil.html b/html/skins/alteeve/anvil.html index 12f3e540..d700adff 100644 --- a/html/skins/alteeve/anvil.html +++ b/html/skins/alteeve/anvil.html @@ -165,7 +165,7 @@   - #!variable!redhat!# + #!variable!redhat_message!# @@ -174,26 +174,35 @@ - - + + + + - + #!variable!redhat_form!#
#!string!striker_0125!#: - #!variable!access!# + + #!variable!access!#
#!string!striker_0126!#: - #!variable!host_name!# + + #!variable!current_host_name!# +
+ #!string!striker_0138!#: + + #!variable!new_host_name!#
#!string!striker_0127!#: - #!variable!host_uuid!# + + #!variable!host_uuid!#
#!string!striker_0098!# @@ -218,7 +227,7 @@
- + #!string!message_0148!# @@ -229,26 +238,23 @@   - - - + + + - + - + + - -
+ + #!string!message_0144!#: + -   +
+ #!string!message_0145!#: +
- - - - -   - - - + diff --git a/html/skins/alteeve/striker.html b/html/skins/alteeve/striker.html index e224c1ff..574ae609 100644 --- a/html/skins/alteeve/striker.html +++ b/html/skins/alteeve/striker.html @@ -1,19 +1,16 @@ - +     - #!variable!host!# - + #!variable!host!# - #!variable!user!# - +  -  - #!variable!target!# - - - - #!variable!file!# + #!variable!target!#   @@ -47,33 +44,27 @@ #!string!header_0015!# - - - #!string!header_0013!# - + +   #!string!header_0012!# - - - #!string!header_0014!# - - +   #!variable!bad_keys!# - +   - + diff --git a/rpm/SPECS/anvil.spec b/rpm/SPECS/anvil.spec index 6691fe20..66934a04 100644 --- a/rpm/SPECS/anvil.spec +++ b/rpm/SPECS/anvil.spec @@ -3,7 +3,7 @@ %define anvilgroup admin Name: anvil Version: 3.0 -Release: 26%{?dist} +Release: 27%{?dist} Summary: Alteeve Anvil! complete package. License: GPLv2+ @@ -287,6 +287,9 @@ firewall-cmd --add-service=postgresql --permanent %changelog +* tbd Madison Kelly 3.0-27 +- + * Wed Oct 02 2019 Madison Kelly 3.0-26 - Updated source diff --git a/share/words.xml b/share/words.xml index 1924cb5d..e92d1b2f 100644 --- a/share/words.xml +++ b/share/words.xml @@ -252,7 +252,7 @@ About to try to download aproximately: [#!variable!packages!#] packages needed t Red Hat password What kind of machine will this host be? current IP address and password?]]> - You can enter your Red Hat subscription credentials below.
The host will be subscribed during setup.]]>
+ The target's host key has changed. If the target has been rebuilt, or the target IP reused, the old key will need to be removed. If this is the case, remove line: [#!variable!line!#] from: [#!variable!file!#]. Set the new host name. @@ -764,6 +764,9 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a The anvil version cache file: [#!variable!file!#] for: [#!variable!target!#] needs to be created/updated. No databases available yet, continuing to wait. + The variable: [#!variable!name!#] is an array reference, but it doesn't have any entries in it. + The variable: [#!variable!name!#] was expected to be a positive integer, but: [#!variable!value!#] was received. + The domain: [#!variable!name!#] does not appear to be a valid domain name or an ipv4 IP address. Skipping it. Test @@ -930,8 +933,8 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st Prepare Node or DR Host Please enter the IP address and root password of the target machine you want to configure. 'root' Password - If you initialize, the target will have the Alteeve repo added and: [#!variable!package!#] installed.
The target will be configured to use this and our peer's databases.]]>
- Initialize Host + + Host to Initialize Current host name Host UUID Initialize @@ -950,6 +953,8 @@ The machines responding when we try to connect to the targets below are respondi
If you are comfortable that the target has changed for a known reason, you can select the broken keys below to have them removed.
]]> + New host name + ]]> #!variable!number!#/sec @@ -1014,10 +1019,10 @@ Failure! The return code: [#!variable!return_code!#] was received ('0' was expec Verifying installation. [ Failed ] - There may be more information in #!data!path::log::file!#. Success! - Adding our database connection information to the target's anvil.conf file! + Adding our database connection information to the target's anvil.conf file. Finished! The target should be ready for initial configuration shortly. If it isn't, please check that the 'anvil-daemon' daemon is running. Removing bad machine keys. - Removing line: [#!variable!line!#] from: [#!variable!file!#] for the target machine: [#!variable!target!#]. + Removing existing entries for the target machine: [#!variable!target!#] from: [#!variable!file!#]. [ Error ] - The known hosts file: [#!variable!file!#] was not found. Skipping it. Finished. [ Error ] - There was a problem reading the known hosts file: [#!variable!file!#]. Skipping it. diff --git a/tools/anvil-manage-keys b/tools/anvil-manage-keys index a55dbbd4..34ef6d44 100755 --- a/tools/anvil-manage-keys +++ b/tools/anvil-manage-keys @@ -128,7 +128,8 @@ WHERE next; } - ### NOTE: We don't need the line anymore, but we're not removing it yet. + ### NOTE: We don't need the file or line anymore, but we're not removing it as having + ### a record of the trigger might be useful someday. # Pull out the details. my $bad_file = ""; my $bad_line = ""; @@ -151,125 +152,164 @@ WHERE $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_line => $bad_line }}); } } - my ($target, $user) = ($state_name =~ /host_key_changed::(.*)::(.*)$/); + my ($target) = ($state_name =~ /host_key_changed::(.*)$/); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target, - user => $user, bad_file => $bad_file, bad_line => $bad_line, }}); - $anvil->data->{job}{progress} += 5; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0049,!!line!:".$bad_line."!!,!!file!".$bad_file."!!,!!target!".$target."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0049", variables => { - line => $bad_line, - file => $bad_file, - target => $target, - }}); + # Read in the specified bad file, then find any other files that might have matching bad keys. + process_file($anvil, "/root/.ssh/known_hosts", $target); - # Read in the file, if it exists. - if (not -e $bad_file) + # Walk through any other users. + my $directory = "/home"; + local(*DIRECTORY); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) { - $anvil->data->{job}{progress} += 10; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0050,!!file!".$bad_file."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0050", variables => { file => $bad_file }}); - - # Remove this job and go on to the next bad key (if any). - delete_state($anvil, $state_uuid); - next; - } - - # Read in the file - my ($old_body) = $anvil->Storage->read_file({file => $bad_file}); - if ($old_body eq "!!error!!") - { - # Failed to read the file - $anvil->data->{job}{progress} += 10; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0052,!!file!".$bad_file."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0052", variables => { file => $bad_file }}); - - # Remove this job and go on to the next bad key (if any). - delete_state($anvil, $state_uuid); - next; - } - - # Find our key - my $line_number = 0; - my $new_body = ""; - my $update = 0; - foreach my $line (split/\n/, $old_body) - { - $line_number++; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:line_number' => $line_number, - 's2:bad_line' => $bad_line, - 's3:line' => $line, + next if $file eq "."; + next if $file eq ".."; + my $full_path = $directory."/".$file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + file => $file, + full_path => $full_path, }}); - # If the line starts with our target, remove it. - if ($line =~ /^$target /) + # If we're looking at a directory, scan it. Otherwise, see if it's an executable and that it + # starts with 'scan-*'. + if (-d $full_path) { - # Found it! - $anvil->data->{job}{progress} += 5; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0053,!!line!".$line_number."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0053", variables => { line => $line_number }}); - $update = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); - } - else - { - $new_body .= $line."\n"; + # Check for a known_hosts file. + my $known_hosts = $full_path."/.ssh/known_hosts"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { known_hosts => $known_hosts }}); + if (-e $known_hosts) + { + process_file($anvil, $known_hosts, $target); + } } } + closedir(DIRECTORY); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:old_body' => $old_body, - 's2:new_body' => $new_body, - 's3:update' => $update, - }}); - if ($update) - { - # Write the file out. - $anvil->data->{job}{progress} += 5; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0055,!!file!".$bad_file."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0055", variables => { file => $bad_file }}); - - # Get the owning user and group. - my ($owning_uid, $owning_gid) = (stat($bad_file))[4,5]; - my $owning_user = getpwuid($owning_uid); - my $owning_group = getpwuid($owning_gid); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - owning_uid => $owning_uid, - owning_gid => $owning_gid, - owning_user => $owning_user, - owning_group => $owning_group, - }}); - - my $error = $anvil->Storage->write_file({ - body => $new_body, - debug => 2, - file => $bad_file, - overwrite => 1, - user => $owning_user, - group => $owning_group - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { error => $error }}); - if ($error) - { - $anvil->data->{job}{progress} += 5; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0059,!!file!".$bad_file."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0059", variables => { file => $bad_file }}); - } - else - { - # Success! - delete_state($anvil, $state_uuid); - $anvil->data->{job}{progress} += 5; - update_progress($anvil, $anvil->data->{job}{progress}, "job_0060,!!file!".$bad_file."!!"); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0060", variables => { file => $bad_file }}); - } - } + delete_state($anvil, $state_uuid); + } + } + + return(0); +} + +# Look through the file for bad keys. +sub process_file +{ + my ($anvil, $file, $target) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + file => $file, + target => $target, + }}); + + $anvil->data->{job}{progress} += 5; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0049,!!file!".$file."!!,!!target!".$target."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0049", variables => { + file => $file, + target => $target, + }}); + + # Read in the file, if it exists. + if (not -e $file) + { + # File doesn't actually exist, wtf? + $anvil->data->{job}{progress} += 10; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0050,!!file!".$file."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0050", variables => { file => $file }}); + + return(1); + } + + # Read in the file + my ($old_body) = $anvil->Storage->read_file({file => $file}); + if ($old_body eq "!!error!!") + { + # Failed to read the file + $anvil->data->{job}{progress} += 5; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0052,!!file!".$file."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0052", variables => { file => $file }}); + + return(1); + } + + # Find our key(s) + my $line_number = 0; + my $new_body = ""; + my $update = 0; + foreach my $line (split/\n/, $old_body) + { + $line_number++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:line_number' => $line_number, + 's2:line' => $line, + }}); + + # If the line starts with our target, remove it. + if ($line =~ /^$target /) + { + # Found it! + $anvil->data->{job}{progress} += 5; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0053,!!line!".$line_number."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0053", variables => { line => $line_number }}); + $update = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); + } + else + { + $new_body .= $line."\n"; + } + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:old_body' => $old_body, + 's2:new_body' => $new_body, + 's3:update' => $update, + }}); + if ($update) + { + # Write the file out. + $anvil->data->{job}{progress} += 5; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0055,!!file!".$file."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0055", variables => { file => $file }}); + + # Get the owning user and group. + my ($owning_uid, $owning_gid) = (stat($file))[4,5]; + my $owning_user = getpwuid($owning_uid); + my $owning_group = getpwuid($owning_gid); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + owning_uid => $owning_uid, + owning_gid => $owning_gid, + owning_user => $owning_user, + owning_group => $owning_group, + }}); + + my $error = $anvil->Storage->write_file({ + body => $new_body, + debug => 3, + file => $file, + overwrite => 1, + user => $owning_user, + group => $owning_group + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { error => $error }}); + if ($error) + { + $anvil->data->{job}{progress} += 5; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0059,!!file!".$file."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0059", variables => { file => $file }}); + } + else + { + # Success! + $anvil->data->{job}{progress} += 5; + update_progress($anvil, $anvil->data->{job}{progress}, "job_0060,!!file!".$file."!!"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0060", variables => { file => $file }}); } } @@ -364,7 +404,7 @@ sub delete_state if ($state_uuid) { my $query = "DELETE FROM states WHERE state_uuid = ".$anvil->Database->quote($state_uuid).";"; - $anvil->Database->write({debug => 2, query => $query, source => $THIS_FILE, line => __LINE__}); + $anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); } return(0); diff --git a/tools/striker-get-peer-data b/tools/striker-get-peer-data index 6ca1e7f0..e455212d 100755 --- a/tools/striker-get-peer-data +++ b/tools/striker-get-peer-data @@ -72,9 +72,16 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list 'target::password' => $anvil->Log->is_secure($anvil->data->{target}{password}), }}); -my ($host_uuid) = get_host_uuid($anvil); -my ($host_name) = get_host_name($anvil); -my ($host_os,, $os_registered) = get_host_os($anvil); +my ($host_uuid) = get_host_uuid($anvil); +my ($host_name) = get_host_name($anvil); +my ($host_os, $os_registered) = get_host_os($anvil); +my $internet = $anvil->Network->check_internet({ + remote_user => $anvil->data->{target}{user}, + target => $anvil->data->{target}{host}, + port => $anvil->data->{target}{port}, + password => $anvil->data->{target}{password}, + tries => 1, +}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid, host_name => $host_name, @@ -86,6 +93,7 @@ print "host_name=".$host_name."\n"; print "host_uuid=".$host_uuid."\n"; print "host_os=".$host_os."\n"; print "os_registered=".$os_registered."\n"; +print "internet=".$internet."\n"; $anvil->nice_exit({code => 0}); @@ -139,14 +147,14 @@ fi; # Is it subscribed? This isn't the best call to make, but it seems to be the one that returns # the fastest. Return code of '0' is registered, return code of '1' is not or not verified. my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, + debug => 2, shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." identity", user => $anvil->data->{target}{user}, target => $anvil->data->{target}{host}, port => $anvil->data->{target}{port}, password => $anvil->data->{target}{password}, }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, error => $error, return_code => $return_code, diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host index 078b239b..289fe1f3 100755 --- a/tools/striker-initialize-host +++ b/tools/striker-initialize-host @@ -175,8 +175,7 @@ sub add_databases last if $db_host; } - ### TODO: Left off here. The password written to the target isn't right. Also, host.uuid is failing to be written. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { db_host => $db_host }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_host => $db_host }}); if ($db_host) { my $failed = $anvil->Database->manage_anvil_conf({ @@ -204,6 +203,13 @@ sub add_databases update_progress($anvil, 100, "job_0047"); } } + else + { + ### TODO: LEft off here; change the message to a proper one. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0076"}); + update_progress($anvil, 100, "error_0076"); + $anvil->nice_exit({exit_code => 6}); + } return(0); } @@ -557,10 +563,14 @@ sub wait_for_access { my ($anvil) = @_; + ### TODO: If the keys changed, the user may have been prompted to fix the keys for the admin user, + ### but not the 'root' user. This, we may fail to access the node as this runs as 'root'. Tell + ### the user to check for bad keys and clear them if/when access fails. # Test access $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0023", variables => { target => $anvil->data->{data}{say_target} }}); $anvil->data->{job}{progress} += 5; update_progress($anvil, $anvil->data->{job}{progress}, "job_0023,!!target!".$anvil->data->{data}{say_target}."!!"); + $anvil->data->{job}{progress} += 5; my $waiting = 1; my $access = 0; my $timeout = time + 600; @@ -597,7 +607,6 @@ sub wait_for_access target => $anvil->data->{data}{say_target}, timeout => $time_left, }}); - $anvil->data->{job}{progress} += 5; update_progress($anvil, $anvil->data->{job}{progress}, "job_0025,!!target!".$anvil->data->{data}{say_target}."!!,!!timeout!".$time_left."!!"); sleep 5; }