From b9a0cc4d56fe3adb3188193c3561c25cb21340e7 Mon Sep 17 00:00:00 2001 From: Digimer Date: Sun, 22 Sep 2019 23:36:59 -0400 Subject: [PATCH] * Finished the initial tools/striker-initialize-host! * Created Tools->refresh to reload anvil.conf in one call. * Created Anvil::Tools::Network to hold network-related tasks. ** Created Network->is_remote() that tests to see if a string (containing a target) refers to the remote machine (versus a local machine). Updated all previous checks to use this new method. ** Moved Get->network_details() and Get->network() to the new Network module. Renamed Get->network() to Network->get_network(). ** Made Network->get_ips() work locally and remotely. ** Created Network->find_matches() that compares two scanned machines IPs (via two previous calls to Network->get_ips()) * Created Database->manage_anvil_conf() that will add, update or remove a given database connection in a local or remote anvil.conf file. * Fixed bugs in Storage->backup() where the bash calls were quite broken. I'm not sure how it ever worked before... x_x * Updated anvil-daemon to not initialize a database unless it's running on dashboard. Also added a check at the startup of anvil-daemon where it will go into a loop waiting for a database to become available, re-reading anvil.conf each loop. Signed-off-by: Digimer --- Anvil/Tools.pm | 37 ++ Anvil/Tools/DRBD.pm | 10 +- Anvil/Tools/Database.pm | 450 +++++++++++++++++- Anvil/Tools/Get.pm | 129 +----- Anvil/Tools/Network.pm | 676 ++++++++++++++++++++++++++++ Anvil/Tools/Server.pm | 4 +- Anvil/Tools/Storage.pm | 26 +- Anvil/Tools/Striker.pm | 12 +- Anvil/Tools/System.pm | 269 +---------- cgi-bin/striker | 18 +- notes | 5 + share/words.xml | 5 + tools/anvil-configure-host | 2 +- tools/anvil-daemon | 72 ++- tools/anvil-manage-files | 18 +- tools/anvil-manage-firewall | 16 +- tools/anvil-update-states | 30 +- tools/striker-initialize-host | 220 ++++++--- tools/striker-manage-install-target | 16 +- 19 files changed, 1456 insertions(+), 559 deletions(-) create mode 100755 Anvil/Tools/Network.pm diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 85accc2c..fea915a3 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -23,6 +23,7 @@ my $THIS_FILE = "Tools.pm"; # data # environment # nice_exit +# refresh # _add_hash_reference # _anvil_version # _hostname @@ -46,6 +47,7 @@ use Anvil::Tools::DRBD; use Anvil::Tools::Get; use Anvil::Tools::Job; use Anvil::Tools::Log; +use Anvil::Tools::Network; use Anvil::Tools::Remote; use Anvil::Tools::Server; use Anvil::Tools::Striker; @@ -126,6 +128,7 @@ sub new GET => Anvil::Tools::Get->new(), LOG => Anvil::Tools::Log->new(), JOB => Anvil::Tools::Job->new(), + NETWORK => Anvil::Tools::Network->new(), REMOTE => Anvil::Tools::Remote->new(), SERVER => Anvil::Tools::Server->new(), STRIKER => Anvil::Tools::Striker->new(), @@ -166,6 +169,7 @@ sub new $anvil->Get->parent($anvil); $anvil->Log->parent($anvil); $anvil->Job->parent($anvil); + $anvil->Network->parent($anvil); $anvil->Remote->parent($anvil); $anvil->Server->parent($anvil); $anvil->Striker->parent($anvil); @@ -407,6 +411,26 @@ sub nice_exit exit($exit_code); } +=head2 refresh + +This method re-reads the configuration file and resets paths, defaults and re-reads the words file(s). + +=cut +sub refresh +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + + $anvil->_set_paths(); + $anvil->_set_defaults(); # This reset the log level + $anvil->Storage->read_config(); # This reset the log level also + $anvil->Get->switches; # Re-read to let switches override again. + $anvil->Words->read(); + + return(0); +} ############################################################################################################# # Public methods used to access sub modules. # @@ -514,6 +538,18 @@ sub Log return ($self->{HANDLE}{LOG}); } +=head2 Network + +Access the C methods via 'C<< $anvil->Network->method >>'. + +=cut +sub Network +{ + my $self = shift; + + return ($self->{HANDLE}{NETWORK}); +} + =head2 Remote Access the C methods via 'C<< $anvil->Remote->method >>'. @@ -1063,6 +1099,7 @@ sub _set_paths 'iptables-save' => "/usr/sbin/iptables-save", journalctl => "/usr/bin/journalctl", logger => "/usr/bin/logger", + ls => "/usr/bin/ls", lvchange => "/usr/sbin/lvchange", lvs => "/usr/sbin/lvs", lvscan => "/usr/sbin/lvscan", diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm index 8ae4ed05..f1756228 100755 --- a/Anvil/Tools/DRBD.pm +++ b/Anvil/Tools/DRBD.pm @@ -186,7 +186,7 @@ sub allow_two_primaries my $shell_call = $anvil->data->{path}{exe}{drbdsetup}." net-options ".$resource." ".$target_node_id." --allow-two-primaries=yes"; my $output = ""; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. ($output, my $error, $return_code) = $anvil->Remote->call({ @@ -273,7 +273,7 @@ sub get_devices my $host = $anvil->_short_hostname; my $shell_call = $anvil->data->{path}{exe}{drbdadm}." dump-xml"; my $output = ""; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. ($output, my $error, $anvil->data->{drbd}{'drbdadm-xml'}{return_code}) = $anvil->Remote->call({ @@ -544,7 +544,7 @@ sub get_status my $shell_call = $anvil->data->{path}{exe}{drbdsetup}." status --json"; my $output = ""; my $host = $anvil->_short_hostname(); - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Clear the hash where we'll store the data. $host = $target; @@ -817,7 +817,7 @@ sub manage_resource my $shell_call = $anvil->data->{path}{exe}{drbdadm}." ".$task." ".$resource; my $output = ""; my $return_code = 255; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. ($output, my $error, $return_code) = $anvil->Remote->call({ @@ -906,7 +906,7 @@ sub reload_defaults $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 2, key => "log_0355"}); my $shell_call = $anvil->data->{path}{exe}{drbdadm}." adjust ".$resource; my $output = ""; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. ($output, my $error, $return_code) = $anvil->Remote->call({ diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index f230589e..41c053b2 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -40,6 +40,7 @@ my $THIS_FILE = "Database.pm"; # insert_or_update_variables # lock_file # locking +# manage_anvil_conf # mark_active # query # quote @@ -1653,7 +1654,7 @@ sub get_local_uuid $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_local_uuid()" }}); my $local_uuid = ""; - my $network_details = $anvil->Get->network_details; + my $network_details = $anvil->Network->get_network_details; foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -5648,6 +5649,453 @@ sub locking return($set); } +=head2 manage_anvil_conf + +This adds, removes or updates a database entry in a machine's anvil.conf file. This returns C<< 0 >> on success, C<< 1 >> if there was a problem. + +Parameters; + +=head3 db_host (required) + +This is the IP address or host name of the database server. + +=head3 db_host_uuid (required) + +This is the C<< host_uuid >> of the server hosting the database we will be managing. + +=head3 db_password (required) + +This is the password used to log into the database. + +=head3 db_ping (optional, default '1') + +This sets whether the target will ping the DB server before trying to connect. See C<< Database->connect >> for more information. + +=head3 db_port (optional, default '5432') + +This is the port used to connect to the database server. + +=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). + +B<< NOTE >>: Do not confuse this with C<< db_password >>. This is the password to log into the remote machine being managed. + +=head3 port (optional, default 22) + +If C<< target >> is set, this is the TCP port number used to connect to the remote machine. + +B<< NOTE >>: Do not confuse this with C<< db_port >>. This is the port used to SSH into a 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. + +B<< NOTE >>: Do not confuse this with C<< db_user >>. This is the user to use when logging into the machine being managed. + +=head3 remove (optional, default '0') + +If set to C<< 1 >>, any existing extries for C<< host_uuid >> will be removed from that machine being managed. + +B<< NOTE >>: When this is set to C<< 1 >>, C<< db_password >> and C<< db_host >> are not required. + +=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. + +The file will be copied to the local system using C<< $anvil->Storage->rsync() >> and stored in C<< /tmp/. >>. if C<< cache >> is set, the file will be preserved locally. Otherwise it will be deleted once it has been read into memory. + +B<< Note >>: the temporary file will be prefixed with the path to the file name, with the C<< / >> converted to C<< _ >>. + +=cut +sub manage_anvil_conf +{ + 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 => "Database->manage_anvil_conf()" }}); + + my $db_password = defined $parameter->{db_password} ? $parameter->{db_password} : ""; + my $db_ping = defined $parameter->{db_ping} ? $parameter->{db_ping} : 1; + my $db_port = defined $parameter->{db_port} ? $parameter->{db_port} : 5432; + my $db_host = defined $parameter->{db_host} ? $parameter->{db_host} : ""; + my $db_host_uuid = defined $parameter->{db_host_uuid} ? $parameter->{db_host_uuid} : ""; + 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 $remove = defined $parameter->{remove} ? $parameter->{remove} : 0; + my $target = defined $parameter->{target} ? $parameter->{target} : "local"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + db_password => $anvil->Log->is_secure($db_password), + db_ping => $db_ping, + db_port => $db_port, + db_host_uuid => $db_host_uuid, + password => $anvil->Log->is_secure($password), + port => $port, + remote_user => $remote_user, + remove => $remove, + target => $target, + }}); + + if (not $db_host_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->manage_anvil_conf()", parameter => "db_host_uuid" }}); + return(1); + } + elsif (not $anvil->Validate->is_uuid({uuid => $db_host_uuid})) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0031", variables => { db_host_uuid => $db_host_uuid }}); + return(1); + } + if (not $remove) + { + if (not $db_host) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->manage_anvil_conf()", parameter => "db_host" }}); + return(0); + } + if (not $db_password) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->manage_anvil_conf()", parameter => "db_password" }}); + return(0); + } + } + + # Read in the anvil.conf + my ($anvil_conf) = $anvil->Storage->read_file({ + debug => $debug, + file => $anvil->data->{path}{configs}{'anvil.conf'}, + force_read => 1, + port => $port, + password => $anvil->Log->is_secure($password), + remote_user => $remote_user, + secure => 1, + target => $target, + }); + + if ($anvil_conf eq "!!error!!") + { + # Something went wrong. + return(1); + } + + # Now walk through the file and look for '### end db list ###' + my $rewrite = 0; + my $host_variable = "database::${db_host_uuid}::host"; + my $host_different = 1; + my $port_variable = "database::${db_host_uuid}::port"; + my $port_different = 1; + my $password_variable = "database::${db_host_uuid}::password"; + my $password_different = 1; + my $ping_variable = "database::${db_host_uuid}::ping"; + my $ping_different = 1; + my $delete_reported = 0; + my $update_reported = 0; + my $new_body = ""; + my $just_deleted = 0; + my $test_line = "database::${db_host_uuid}::"; + my $insert = ""; + my $host_seen = 0; + + # If we're not removing, and we don't find the entry at all, this will be inserted. + if (not $remove) + { + $insert = $host_variable." = ".$db_host."\n"; + $insert .= $port_variable." = ".$port."\n"; + $insert .= $password_variable." = ".$password."\n"; + $insert .= $ping_variable." = ".$db_ping."\n"; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host_variable => $host_variable, + port_variable => $port_variable, + password_variable => $anvil->Log->is_secure($password_variable), + ping_variable => $ping_variable, + insert => $anvil->Log->is_secure($insert), + test_line => $test_line, + }}); + + foreach my $line (split/\n/, $anvil_conf) + { + # Secure password lines ? + my $secure = (($line =~ /password/) && ($line !~ /^#/)) ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => $secure, level => $debug, list => { line => $line }}); + + # If I removed an entry, I also want to delete the white space after it. + if (($just_deleted) && ((not $line) or ($line =~ /^\s+$/))) + { + $just_deleted = 0; + next; + } + $just_deleted = 0; + + # If we've hit the end of the DB list, see if we need to insert a new entry. + if ($line eq "### end db list ###") + { + # If I've not seen this DB, enter it. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 0, level => 2, list => { + host_seen => $host_seen, + remove => $remove, + }}); + if ((not $host_seen) && (not $remove)) + { + $new_body .= $insert."\n"; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 1, level => 2, list => { + new_body => $new_body, + rewrite => $rewrite, + }}); + } + } + + # Now Skip any more comments. + if ($line =~ /^#/) + { + $new_body .= $line."\n"; + next; + } + # Process lines with the 'var = val' format + if ($line =~ /^(.*?)(\s*)=(\s*)(.*)$/) + { + my $variable = $1; + my $left_space = $2; + my $right_space = $3; + my $value = $4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:variable" => $variable, + "s2:value" => $value, + "s3:left_space" => $left_space, + "s4:right_space" => $right_space, + }}); + + # Is the the host line we're possibly updating? + if ($variable eq $host_variable) + { + # Yup. Are we removing it, or do we need to edit it? + $host_seen = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:value" => $value, + "s2:db_host" => $db_host, + "s3:host_seen" => $host_seen, + }}); + if ($remove) + { + # Remove the line + $delete_reported = 1; + $just_deleted = 1; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + just_deleted => $just_deleted, + rewrite => $rewrite, + delete_reported => $delete_reported, + }}); + next; + } + elsif ($value eq $db_host) + { + # No change. + $host_different = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_different => $host_different }}); + } + else + { + # Needs to be updated. + $line = $variable.$left_space."=".$right_space.$db_host; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + line => $line, + rewrite => $rewrite, + }}); + } + } + elsif ($variable eq $port_variable) + { + # Port line + $host_seen = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:value" => $value, + "s2:port" => $port, + "s3:host_seen" => $host_seen, + }}); + if ($remove) + { + # Remove it + $delete_reported = 1; + $just_deleted = 1; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + delete_reported => $delete_reported, + just_deleted => $just_deleted, + rewrite => $rewrite, + }}); + next; + } + elsif ($value eq $port) + { + # No change. + $port_different = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { port_different => $port_different }}); + } + else + { + # Needs to be updated. + $update_reported = 1; + $line = $variable.$left_space."=".$right_space.$port; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + update_reported => $update_reported, + line => $line, + rewrite => $rewrite, + }}); + } + } + elsif ($variable eq $password_variable) + { + # Password + $host_seen = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { + "s1:value" => $value, + "s2:password" => $anvil->Log->is_secure($password), + "s3:host_seen" => $host_seen, + }}); + if ($remove) + { + # Remove it + $delete_reported = 1; + $just_deleted = 1; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + delete_reported => $delete_reported, + just_deleted => $just_deleted, + rewrite => $rewrite, + }}); + next; + } + elsif ($value eq $password) + { + # No change. + $password_different = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { password_different => $password_different }}); + } + else + { + # Changed, update it + $update_reported = 1; + $line = $variable.$left_space."=".$right_space.$password; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + update_reported => $update_reported, + line => $anvil->Log->is_secure($line), + rewrite => $rewrite, + }}); + } + } + elsif ($variable eq $ping_variable) + { + # Ping? + $host_seen = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:value" => $value, + "s2:db_ping" => $db_ping, + "s3:host_seen" => $host_seen, + }}); + if ($remove) + { + # Remove it + $delete_reported = 1; + $just_deleted = 1; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + delete_reported => $delete_reported, + just_deleted => $just_deleted, + rewrite => $rewrite, + }}); + next; + } + elsif ($value eq $db_ping) + { + # No change. + $ping_different = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ping_different => $ping_different }}); + } + else + { + # Changed, update + $update_reported = 1; + $line = $variable.$left_space."=".$right_space.$db_ping; + $rewrite = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + update_reported => $update_reported, + line => $line, + rewrite => $rewrite, + }}); + } + } + } + # Add the (modified?) line to the new body. + $new_body .= $line."\n"; + } + + # If there was a change, write the file out. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:new_body' => $new_body, + 's2:rewrite' => $rewrite, + }}); + + if ($rewrite) + { + # Backup the original + my $backup_file = $anvil->Storage->backup({ + debug => 2, + secure => 1, + file => $anvil->data->{path}{configs}{'anvil.conf'}, + password => $password, + port => $port, + remote_user => $remote_user, + target => $target, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }}); + + # Now update! + my ($failed) = $anvil->Storage->write_file({ + secure => 1, + file => $anvil->data->{path}{configs}{'anvil.conf'}, + body => $new_body, + user => "admin", + group => "admin", + mode => "0644", + overwrite => 1, + password => $anvil->Log->is_secure($password), + port => $port, + remote_user => $remote_user, + target => $target, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); + if ($failed) + { + # Simething went weong. + return(1); + } + + # If this is a local update, disconnect (if no connections exist, will still clear out known + # databases), the re-read the new config. + if (not $anvil->Network->is_remote($target)) + { + $anvil->Database->disconnect; + + # Re-read the config. + sleep 1; + $anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}}); + + # Reconnect + $anvil->Database->connect(); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); + } + } + + return(0); +} + =head2 mark_active This sets or clears that the caller is about to work on the database diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 85247b6f..81a338b6 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -20,8 +20,6 @@ my $THIS_FILE = "Get.pm"; # date_and_time # host_uuid # md5sum -# network -# network_details # switches # users_home # uuid @@ -136,7 +134,7 @@ sub anvil_version }}); # Is this a local call or a remote call? - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. If we're running as the apache user, we need to read the cached version for # the peer. otherwise, after we read the version, will write the cached version. @@ -692,131 +690,6 @@ sub md5sum return($sum); } -=head2 network - -This takes an IP address and subnet and returns the network it belongs too. For example; - - my $network = $anvil->Get->network({ip => "10.2.4.1", subnet => "255.255.0.0"}); - -This would set C<< $network >> to C<< 10.2.0.0 >>. - -If the network can't be caluclated for any reason, and empty string will be returned. - -Parameters; - -=head3 ip (required) - -This is the IPv4 IP address being calculated. - -=head3 subnet (required) - -This is the subnet of the IP address being calculated. - -=cut -sub network -{ - my $self = shift; - my $parameter = shift; - my $anvil = $self->parent; - my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - - my $network = ""; - my $ip = defined $parameter->{ip} ? $parameter->{ip} : ""; - my $subnet = defined $parameter->{subnet} ? $parameter->{subnet} : ""; - - if (not $ip) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->network()", parameter => "ip" }}); - } - if (not $subnet) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->network()", parameter => "subnet" }}); - } - - my $block = Net::Netmask->new($ip."/".$subnet); - my $base = $block->base(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { base => $base }}); - - if ($anvil->Validate->is_ipv4({ip => $base})) - { - $network = $base; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network => $network }}); - } - - return($network); -} - - -### TODO: Is this a waste of time / duplicate of System->get_ips()? -=head2 network_details - -This method returns the local hostname and IP addresses. - -It returns a hash reference containing data in the following keys: - -C<< hostname >> = -C<< interface::::ip >> = -C<< interface::::netmask >> = - -=cut -sub network_details -{ - my $self = shift; - my $parameter = shift; - my $anvil = $self->parent; - my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - - my $network = {}; - my ($hostname, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{hostname}}); - (my $ip_addr_list, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ip}." addr list"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - hostname => $hostname, - ip_addr_list => $ip_addr_list, - }}); - $network->{hostname} = $hostname; - - my $in_interface = ""; - my $ip_address = ""; - my $subnet_mask = ""; - foreach my $line (split/\n/, $ip_addr_list) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - if ($line =~ /^\d+: (.*?):/) - { - $in_interface = $1; - $ip_address = ""; - $subnet_mask = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); - next if $in_interface eq "lo"; - $network->{interface}{$in_interface}{ip} = "--"; - $network->{interface}{$in_interface}{netmask} = "--"; - } - if ($in_interface) - { - next if $in_interface eq "lo"; - if ($line =~ /inet (.*?)\/(.*?) /) - { - $ip_address = $1; - $subnet_mask = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - ip_address => $ip_address, - subnet_mask => $subnet_mask, - }}); - - if ((($subnet_mask =~ /^\d$/) or ($subnet_mask =~ /^\d\d$/)) && ($subnet_mask < 25)) - { - $subnet_mask = $anvil->Convert->cidr({cidr => $subnet_mask}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { subnet_mask => $subnet_mask }}); - } - $network->{interface}{$in_interface}{ip} = $ip_address; - $network->{interface}{$in_interface}{netmask} = $subnet_mask; - } - } - } - - return($network); -} - =head2 switches This reads in the command line switches used to invoke the parent program. diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm new file mode 100755 index 00000000..b15bc4ed --- /dev/null +++ b/Anvil/Tools/Network.pm @@ -0,0 +1,676 @@ +package Anvil::Tools::Network; +# +# This module contains methods used to deal with networking stuff. +# + +use strict; +use warnings; +use Data::Dumper; +use Scalar::Util qw(weaken isweak); + +our $VERSION = "3.0.0"; +my $THIS_FILE = "Network.pm"; + +### Methods; +# find_matches +# get_ips +# get_network +# is_local + +=pod + +=encoding utf8 + +=head1 NAME + +Anvil::Tools::Network + +Provides all methods related to networking. + +=head1 SYNOPSIS + + use Anvil::Tools; + + # Get a common object handle on all Anvil::Tools modules. + my $anvil = Anvil::Tools->new(); + + # Access to methods using '$anvil->Storage->X'. + # + +=head1 METHODS + +Methods in this module; + +=cut +sub new +{ + my $class = shift; + my $self = { + }; + + bless $self, $class; + + return ($self); +} + +# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more +# sense in this case to think of it as a parent. +sub parent +{ + my $self = shift; + my $parent = shift; + + $self->{HANDLE}{TOOLS} = $parent if $parent; + + # Defend against memory leads. See Scalar::Util'. + if (not isweak($self->{HANDLE}{TOOLS})) + { + weaken($self->{HANDLE}{TOOLS}); + } + + return ($self->{HANDLE}{TOOLS}); +} + + +############################################################################################################# +# Public methods # +############################################################################################################# + +=head2 find_matches + +This takes two hash keys from prior C<< Network->get_ips() >> runs and finds which are on the same network. + +Paramters; + +=head3 first (required) + +This is the hash key of the first machine being compared. + +=head3 second (required) + +This is the hash key of the second machine being compared. + +=cut +sub find_matches +{ + 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 $first = defined $parameter->{first} ? $parameter->{first} : ""; + my $second = defined $parameter->{second} ? $parameter->{second} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + first => $first, + second => $second, + }}); + + if (ref($anvil->data->{network}{$first}) ne "HASH") + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "first" }}); + return(""); + } + if (ref($anvil->data->{network}{$second}) ne "HASH") + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "second" }}); + return(""); + } + + # Loop through the first, and on each interface with an IP/subnet, look for a match in the second. + my $match = {}; + foreach my $first_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$first}{interface}}) + { + my $first_ip = $anvil->data->{network}{$first}{interface}{$first_interface}{ip}; + my $first_subnet = $anvil->data->{network}{$first}{interface}{$first_interface}{subnet}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + first => $first, + first_interface => $first_interface, + first_ip => $first_ip, + first_subnet => $first_subnet, + }}); + + if (($first_ip) && ($first_subnet)) + { + # Look for a match. + my $first_network = $anvil->Network->get_network({ + debug => $debug, + ip => $first_ip, + subnet => $first_subnet, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { a_network => $first_network }}); + + foreach my $second_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$second}{interface}}) + { + my $second_ip = $anvil->data->{network}{$second}{interface}{$second_interface}{ip}; + my $second_subnet = $anvil->data->{network}{$second}{interface}{$second_interface}{subnet}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + second => $second, + second_interface => $second_interface, + second_ip => $second_ip, + second_subnet => $second_subnet, + }}); + if (($second_ip) && ($second_subnet)) + { + # Do we have a match? + my $second_network = $anvil->Network->get_network({ + debug => $debug, + ip => $second_ip, + subnet => $second_subnet, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + a_network => $first_network, + b_network => $second_network, + }}); + + if ($first_network eq $second_network) + { + # Match! + $match->{$first}{$first_interface} = $second_network; + $match->{$second}{$second_interface} = $second_network; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "${first}::${first_interface}" => $match->{$first}{$first_interface}, + "${second}::${second_interface}" => $match->{$second}{$second_interface}, + }}); + } + } + } + } + } + + return($match); +} + +=head2 get_ips + +This method checks the local system for interfaces and stores them in: + +* C<< network::::interface::::ip >> - If an IP address is set +* C<< network::::interface::::subnet >> - If an IP is set +* C<< network::::interface::::mac >> - Always set. +* C<< network::::interface::::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so. +* C<< network::::interface::::gateway >> = If the default gateway, this is the gateway IP address. +* C<< network::::interface::::dns >> = If the default gateway, this is the comma-separated list of active DNS servers. + +When called without a C<< target >>, C<< local >> is used. + +To aid in look-up by MAC address, C<< network::mac::::iface >> is also set. Note that this is not target-dependent. + +Parameters; + +=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. + +The file will be copied to the local system using C<< $anvil->Storage->rsync() >> and stored in C<< /tmp/. >>. if C<< cache >> is set, the file will be preserved locally. Otherwise it will be deleted once it has been read into memory. + +B<< Note >>: the temporary file will be prefixed with the path to the file name, with the C<< / >> converted to C<< _ >>. + +=cut +sub get_ips +{ + 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->get_ips()" }}); + + 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"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + password => $anvil->Log->is_secure($password), + port => $port, + remote_user => $remote_user, + target => $target, + }}); + + # Reading locally or remote? + my $in_iface = ""; + my $shell_call = $anvil->data->{path}{exe}{ip}." addr list"; + my $output = ""; + if ($anvil->Network->is_remote($target)) + { + # Remote call + ($output, my $error, my $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:error' => $error, + 's3:return_code' => $return_code, + }}); + } + else + { + # Local call. + ($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2: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+: (.*?): /) + { + $in_iface = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_iface => $in_iface }}); + + $anvil->data->{network}{$target}{interface}{$in_iface}{ip} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{ip}; + $anvil->data->{network}{$target}{interface}{$in_iface}{subnet} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{subnet}; + $anvil->data->{network}{$target}{interface}{$in_iface}{mac} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{mac}; + $anvil->data->{network}{$target}{interface}{$in_iface}{default_gateway} = 0 if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{default_gateway}; + $anvil->data->{network}{$target}{interface}{$in_iface}{gateway} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{gateway}; + $anvil->data->{network}{$target}{interface}{$in_iface}{dns} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{dns}; + } + next if not $in_iface; + if ($in_iface eq "lo") + { + # We don't care about 'lo'. + delete $anvil->data->{network}{$target}{interface}{$in_iface}; + next; + } + if ($line =~ /inet (.*?)\/(.*?) /) + { + my $ip = $1; + my $cidr = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ip => $ip, cidr => $cidr }}); + + my $subnet = $cidr; + if (($cidr =~ /^\d{1,2}$/) && ($cidr >= 0) && ($cidr <= 32)) + { + # Convert to subnet + $subnet = $anvil->Convert->cidr({cidr => $cidr}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { subnet => $subnet }}); + } + + $anvil->data->{network}{$target}{interface}{$in_iface}{ip} = $ip; + $anvil->data->{network}{$target}{interface}{$in_iface}{subnet} = $subnet; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "s1:network::${target}::interface::${in_iface}::ip" => $anvil->data->{network}{$target}{interface}{$in_iface}{ip}, + "s2:network::${target}::interface::${in_iface}::subnet" => $anvil->data->{network}{$target}{interface}{$in_iface}{subnet}, + }}); + } + if ($line =~ /ether ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}) /i) + { + my $mac = $1; + $anvil->data->{network}{$target}{interface}{$in_iface}{mac} = $mac; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "network::${target}::interface::${in_iface}::mac" => $anvil->data->{network}{$target}{interface}{$in_iface}{mac}, + }}); + + # We only record the mac in 'network::mac' if this isn't a bond. + my $test_file = "/proc/net/bonding/".$in_iface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_file => $test_file }}); + if (not -e $test_file) + { + $anvil->data->{network}{mac}{$mac}{iface} = $in_iface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "network::mac::${mac}::iface" => $anvil->data->{network}{mac}{$mac}{iface}, + }}); + } + } + } + + # Read the config files for the interfaces we've found. Use 'ls' to find the interface files. Then + # we'll read them all in. + $shell_call = $anvil->data->{path}{exe}{ls}." ".$anvil->data->{path}{directories}{ifcfg}; + $output = ""; + if ($anvil->Network->is_remote($target)) + { + # Remote call + ($output, my $error, my $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:error' => $error, + 's3:return_code' => $return_code, + }}); + } + else + { + # Local call. + ($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:return_code' => $return_code, + }}); + } + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + next if $line !~ /^ifcfg-/; + my $full_path = $anvil->data->{path}{directories}{ifcfg}."/".$line; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }}); + + my $file_body = $anvil->Storage->read_file({ + debug => $debug, + file => $full_path, + target => $target, + password => $password, + port => $port, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "s1:full_path" => $full_path, + "s2:file_body" => $file_body, + }}); + + # Break it apart and store any variables. + my $temp = {}; + my $interface = ""; + foreach my $line (split/\n/, $file_body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + next if $line =~ /^#/; + if ($line =~ /(.*?)=(.*)/) + { + my $variable = $1; + my $value = $2; + $value =~ s/^"(.*)"$/$1/; + $temp->{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "temp->{$variable}" => $temp->{$variable} }}); + + if (uc($variable) eq "DEVICE") + { + $interface = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "interface" => $interface }}); + } + } + + if ($interface) + { + $anvil->data->{network}{$target}{interface}{$interface}{file} = $full_path; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "network::${target}::interface::${interface}::file" => $anvil->data->{network}{$target}{interface}{$interface}{file}, + }}); + foreach my $variable (sort {$a cmp $b} keys %{$temp}) + { + $anvil->data->{network}{$target}{interface}{$interface}{variable}{$variable} = $temp->{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "network::${target}::interface::${interface}::file::variable::${variable}" => $anvil->data->{network}{$target}{interface}{$interface}{variable}{$variable}, + }}); + } + } + } + } + + # Get the routing info. + my $lowest_metric = 99999999; + my $route_interface = ""; + my $route_ip = ""; + $shell_call = $anvil->data->{path}{exe}{ip}." route show"; + $output = ""; + if ($anvil->Network->is_remote($target)) + { + # Remote call + ($output, my $error, my $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:error' => $error, + 's3:return_code' => $return_code, + }}); + } + else + { + # Local call. + ($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2: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 =~ /default via (.*?) dev (.*?) proto .*? metric (\d+)/i) + { + my $this_ip = $1; + my $this_interface = $2; + my $metric = $3; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:this_ip' => $this_ip, + 's2:this_interface' => $this_interface, + 's3:metric' => $metric, + 's4:lowest_metric' => $lowest_metric, + }}); + + if ($metric < $lowest_metric) + { + $lowest_metric = $metric; + $route_interface = $this_interface; + $route_ip = $this_ip; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + lowest_metric => $lowest_metric, + route_interface => $route_interface, + route_ip => $route_ip, + }}); + } + } + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + route_interface => $route_interface, + route_ip => $route_ip, + }}); + + # If I got a route, get the DNS. + if ($route_interface) + { + # I want to build the DNS list from only the interface that is used for routing. + my $in_interface = ""; + my $dns_list = ""; + my $dns_hash = {}; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." dev show"; + my $output = ""; + if ($anvil->Network->is_remote($target)) + { + # Remote call + ($output, my $error, my $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:error' => $error, + 's3:return_code' => $return_code, + }}); + } + else + { + # Local call. + ($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2: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 =~ /GENERAL.DEVICE:\s+(.*)$/) + { + $in_interface = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); + } + if (not $line) + { + $in_interface = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); + } + + next if $in_interface ne $route_interface; + + if ($line =~ /IP4.DNS\[(\d+)\]:\s+(.*)/i) + { + my $order = $1; + my $ip = $2; + + $dns_hash->{$order} = $ip; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "dns_hash->{$order}" => $dns_hash->{$order} }}); + } + } + + foreach my $order (sort {$a cmp $b} keys %{$dns_hash}) + { + $dns_list .= $dns_hash->{$order}.", "; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "s1:dns_hash->{$order}" => $dns_hash->{$order}, + "s2:dns_list" => $dns_list, + }}); + } + $dns_list =~ s/, $//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { dns_list => $dns_list }}); + + $anvil->data->{network}{$target}{interface}{$route_interface}{default_gateway} = 1; + $anvil->data->{network}{$target}{interface}{$route_interface}{gateway} = $route_ip; + $anvil->data->{network}{$target}{interface}{$route_interface}{dns} = $dns_list; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "network::${target}::interface::${route_interface}::default_gateway" => $anvil->data->{network}{$target}{interface}{$route_interface}{default_gateway}, + "network::${target}::interface::${route_interface}::gateway" => $anvil->data->{network}{$target}{interface}{$route_interface}{gateway}, + "network::${target}::interface::${route_interface}::dns" => $anvil->data->{network}{$target}{interface}{$route_interface}{dns}, + }}); + } + + return(0); +} + +=head2 get_network + +This takes an IP address and subnet and returns the network it belongs too. For example; + + my $network = $anvil->Network->get_network({ip => "10.2.4.1", subnet => "255.255.0.0"}); + +This would set C<< $network >> to C<< 10.2.0.0 >>. + +If the network can't be caluclated for any reason, and empty string will be returned. + +Parameters; + +=head3 ip (required) + +This is the IPv4 IP address being calculated. + +=head3 subnet (required) + +This is the subnet of the IP address being calculated. + +=cut +sub get_network +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + + my $network = ""; + my $ip = defined $parameter->{ip} ? $parameter->{ip} : ""; + my $subnet = defined $parameter->{subnet} ? $parameter->{subnet} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + ip => $ip, + subnet => $subnet, + }}); + + if (not $ip) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->get_network()", parameter => "ip" }}); + return(""); + } + if (not $subnet) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->get_network()", parameter => "subnet" }}); + return(""); + } + + my $block = Net::Netmask->new($ip."/".$subnet); + my $base = $block->base(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { base => $base }}); + + if ($anvil->Validate->is_ipv4({ip => $base})) + { + $network = $base; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network => $network }}); + } + + return($network); +} + +=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. + + if ($anvil->Network->is_remote($target)) + { + # Do something remotely + } + else + { + # Do something locally + } + +B<< NOTE >>: Unlike most methods, this one does not take a hash reference for the parameters. It takes the string directly. + +=cut +sub is_remote +{ + my $self = shift; + my $target = shift; + my $anvil = $self->parent; + + my $remote = 0; + if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + { + # It's a remote system + $remote = 1; + } + + return($remote); +} + +# =head3 +# +# Private Functions; +# +# =cut + +############################################################################################################# +# Private functions # +############################################################################################################# + +1; diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index 6890a807..046849d8 100755 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -229,7 +229,7 @@ sub find my $host = $anvil->_hostname; my $virsh_output = ""; my $return_code = ""; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. ($host, my $error, my $host_return_code) = $anvil->Remote->call({ @@ -357,7 +357,7 @@ sub get_status # Is this a local call or a remote call? my $shell_call = $anvil->data->{path}{exe}{virsh}." dumpxml ".$server; my $host = $anvil->_short_hostname; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote call. $host = $target; diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index f292dee6..47589bc2 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -156,7 +156,7 @@ sub backup source_file => $source_file, }}); - my $proceed = 0; + my $proceed = 0; my $target_file = ""; if (not $source_file) { @@ -171,11 +171,12 @@ sub backup if ($fatal) { $anvil->nice_exit({code => 1}); } } - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Make sure the source file exists, is a file and can be read. my $shell_call = " if [ -e '".$source_file."' ]; +then if [ -f '".$source_file."' ]; then if [ -r '".$source_file."' ]; @@ -668,19 +669,22 @@ sub copy_file file => $file, }}); - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Copying on a remote system. my $proceed = 1; my $shell_call = " if [ -e '".$source_file."' ]; +then ".$anvil->data->{path}{exe}{echo}." 'source file exists' else ".$anvil->data->{path}{exe}{echo}." 'source file not found' fi -if [ -d '".$target_file."' ]; +if [ -e '".$target_file."' ]; +then ".$anvil->data->{path}{exe}{echo}." 'target file exists' elif [ -d '".$directory."' ]; +then ".$anvil->data->{path}{exe}{echo}." 'target directory exists' else ".$anvil->data->{path}{exe}{echo}." 'target directory not found' @@ -726,7 +730,7 @@ fi"; }}); return(1); } - if (($line1 eq "source file exists") && (not $overwrite)) + if (($line1 eq "target file exists") && (not $overwrite)) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0046", variables => { method => "copy_file", @@ -984,7 +988,7 @@ sub make_directory $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { working_directory => $working_directory }}); # Are we working locally or remotely? - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Assemble the command my $shell_call = " @@ -1193,7 +1197,7 @@ sub move_file }}); } - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Copying on a remote system. my $proceed = 1; @@ -1561,7 +1565,7 @@ sub read_file } # Reading locally or remote? - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # Remote. Make sure the passed file is a full path and file name. if ($file !~ /^\/\w/) @@ -1913,7 +1917,7 @@ sub rsync # If local, call rsync directly. If remote, setup the rsync wrapper my $wrapper_script = ""; my $shell_call = $anvil->data->{path}{exe}{rsync}." ".$switches." ".$source." ".$destination; - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # If we didn't get a port, but the target is pre-configured for a port, use it. if ((not $parameter->{port}) && ($anvil->data->{hosts}{$target}{port})) @@ -2414,7 +2418,7 @@ sub update_config # Did we see the variable? if (not $seen) { - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0175", variables => { variable => $variable, @@ -2743,7 +2747,7 @@ sub write_file }}); # Now, are we writing locally or on a remote system? - if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) + if ($anvil->Network->is_remote($target)) { # If we didn't get a port, but the target is pre-configured for a port, use it. if ((not $parameter->{port}) && ($anvil->data->{hosts}{$target}{port})) diff --git a/Anvil/Tools/Striker.pm b/Anvil/Tools/Striker.pm index 77e14784..944c734b 100644 --- a/Anvil/Tools/Striker.pm +++ b/Anvil/Tools/Striker.pm @@ -134,21 +134,21 @@ sub get_local_repo } # What are my IPs? - $anvil->System->get_ips(); + $anvil->Network->get_ips(); my $base_url = ""; - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface => $interface }}); - if ($anvil->data->{sys}{network}{interface}{$interface}{ip}) + if ($anvil->data->{network}{'local'}{interface}{$interface}{ip}) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::network::interface::${interface}::ip" => $anvil->data->{sys}{network}{interface}{$interface}{ip} }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip} }}); if (not $base_url) { - $base_url = "baseurl=http://".$anvil->data->{sys}{network}{interface}{$interface}{ip}.$directory; + $base_url = "baseurl=http://".$anvil->data->{network}{'local'}{interface}{$interface}{ip}.$directory; } else { - $base_url .= "\n http://".$anvil->data->{sys}{network}{interface}{$interface}{ip}.$directory; + $base_url .= "\n http://".$anvil->data->{network}{'local'}{interface}{$interface}{ip}.$directory; } } } diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 7ca221e1..7fd8b9e0 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -27,7 +27,6 @@ my $THIS_FILE = "System.pm"; # get_host_type # enable_daemon # find_matching_ip -# get_ips # get_uptime # get_os_type # hostname @@ -958,7 +957,7 @@ sub get_host_type $host_type = $anvil->data->{sys}{host_type}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); } - elsif (($host_name =~ /n\d+$/) or ($host_name =~ /node\d+$/)) + elsif (($host_name =~ /n\d+$/) or ($host_name =~ /node\d+$/) or ($host_name =~ /new-node+$/)) { $host_type = "node"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); @@ -968,7 +967,7 @@ sub get_host_type $host_type = "dashboard"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); } - elsif ($host_name =~ /dr\d+$/) + elsif (($host_name =~ /dr\d+$/) or ($host_name =~ /new-dr$/)) { $host_type = "dr"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); @@ -1059,18 +1058,18 @@ sub find_matching_ip } # Get my local IPs - $anvil->System->get_ips({debug => $debug}); + $anvil->Network->get_ips({debug => $debug}); my $ip = NetAddr::IP->new($host); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ip => $ip }}); # Look through our IPs. First match wins. - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface => $interface }}); - next if not $anvil->data->{sys}{network}{interface}{$interface}{ip}; - my $this_ip = $anvil->data->{sys}{network}{interface}{$interface}{ip}; - my $this_subnet = $anvil->data->{sys}{network}{interface}{$interface}{subnet}; + next if not $anvil->data->{network}{'local'}{interface}{$interface}{ip}; + my $this_ip = $anvil->data->{network}{'local'}{interface}{$interface}{ip}; + my $this_subnet = $anvil->data->{network}{'local'}{interface}{$interface}{subnet}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "s1:this_ip" => $this_ip, "s2:this_subnet" => $this_subnet, @@ -1096,256 +1095,6 @@ sub find_matching_ip return($local_ip); } -=head2 get_ips - -This method checks the local system for interfaces and stores them in: - -* C<< sys::network::interface::::ip >> - If an IP address is set -* C<< sys::network::interface::::subnet >> - If an IP is set -* C<< sys::network::interface::::mac >> - Always set. -* C<< sys::network::interface::::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so. -* C<< sys::network::interface::::gateway >> = If the default gateway, this is the gateway IP address. -* C<< sys::network::interface::::dns >> = If the default gateway, this is the comma-separated list of active DNS servers. - -To aid in look-up by MAC address, C<< sys::mac::::iface >> is also set. - -No parameters are accepted by this method. - -=cut -sub get_ips -{ - 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->get_ips()" }}); - - my $in_iface = ""; - my ($ip_addr, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{ip}." addr list"}); - foreach my $line (split/\n/, $ip_addr) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - if ($line =~ /^\d+: (.*?): /) - { - $in_iface = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_iface => $in_iface }}); - - $anvil->data->{sys}{network}{interface}{$in_iface}{ip} = "" if not defined $anvil->data->{sys}{network}{interface}{$in_iface}{ip}; - $anvil->data->{sys}{network}{interface}{$in_iface}{subnet} = "" if not defined $anvil->data->{sys}{network}{interface}{$in_iface}{subnet}; - $anvil->data->{sys}{network}{interface}{$in_iface}{mac} = "" if not defined $anvil->data->{sys}{network}{interface}{$in_iface}{mac}; - $anvil->data->{sys}{network}{interface}{$in_iface}{default_gateway} = 0 if not defined $anvil->data->{sys}{network}{interface}{$in_iface}{default_gateway}; - $anvil->data->{sys}{network}{interface}{$in_iface}{gateway} = "" if not defined $anvil->data->{sys}{network}{interface}{$in_iface}{gateway}; - $anvil->data->{sys}{network}{interface}{$in_iface}{dns} = "" if not defined $anvil->data->{sys}{network}{interface}{$in_iface}{dns}; - } - next if not $in_iface; - if ($in_iface eq "lo") - { - # We don't care about 'lo'. - delete $anvil->data->{sys}{network}{interface}{$in_iface}; - next; - } - if ($line =~ /inet (.*?)\/(.*?) /) - { - my $ip = $1; - my $cidr = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ip => $ip, cidr => $cidr }}); - - my $subnet = $cidr; - if (($cidr =~ /^\d{1,2}$/) && ($cidr >= 0) && ($cidr <= 32)) - { - # Convert to subnet - $subnet = $anvil->Convert->cidr({cidr => $cidr}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { subnet => $subnet }}); - } - - $anvil->data->{sys}{network}{interface}{$in_iface}{ip} = $ip; - $anvil->data->{sys}{network}{interface}{$in_iface}{subnet} = $subnet; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:sys::network::interface::${in_iface}::ip" => $anvil->data->{sys}{network}{interface}{$in_iface}{ip}, - "s2:sys::network::interface::${in_iface}::subnet" => $anvil->data->{sys}{network}{interface}{$in_iface}{subnet}, - }}); - } - if ($line =~ /ether ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}) /i) - { - my $mac = $1; - $anvil->data->{sys}{network}{interface}{$in_iface}{mac} = $mac; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::network::interface::${in_iface}::mac" => $anvil->data->{sys}{network}{interface}{$in_iface}{mac}, - }}); - - # We only record the mac in 'sys::mac' if this isn't a bond. - my $test_file = "/proc/net/bonding/".$in_iface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_file => $test_file }}); - if (not -e $test_file) - { - $anvil->data->{sys}{mac}{$mac}{iface} = $in_iface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::mac::${mac}::iface" => $anvil->data->{sys}{mac}{$mac}{iface}, - }}); - } - } - } - - # Read the config files for the interfaces we've found. - local(*DIRECTORY); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { "path::directories::ifcfg" => $anvil->data->{path}{directories}{ifcfg} }}); - opendir(DIRECTORY, $anvil->data->{path}{directories}{ifcfg}); - while(my $file = readdir(DIRECTORY)) - { - next if $file eq "."; - next if $file eq ".."; - next if $file eq "ifcfg-lo"; - next if $file !~ /^ifcfg/; - next if $file =~ /\.bak$/; - my $full_path = $anvil->data->{path}{directories}{ifcfg}."/".$file; - $full_path =~ s/\/\///g; - next if not -f $full_path; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file => $file }}); - - # Read the file. - my $file_body = $anvil->Storage->read_file({file => $full_path}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:full_path" => $full_path, - "s2:file_body" => $file_body, - }}); - - # Break it apart and store any variables. - my $temp = {}; - my $interface = ""; - foreach my $line (split/\n/, $file_body) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - next if $line =~ /^#/; - if ($line =~ /(.*?)=(.*)/) - { - my $variable = $1; - my $value = $2; - $value =~ s/^"(.*)"$/$1/; - $temp->{$variable} = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "temp->{$variable}" => $temp->{$variable} }}); - - if (uc($variable) eq "DEVICE") - { - $interface = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "interface" => $interface }}); - } - } - - if ($interface) - { - $anvil->data->{sys}{network}{interface}{$interface}{file} = $full_path; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::network::interface::${interface}::file" => $anvil->data->{sys}{network}{interface}{$interface}{file}, - }}); - foreach my $variable (sort {$a cmp $b} keys %{$temp}) - { - $anvil->data->{sys}{network}{interface}{$interface}{variable}{$variable} = $temp->{$variable}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::network::interface::${interface}::file::variable::${variable}" => $anvil->data->{sys}{network}{interface}{$interface}{variable}{$variable}, - }}); - } - } - } - } - closedir(DIRECTORY); - - # Get the routing info. - my $lowest_metric = 99999999; - my $route_interface = ""; - my $route_ip = ""; - (my $ip_route, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{ip}." route show"}); - foreach my $line (split/\n/, $ip_route) - { - $line = $anvil->Words->clean_spaces({ string => $line }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - if ($line =~ /default via (.*?) dev (.*?) proto .*? metric (\d+)/i) - { - my $this_ip = $1; - my $this_interface = $2; - my $metric = $3; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 's1:this_ip' => $this_ip, - 's2:this_interface' => $this_interface, - 's3:metric' => $metric, - 's4:lowest_metric' => $lowest_metric, - }}); - - if ($metric < $lowest_metric) - { - $lowest_metric = $metric; - $route_interface = $this_interface; - $route_ip = $this_ip; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - lowest_metric => $lowest_metric, - route_interface => $route_interface, - route_ip => $route_ip, - }}); - } - } - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - route_interface => $route_interface, - route_ip => $route_ip, - }}); - - # If I got a route, get the DNS. - if ($route_interface) - { - # I want to build the DNS list from only the interface that is used for routing. - my $in_interface = ""; - my $dns_list = ""; - my $dns_hash = {}; - my ($ip_route, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{nmcli}." dev show"}); - foreach my $line (split/\n/, $ip_route) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - if ($line =~ /GENERAL.DEVICE:\s+(.*)$/) - { - $in_interface = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); - } - if (not $line) - { - $in_interface = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); - } - - next if $in_interface ne $route_interface; - - if ($line =~ /IP4.DNS\[(\d+)\]:\s+(.*)/i) - { - my $order = $1; - my $ip = $2; - - $dns_hash->{$order} = $ip; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "dns_hash->{$order}" => $dns_hash->{$order} }}); - } - } - - foreach my $order (sort {$a cmp $b} keys %{$dns_hash}) - { - $dns_list .= $dns_hash->{$order}.", "; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:dns_hash->{$order}" => $dns_hash->{$order}, - "s2:dns_list" => $dns_list, - }}); - } - $dns_list =~ s/, $//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { dns_list => $dns_list }}); - - $anvil->data->{sys}{network}{interface}{$route_interface}{default_gateway} = 1; - $anvil->data->{sys}{network}{interface}{$route_interface}{gateway} = $route_ip; - $anvil->data->{sys}{network}{interface}{$route_interface}{dns} = $dns_list; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "sys::network::interface::${route_interface}::default_gateway" => $anvil->data->{sys}{network}{interface}{$route_interface}{default_gateway}, - "sys::network::interface::${route_interface}::gateway" => $anvil->data->{sys}{network}{interface}{$route_interface}{gateway}, - "sys::network::interface::${route_interface}::dns" => $anvil->data->{sys}{network}{interface}{$route_interface}{dns}, - }}); - } - - return(0); -} - =head2 get_uptime This returns, in seconds, how long the host has been up and running for. @@ -1549,7 +1298,7 @@ sub is_local else { # Get the list of current IPs and see if they match. - my $network = $anvil->Get->network_details; + my $network = $anvil->Network->get_network_details; foreach my $interface (keys %{$network->{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "network->interface::${interface}::ip" => $network->{interface}{$interface}{ip} }}); @@ -2373,7 +2122,7 @@ sub ping 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)) + 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 }}); diff --git a/cgi-bin/striker b/cgi-bin/striker index 6adb8b00..ed20e615 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -962,15 +962,15 @@ sub process_sync_page } my $host_uuid = $anvil->Get->host_uuid; - $anvil->System->get_ips(); + $anvil->Network->get_ips(); # We'll want to show the user way to access the local machine. For that, we'll loop through our own IPs. my $inbound_table = ""; - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { next if (($interface !~ /^bcn/) && ($interface !~ /^ifn/)); - next if not $anvil->Validate->is_ipv4({ip => $anvil->data->{sys}{network}{interface}{$interface}{ip}}); - next if not $anvil->Validate->is_subnet({subnet => $anvil->data->{sys}{network}{interface}{$interface}{subnet}}); + next if not $anvil->Validate->is_ipv4({ip => $anvil->data->{network}{'local'}{interface}{$interface}{ip}}); + next if not $anvil->Validate->is_subnet({subnet => $anvil->data->{network}{'local'}{interface}{$interface}{subnet}}); my ($network_type, $network_number) = ($interface =~ /^(.*?)(\d+)_/); my $database_user = $anvil->data->{database}{$host_uuid}{user} ? $anvil->data->{database}{$host_uuid}{user} : $anvil->data->{sys}{database}{user}; @@ -979,18 +979,18 @@ sub process_sync_page my $say_network = $anvil->Words->string({key => $network_key, variables => { number => $network_number }}); # The user 'admin' and the port 5432 are default, so only show them if they're non-standard. - my $access_string = $database_user."\@".$anvil->data->{sys}{network}{interface}{$interface}{ip}.":".$database_port; + my $access_string = $database_user."\@".$anvil->data->{network}{'local'}{interface}{$interface}{ip}.":".$database_port; if (($database_port eq "5432") && ($database_user eq "admin")) { - $access_string = $anvil->data->{sys}{network}{interface}{$interface}{ip}; + $access_string = $anvil->data->{network}{'local'}{interface}{$interface}{ip}; } elsif ($database_port eq "5432") { - $access_string = $database_user."\@".$anvil->data->{sys}{network}{interface}{$interface}{ip}; + $access_string = $database_user."\@".$anvil->data->{network}{'local'}{interface}{$interface}{ip}; } elsif ($database_user eq "admin") { - $access_string = $anvil->data->{sys}{network}{interface}{$interface}{ip}.":".$database_port; + $access_string = $anvil->data->{network}{'local'}{interface}{$interface}{ip}.":".$database_port; } $inbound_table .= $anvil->Template->get({file => "striker.html", name => "striker-sync-inbound", variables => { access => $access_string, @@ -1611,7 +1611,7 @@ ORDER BY # Get the list of current IPs so that we can warn the user if committing the changes will require # reconnecting. - $anvil->System->get_ips({debug => 2}); + $anvil->Network->get_ips({debug => 2}); my $matched_ip = 0; my $server_ip = $ENV{SERVER_ADDR}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_ip => $server_ip }}); diff --git a/notes b/notes index 986e8d64..003d6417 100644 --- a/notes +++ b/notes @@ -1126,3 +1126,8 @@ pcs constraint remove cli-ban-test_server-on-el8-a01n01 pcs constraint remove $(pcs constraint show --full | grep ban-test_server | perl -pe 's/^.*?id:(.*?)\)/$1/') + + +DRBD 9 - Check; +/sys/kernel/debug/drbd/resources/${resource_name}/connections/${hostname}/0/proc_drbd + diff --git a/share/words.xml b/share/words.xml index e3796521..55775edd 100644 --- a/share/words.xml +++ b/share/words.xml @@ -761,6 +761,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a The setuid c-wrapper: [#!variable!wrapper!#] already exists, no need to create it. The anvil version cache file: [#!variable!file!#] for: [#!variable!target!#] needs to be created/updated. + No databases available yet, continuing to wait. Test @@ -994,6 +995,8 @@ Failure! The return code: [#!variable!return_code!#] was received ('0' was expec Verifying installation. [ Failed ] - There may be more information in #!data!path::configs::anvil.conf!#. Success! + 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. The IP address will change. You will need to reconnect after applying these changes. @@ -1099,6 +1102,8 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp Something went wrong trying to compile the C-program: [#!variable!file!#], unable to proceed. The job UUID was not passed via '--job-uuid' and no unclaimed job was found in the database. The initialization target: [#!variable!target!#] is not accessible. Will keep trying... + There are no databases available. Will check periodically, waiting until one becomes available. + There was a problem adding out database to the target's anvil.conf file. Yes diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 7ff8419d..b032af62 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -241,7 +241,7 @@ sub reconfigure_network } # Get the current list of IPs and MAC addresses. - $anvil->System->get_ips(); + $anvil->Network->get_ips(); # Now configure the network. my $dns = defined $anvil->data->{variables}{form}{config_step2}{dns}{value} ? [split/,/, $anvil->data->{variables}{form}{config_step2}{dns}{value}] : []; diff --git a/tools/anvil-daemon b/tools/anvil-daemon index a6b4b7e0..e999af69 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -77,20 +77,41 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure = # If I have no databases, sleep for a second and then exit (systemd will restart us). if (not $anvil->data->{sys}{database}{connections}) { - # Try to configure the local database, and then try to connect again. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0201"}); - prep_database($anvil); - sleep 1; - - # Try connecting again - $anvil->Database->connect(); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0132"}); - if (not $anvil->data->{sys}{database}{connections}) + # If this is a dashboard, try to configure and then connect to the local database. If this isn't a + # dashboard, then just go into a loop waiting for a database to be configured. + if ($anvil->System->get_host_type eq "dashboard") { - # Still nothing, sleep and exit. - print $anvil->Words->string({key => "error_0003"})."\n"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "error_0003"}); - $anvil->nice_exit({exit_code => 2}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0201"}); + prep_database($anvil); + sleep 1; + + # Try connecting again + $anvil->Database->connect(); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0132"}); + if (not $anvil->data->{sys}{database}{connections}) + { + # Still nothing, sleep and exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, secure => 0, key => "error_0003"}); + $anvil->nice_exit({exit_code => 2}); + } + } + else + { + # Wait until we have one. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, secure => 0, key => "error_0075"}); + + until($anvil->data->{sys}{database}{connections}) + { + sleep 10; + + $anvil->refresh(); + $anvil->Database->connect({debug => 3, check_if_configured => 1}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); + if (not $anvil->data->{sys}{database}{connections}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 2, secure => 0, key => "log_0439"}); + } + } } } @@ -147,11 +168,7 @@ my $check_if_database_is_configured = 0; while(1) { # Reload defaults, re-read the config and then connect to the database(s) - $anvil->_set_paths(); - $anvil->_set_defaults(); # This reset the log level - $anvil->Storage->read_config(); # This reset the log level also - $anvil->Get->switches; # Re-read to let switches override again. - $anvil->Words->read(); + $anvil->refresh(); $anvil->Database->connect({check_if_configured => $check_if_database_is_configured}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); @@ -1014,12 +1031,21 @@ sub prep_database { my ($anvil) = @_; - my $shell_call = $anvil->data->{path}{exe}{'striker-prep-database'}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); - my ($database_output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); - if ($database_output) + # Only run this if we're a dashboard. + my $host_type = $anvil->System->get_host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); + if ($host_type eq "dashboard") { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { database_output => $database_output }}); + my ($database_output, $return_code) = $anvil->System->call({ + debug => 2, + shell_call => $anvil->data->{path}{exe}{'striker-prep-database'}, + source => $THIS_FILE, + line => __LINE__, + }); + if ($database_output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_output => $database_output }}); + } } return(0); diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index ebb04598..252eb852 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -151,7 +151,7 @@ $anvil->nice_exit({exit_code => 0}); # is server definition files. For those, we write the file out from the server's 'definition' table entry. # # When a missing entry is found, and an entry doesn't exist, the file will be found (if possible) and copied -# to this houst. Only machines on the same subnet are searched. The search pattern is; +# to this host. Only machines on the same subnet are searched. The search pattern is; # # Nodes; 1. Check for the file on the peer. # 2. Check for the file on Strikers, in alphabetical order. @@ -243,14 +243,14 @@ sub find_file my $found = 0; # What are my IPs? - $anvil->System->get_ips(); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + $anvil->Network->get_ips(); + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { - next if not $anvil->data->{sys}{network}{interface}{$interface}{ip}; - next if not $anvil->data->{sys}{network}{interface}{$interface}{subnet}; - my $ip = $anvil->data->{sys}{network}{interface}{$interface}{ip}; - my $subnet = $anvil->data->{sys}{network}{interface}{$interface}{subnet}; - my $network = $anvil->Get->network({ip => $ip, subnet => $subnet}); + next if not $anvil->data->{network}{'local'}{interface}{$interface}{ip}; + next if not $anvil->data->{network}{'local'}{interface}{$interface}{subnet}; + my $ip = $anvil->data->{network}{'local'}{interface}{$interface}{ip}; + my $subnet = $anvil->data->{network}{'local'}{interface}{$interface}{subnet}; + my $network = $anvil->Network->get_network({ip => $ip, subnet => $subnet}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 's1:interface' => $interface, 's2:ip' => $ip, @@ -360,7 +360,7 @@ AND { my $ip_address_address = $row->[0]; my $ip_address_subnet_mask = $row->[1]; - my $network = $anvil->Get->network({ip => $ip_address_address, subnet => $ip_address_subnet_mask}); + my $network = $anvil->Network->get_network({ip => $ip_address_address, subnet => $ip_address_subnet_mask}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_address => $ip_address_address, ip_address_subnet_mask => $ip_address_subnet_mask, diff --git a/tools/anvil-manage-firewall b/tools/anvil-manage-firewall index 21255475..91528001 100755 --- a/tools/anvil-manage-firewall +++ b/tools/anvil-manage-firewall @@ -98,14 +98,14 @@ sub check_initial_setup $anvil->data->{firewall}{reload} = 0; # Get a list of networks. - $anvil->System->get_ips({debug => 3}); + $anvil->Network->get_ips({debug => 3}); # Get the list of existing zones from iptables/firewalld. $anvil->System->check_firewall({debug => 3}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "firewall::default_zone" => $anvil->data->{firewall}{default_zone} }}); my $internet_zone = ""; - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface => $interface }}); if ($interface =~ /^((bcn|ifn|sn)\d+)_/) @@ -114,24 +114,24 @@ sub check_initial_setup # always be overridden by the ZONE="" variable in each interface's config. my $zone = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { zone => $zone }}); - if ((exists $anvil->data->{sys}{network}{interface}{$interface}{variable}{ZONE}) && ($anvil->data->{sys}{network}{interface}{$interface}{variable}{ZONE})) + if ((exists $anvil->data->{network}{'local'}{interface}{$interface}{variable}{ZONE}) && ($anvil->data->{network}{'local'}{interface}{$interface}{variable}{ZONE})) { - $zone = $anvil->data->{sys}{network}{interface}{$interface}{variable}{ZONE}; + $zone = $anvil->data->{network}{'local'}{interface}{$interface}{variable}{ZONE}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { zone => $zone }}); } push @{$needed_zones}, $zone; - $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{ip} = $anvil->data->{sys}{network}{interface}{$interface}{ip}; - $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{subnet} = $anvil->data->{sys}{network}{interface}{$interface}{subnet}; + $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{ip} = $anvil->data->{network}{'local'}{interface}{$interface}{ip}; + $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{subnet} = $anvil->data->{network}{'local'}{interface}{$interface}{subnet}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "firewall::zone::${zone}::interface::${interface}::ip" => $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{ip}, "firewall::zone::${zone}::interface::${interface}::subnet" => $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{subnet}, }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "sys::network::interface::${interface}::default_gateway" => $anvil->data->{sys}{network}{interface}{$interface}{default_gateway}, + "network::local::interface::${interface}::default_gateway" => $anvil->data->{network}{'local'}{interface}{$interface}{default_gateway}, }}); - if ($anvil->data->{sys}{network}{interface}{$interface}{default_gateway}) + if ($anvil->data->{network}{'local'}{interface}{$interface}{default_gateway}) { $internet_zone = $zone; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { internet_zone => $internet_zone }}); diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 0ef8c834..6c9050e6 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -45,12 +45,12 @@ sub update_network { my ($anvil) = @_; - # Run 'ip addr' to see what IPs are in use. The results will be stored in: - $anvil->System->get_ips(); + # Run 'ip addr' to see what IPs are in use. + $anvil->Network->get_ips(); # We'll read through '/sys/class/net' looking for network interfaces. - # * 'sys::network::interface::::ip' - If an IP address is set - # * 'sys::network::interface::::subnet' - If an IP is set + # * 'network::local::interface::::ip' - If an IP address is set + # * 'network::local::interface::::subnet' - If an IP is set my $directory = "/sys/class/net"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }}); @@ -111,10 +111,10 @@ sub update_network my $down_delay = ""; my $bond_master = ""; - if (exists $anvil->data->{sys}{network}{interface}{$interface}) + if (exists $anvil->data->{network}{'local'}{interface}{$interface}) { - $ip_address = $anvil->data->{sys}{network}{interface}{$interface}{ip} ? $anvil->data->{sys}{network}{interface}{$interface}{ip} : ""; - $subnet_mask = $anvil->data->{sys}{network}{interface}{$interface}{subnet} ? $anvil->data->{sys}{network}{interface}{$interface}{subnet} : ""; + $ip_address = $anvil->data->{network}{'local'}{interface}{$interface}{ip} ? $anvil->data->{network}{'local'}{interface}{$interface}{ip} : ""; + $subnet_mask = $anvil->data->{network}{'local'}{interface}{$interface}{subnet} ? $anvil->data->{network}{'local'}{interface}{$interface}{subnet} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address => $ip_address, subnet_mask => $subnet_mask, @@ -319,9 +319,9 @@ sub update_network my $subnet_mask = $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask}; my $type = $anvil->data->{network}{interfaces}{by_name}{$interface}{type}; my $up_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay}; - my $default_gateway = $anvil->data->{sys}{network}{interface}{$interface}{default_gateway}; - my $gateway = $anvil->data->{sys}{network}{interface}{$interface}{gateway}; - my $dns = $anvil->data->{sys}{network}{interface}{$interface}{dns}; + my $default_gateway = $anvil->data->{network}{'local'}{interface}{$interface}{default_gateway}; + my $gateway = $anvil->data->{network}{'local'}{interface}{$interface}{gateway}; + my $dns = $anvil->data->{network}{'local'}{interface}{$interface}{dns}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { active_slave => $active_slave, bond_mode => $bond_mode, @@ -700,14 +700,14 @@ WHERE # Did we see this IP on this scan? If not, set on_type to DELETEd. my $found = 0; - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - interface => $interface, - ip_address_address => $ip_address_address, - "sys::network::interface::${interface}::ip" => $anvil->data->{sys}{network}{interface}{$interface}{ip}, + interface => $interface, + ip_address_address => $ip_address_address, + "network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip}, }}); - if ((defined $anvil->data->{sys}{network}{interface}{$interface}{ip}) && ($anvil->data->{sys}{network}{interface}{$interface}{ip} eq $ip_address_address)) + if ((defined $anvil->data->{network}{'local'}{interface}{$interface}{ip}) && ($anvil->data->{network}{'local'}{interface}{$interface}{ip} eq $ip_address_address)) { $found = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }}); diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host index 896182d7..af64da53 100755 --- a/tools/striker-initialize-host +++ b/tools/striker-initialize-host @@ -10,6 +10,7 @@ # 3 = Job detauls not found in the database. # 4 = Unable to connect to the target. # 5 = Failed to install the anvil package. +# 6 = Failed to add our database to the target's anvil.conf file. # use strict; @@ -66,6 +67,79 @@ sub add_databases { my ($anvil) = @_; + # Normally, we'd use the BCN IPs to tell the peer how to reach our database, but it's entirely + # possible at this stage that the target doesn't have a BCN IP. So we need to figure out what IP it + # has and we have that are on the same subnet. + # Scan our network and the target's network, then compare them. + update_progress($anvil, 95, "job_0046"); + my $target = $anvil->data->{data}{host_ip_address}; + $anvil->Network->get_ips(); + $anvil->Network->get_ips({ + target => $target, + remote_user => "root", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + }); + my ($match) = $anvil->Network->find_matches({ + debug => 3, + first => 'local', + second => $target, + }); + + # We'll sort in reverse order, so if there is a BCN address, we'll use it. + my $host_uuid = $anvil->data->{sys}{host_uuid}; + my $db_host = ""; + my $db_port = ""; + my $db_password = ""; + foreach my $interface (sort {$a cmp $b} keys %{$match->{'local'}}) + { + my $local_ip = $anvil->data->{network}{'local'}{interface}{$interface}{ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + local_ip => $local_ip, + }}); + if (($local_ip) && ($anvil->Validate->is_ipv4({ip => $local_ip}))) + { + $db_host = $local_ip; + $db_port = $anvil->data->{database}{$host_uuid}{port}; + $db_password = $anvil->data->{database}{$host_uuid}{password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + db_host => $db_host, + db_port => $db_port, + db_password => $anvil->Log->is_secure($db_password), + }}); + } + last if $db_host; + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { db_host => $db_host }}); + if ($db_host) + { + my $failed = $anvil->Database->manage_anvil_conf({ + debug => 2, + target => $target, + remote_user => "root", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + db_host_uuid => $anvil->data->{sys}{host_uuid}, + db_host => $db_host, + db_port => $db_port, + db_password => $db_password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { failed => $failed }}); + if ($failed) + { + # Something went wrong + $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}); + } + else + { + # Success! We're done@ + update_progress($anvil, 100, "job_0047"); + } + } return(0); } @@ -93,12 +167,12 @@ EOF "; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $shell_call, - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", + debug => 3, + shell_call => $shell_call, + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error => $error, @@ -120,12 +194,12 @@ EOF # We'll attach subscriptions if this is set my $subscribe = 1; my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." identity", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", + debug => 3, + shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." identity", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, @@ -146,13 +220,13 @@ EOF my $bash_password = $anvil->data->{data}{rh_password}; $bash_password =~ s/'/\\\'/g; my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." register --username ".$anvil->data->{data}{rh_user}." --password '".$bash_password."' --auto-attach --force", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 300, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." register --username ".$anvil->data->{data}{rh_user}." --password '".$bash_password."' --auto-attach --force", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 300, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -202,13 +276,13 @@ EOF $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0036", variables => { repo => 'codeready-builder-for-rhel-8-x86_64-rpms' }}); update_progress($anvil, 10, "job_0036,!!repo!codeready-builder-for-rhel-8-x86_64-rpms!!"); my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." repos --enable codeready-builder-for-rhel-8-x86_64-rpms", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 300, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." repos --enable codeready-builder-for-rhel-8-x86_64-rpms", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 300, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -221,15 +295,15 @@ EOF if ($anvil->data->{data}{type} eq "node") { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0036", variables => { repo => 'rhel-8-for-x86_64-highavailability-rpms' }}); - update_progress($anvil, 11, "job_0036,!!repo!rhel-8-for-x86_64-highavailability-rpms!!"); + update_progress($anvil, 15, "job_0036,!!repo!rhel-8-for-x86_64-highavailability-rpms!!"); my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." repos --enable rhel-8-for-x86_64-highavailability-rpms", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 300, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." repos --enable rhel-8-for-x86_64-highavailability-rpms", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 300, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -242,18 +316,18 @@ EOF } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0037"}); - update_progress($anvil, 12, "job_0037"); + update_progress($anvil, 20, "job_0037"); undef $output; undef $error; undef $return_code; ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." repos --list-enabled", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 300, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." repos --list-enabled", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 300, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -278,7 +352,7 @@ EOF if (not $anvil->data->{repos}{$repo}) { # Well this is a problem... - update_progress($anvil, 11, "job_0038,!!repo!".$repo."!!"); + update_progress($anvil, 25, "job_0038,!!repo!".$repo."!!"); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0038", variables => { repo => $repo }}); } } @@ -286,18 +360,18 @@ EOF } # Call an OS update. - update_progress($anvil, 20, "job_0039"); - update_progress($anvil, 25, "job_0040"); + update_progress($anvil, 29, "job_0039"); + update_progress($anvil, 30, "job_0040"); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0039"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0040"}); my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'dnf'}." -y update", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 3600, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'dnf'}." -y update", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 3600, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -312,13 +386,13 @@ EOF undef $error; undef $return_code; ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'dnf'}." -y remove biosdevname", - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 300, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'dnf'}." -y remove biosdevname", + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 300, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -335,13 +409,13 @@ EOF undef $error; undef $return_code; ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'dnf'}." -y install ".$package, - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 3600, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'dnf'}." -y install ".$package, + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 3600, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, @@ -355,13 +429,13 @@ EOF undef $error; undef $return_code; ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, - shell_call => $anvil->data->{path}{exe}{'dnf'}." list installed ".$package, - password => $anvil->data->{data}{password}, - port => $anvil->data->{data}{ssh_port}, - target => $anvil->data->{data}{host_ip_address}, - user => "root", - timeout => 3600, + debug => 3, + shell_call => $anvil->data->{path}{exe}{'dnf'}." list installed ".$package, + password => $anvil->data->{data}{password}, + port => $anvil->data->{data}{ssh_port}, + target => $anvil->data->{data}{host_ip_address}, + remote_user => "root", + timeout => 3600, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, diff --git a/tools/striker-manage-install-target b/tools/striker-manage-install-target index df0745c5..b8472c68 100755 --- a/tools/striker-manage-install-target +++ b/tools/striker-manage-install-target @@ -433,15 +433,15 @@ sub setup_boot_environment ### We;re going to need the '.treeinfo' as well in anvil-striker-extra ### - https://docs.fedoraproject.org/en-US/fedora/f28/install-guide/advanced/Network_based_Installations/ # Get my BCN IP and active OS. - $anvil->System->get_ips(); + $anvil->Network->get_ips(); my $bcn_interface = ""; - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface => $interface }}); next if $interface !~ /^bcn/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::network::${interface}::ip" => $anvil->data->{sys}{network}{interface}{$interface}{ip} }}); - if ($anvil->Validate->is_ipv4({ip => $anvil->data->{sys}{network}{interface}{$interface}{ip} })) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "network::local::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip} }}); + if ($anvil->Validate->is_ipv4({ip => $anvil->data->{network}{'local'}{interface}{$interface}{ip} })) { $bcn_interface = $interface; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bcn_interface => $bcn_interface }}); @@ -457,10 +457,10 @@ sub setup_boot_environment $anvil->nice_exit({code => 2}); } - my $bcn_ip = $anvil->data->{sys}{network}{interface}{$bcn_interface}{ip}; - my $bcn_subnet = $anvil->data->{sys}{network}{interface}{$bcn_interface}{subnet}; - my $bcn_network = $anvil->Get->network({ip => $bcn_ip, subnet => $bcn_subnet}); - my $dns = $anvil->data->{sys}{network}{interface}{$bcn_interface}{dns} ? $anvil->data->{sys}{network}{interface}{$bcn_interface}{dns} : $anvil->data->{defaults}{network}{dns}; + my $bcn_ip = $anvil->data->{network}{'local'}{interface}{$bcn_interface}{ip}; + my $bcn_subnet = $anvil->data->{network}{'local'}{interface}{$bcn_interface}{subnet}; + my $bcn_network = $anvil->Network->get_network({ip => $bcn_ip, subnet => $bcn_subnet}); + my $dns = $anvil->data->{network}{'local'}{interface}{$bcn_interface}{dns} ? $anvil->data->{network}{'local'}{interface}{$bcn_interface}{dns} : $anvil->data->{defaults}{network}{dns}; my $domain = "localdomain"; my $base_url = "http://".$bcn_ip."/".$anvil->data->{host_os}{os_type}."/".$anvil->data->{host_os}{os_arch}; if ($anvil->_hostname =~ /\./)