diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 16d4ad8c..bd24705d 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1102,6 +1102,7 @@ sub _set_paths units => "/usr/lib/systemd/system", }, exe => { + akmods => "/usr/sbin/akmods", 'alteeve-repo-setup' => "/usr/sbin/alteeve-repo-setup", 'anvil-boot-server' => "/usr/sbin/anvil-boot-server", 'anvil-change-password' => "/usr/sbin/anvil-change-password", @@ -1197,6 +1198,7 @@ sub _set_paths md5sum => "/usr/bin/md5sum", 'mkdir' => "/usr/bin/mkdir", modifyrepo_c => "/usr/bin/modifyrepo_c", + modprobe => "/usr/sbin/modprobe", mv => "/usr/bin/mv", nmap => "/usr/bin/nmap", nmcli => "/bin/nmcli", @@ -1244,6 +1246,7 @@ sub _set_paths su => "/usr/bin/su", 'subscription-manager' => "/usr/sbin/subscription-manager", swapon => "/usr/sbin/swapon", + sysctl => "/usr/sbin/sysctl", systemctl => "/usr/bin/systemctl", timeout => "/usr/bin/timeout", touch => "/usr/bin/touch", diff --git a/Anvil/Tools/Account.pm b/Anvil/Tools/Account.pm index 030c9846..68fbaf2d 100644 --- a/Anvil/Tools/Account.pm +++ b/Anvil/Tools/Account.pm @@ -451,7 +451,8 @@ AND $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0198", variables => { user => $anvil->data->{cgi}{username}{value} }}); + my $user = $anvil->data->{cgi}{username}{value} ? $anvil->data->{cgi}{username}{value} : "--"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0198", variables => { user => $user }}); # Log that they're out $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0179"}); @@ -573,7 +574,7 @@ AND $anvil->data->{sys}{users}{user_name} = $results->[0]->[0]; $anvil->data->{sessions}{session_salt} = $results->[0]->[1]; $anvil->data->{sessions}{session_salt} = "" if not defined $anvil->data->{sessions}{session_salt}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::users::user_name" => $anvil->data->{sys}{users}{user_name}, "sessions::session_salt" => $anvil->data->{sessions}{session_salt}, }}); @@ -592,8 +593,9 @@ AND offset => -86400, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - today_hash => $today_hash, - yesterday_hash => $yesterday_hash, + "s1:cookie::anvil_user_hash" => $anvil->data->{cookie}{anvil_user_hash}, + "s2:today_hash" => $today_hash, + "s3:yesterday_hash" => $yesterday_hash, }}); # See if either hash matches what the user has stored. diff --git a/Anvil/Tools/Alert.pm b/Anvil/Tools/Alert.pm index b49b0944..dc1d322f 100644 --- a/Anvil/Tools/Alert.pm +++ b/Anvil/Tools/Alert.pm @@ -295,6 +295,7 @@ sub check_condition_age # See if this variable has been set yet. my ($variable_value, $variable_uuid, $epoch_modified_date, $modified_date) = $anvil->Database->read_variable({ + debug => $debug, variable_name => $name, variable_source_table => $source_table, variable_source_uuid => $host_uuid, @@ -319,8 +320,8 @@ sub check_condition_age }); } - # if the value was 'clear', change it to 'set'. - if ($variable_value eq "clear") + # if the 'clear' parameter isn't set, and the value is 'clear', change it to 'set'. + if (($variable_value eq "clear") && (not $clear)) { # Set it. $variable_uuid = $anvil->Database->insert_or_update_variables({ diff --git a/Anvil/Tools/Convert.pm b/Anvil/Tools/Convert.pm index 28c50483..e73d0150 100644 --- a/Anvil/Tools/Convert.pm +++ b/Anvil/Tools/Convert.pm @@ -848,6 +848,12 @@ sub format_mmddyy_to_yymmdd date => $date, }}); + # Sometimes we're passed '--' or '#!no_value!#' which is not strictly an error, so we'll return it back. + if (($date eq "--") or ($date eq "#!no_value!#")) + { + return($date); + } + if (not $date) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Convert->format_mmddyy_to_yymmdd()", parameter => "host_name" }}); @@ -905,7 +911,6 @@ sub host_name_to_ip } ### TODO: Check local cached information later. - # Try to resolve it using 'gethostip'. my $shell_call = $anvil->data->{path}{exe}{gethostip}." -d ".$host_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm index 263579b9..247be8e4 100644 --- a/Anvil/Tools/DRBD.pm +++ b/Anvil/Tools/DRBD.pm @@ -26,6 +26,7 @@ my $THIS_FILE = "DRBD.pm"; # reload_defaults # resource_uuid # update_global_common +# _initialize_kmod # =pod @@ -1835,6 +1836,7 @@ sub get_status return(0); } + =head2 manage_resource This takes a task, C<< up >>, C<< down >>, C<< primary >>, or C<< secondary >> and a resource name and acts on the request. @@ -3029,3 +3031,114 @@ sub update_global_common ############################################################################################################# # Private functions # ############################################################################################################# + +=head2 _initialize_kmod + +This checks to see if the C<< drbd >> kernel module can load. If not, a check is made to see if an RPM that matches the kernel exists. If so, it is installed. If not, C<< akmods >> is asked to build and install the drbd kernel module. + +Returns C<< 0 >> is the module loads or is already loaded. C<< !!error!! >> if not. + +=cut +sub _initialize_kmod +{ + 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 => "DRBD->_initialize_kmod()" }}); + + my $kernel_release = $anvil->Get->kernel_release({debug => $debug}); + my $shell_call = $anvil->data->{path}{exe}{modprobe}." drbd"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + kernel_release => $kernel_release, + shell_call => $shell_call, + }}); + + my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + + if (not $return_code) + { + # Loaded fine + return(0); + } + else + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0676"}); + my $install = 0; + my $shell_call = $anvil->data->{path}{exe}{dnf}." -q search kmod-drbd-".$kernel_release; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + if ($line =~ /Name Exactly/) + { + # We can install. + $install = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { install => $install }}); + last; + } + } + + # Install or build? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { install => $install }}); + if ($install) + { + ### TODO: Should this be a background process? + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0677"}); + my $shell_call = $anvil->data->{path}{exe}{dnf}." -y install kmod-drbd-".$kernel_release; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + } + else + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0678"}); + my $shell_call = $anvil->data->{path}{exe}{akmods}." --force"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + } + + # In either case, try again. + $output = undef; + $return_code = undef; + $shell_call = $anvil->data->{path}{exe}{modprobe}." drbd"; + ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + + if (not $return_code) + { + # Loaded fine + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0679"}); + return(0); + } + else + { + # Failed + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "warning_0132"}); + } + } + + return('!!error!!'); +} diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 7e84ee06..387b91bc 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -93,6 +93,7 @@ my $THIS_FILE = "Database.pm"; # resync_databases # update_host_status # write +# _add_to_local_config # _age_out_data # _archive_table # _find_column @@ -778,6 +779,7 @@ If the method completes, C<< 0 >> is returned. If this method is called without This method takes no parameters. =cut +### TODO: Much of this logic is in striker-prep-database, consolidate! sub configure_pgsql { my $self = shift; @@ -798,6 +800,23 @@ sub configure_pgsql $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0113"}); return(1); } + + # Make sure we have an entry in our own anvil.conf. + my $local_uuid = $anvil->Database->get_local_uuid(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_uuid => $local_uuid }}); + + # If we didn't get the $local_uuid, then there is no entry for this system in anvil.conf yet, so we'll add it. + if (not $local_uuid) + { + $local_uuid = $anvil->Database->_add_to_local_config({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }}); + + if ($local_uuid eq "!!error!!") + { + # Already logged the error, return. + return('!!error!!'); + } + } # First, is it running and is it initialized? my $initialized = 0; @@ -806,7 +825,7 @@ sub configure_pgsql if (not -e $anvil->data->{path}{configs}{'pg_hba.conf'}) { # Initialize. Record that we did so, so that we know to start the daemon. - my ($output, $return_code) = $anvil->System->call({debug => 1, shell_call => $anvil->data->{path}{exe}{'postgresql-setup'}." initdb", source => $THIS_FILE, line => __LINE__}); + my ($output, $return_code) = $anvil->System->call({debug => 1, shell_call => $anvil->data->{path}{exe}{'postgresql-setup'}." --initdb --unit postgresql", source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { output => $output, return_code => $return_code }}); # Did it succeed? @@ -933,14 +952,20 @@ sub configure_pgsql } # Start or restart the daemon? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:running' => $running, + 's2:update_postgresql_file' => $update_postgresql_file, + 's3:update_pg_hba_file' => $update_pg_hba_file, + }}); if (not $running) { # Did we initialize? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { initialized => $initialized }}); if ($initialized) { # Start the daemon. my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{postgresql}}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { return_code => $return_code }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_code => $return_code }}); if ($return_code eq "0") { # Started the daemon. @@ -958,7 +983,7 @@ sub configure_pgsql { # Reload my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{postgresql}}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { return_code => $return_code }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_code => $return_code }}); if ($return_code eq "0") { # Reloaded the daemon. @@ -972,6 +997,11 @@ sub configure_pgsql } # Do user and DB checks only if we're made a change above. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:initialized' => $initialized, + 's2:update_postgresql_file' => $update_postgresql_file, + 's3:update_pg_hba_file' => $update_pg_hba_file, + }}); if (($initialized) or ($update_postgresql_file) or ($update_pg_hba_file)) { # Create the .pgpass file, if needed. @@ -1321,12 +1351,14 @@ sub connect # If we're a Striker, see if we're configured. my $local_host_type = $anvil->Get->host_type(); my $local_host_uuid = $anvil->Get->host_uuid(); + my $db_count = keys %{$anvil->data->{database}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_host_type => $local_host_type, local_host_uuid => $local_host_uuid, check_if_configured => $check_if_configured, real_uid => $<, effective_uid => $>, + db_count => $db_count, }}); # If requested, and if running with root access, set it up (or update it) if needed. # This method just returns if nothing is needed. @@ -1347,15 +1379,18 @@ sub connect if (($db_uuid) && ($db_uuid ne $uuid)) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0191", variables => { db_uuid => $db_uuid, uuid => $uuid }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0191", variables => { + db_uuid => $db_uuid, + uuid => $uuid, + }}); next; } # Make sure values are set. - $anvil->data->{database}{$uuid}{port} = 5432 if not $anvil->data->{database}{$uuid}{port}; - $anvil->data->{database}{$uuid}{name} = $anvil->data->{sys}{database}{name} if not $anvil->data->{database}{$uuid}{name}; - $anvil->data->{database}{$uuid}{user} = $anvil->data->{sys}{database}{user} if not $anvil->data->{database}{$uuid}{user}; - $anvil->data->{database}{$uuid}{password} = "" if not defined $anvil->data->{database}{$uuid}{password}; + $anvil->data->{database}{$uuid}{port} = 5432 if not defined $anvil->data->{database}{$uuid}{port}; + $anvil->data->{database}{$uuid}{name} = "anvil" if not $anvil->data->{database}{$uuid}{name}; + $anvil->data->{database}{$uuid}{user} = "admin" if not $anvil->data->{database}{$uuid}{user}; + $anvil->data->{database}{$uuid}{password} = "" if not defined $anvil->data->{database}{$uuid}{password}; my $driver = "DBI:Pg"; my $host = $anvil->data->{database}{$uuid}{host}; # This should fail if not set @@ -1371,6 +1406,13 @@ sub connect password => $anvil->Log->is_secure($password), }}); + # If there's no password, skip. + if (not $password) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0668", variables => { uuid => $uuid }}); + next; + } + # Some places will want to pull up the database user, so in case it isn't set (which is # usual), set it as if we had read it from the config file using the default. if (not $anvil->data->{database}{$uuid}{name}) @@ -1708,7 +1750,7 @@ sub connect } # If we're a striker and no connections were found, start our database. - if (($local_host_type eq "striker") && (not $anvil->data->{sys}{database}{connections})) + if (($local_host_type eq "striker") && (not $anvil->data->{sys}{database}{connections}) && ($db_count > 1)) { # Tell the user we're going to try to load and start. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0650"}); @@ -12031,7 +12073,20 @@ sub insert_or_update_states # If we were passed a database UUID, check for the open handle. if ($uuid) { - $anvil->data->{cache}{database_handle}{$uuid} = "" if not defined $anvil->data->{cache}{database_handle}{$uuid}; + if ((not defined $anvil->data->{cache}{database_handle}{$uuid}) or (not $anvil->data->{cache}{database_handle}{$uuid})) + { + # Switch to another UUID + foreach my $this_uuid (keys %{$anvil->data->{cache}{database_handle}}) + { + if ($anvil->data->{cache}{database_handle}{$this_uuid}) + { + # Switch to this UUID + $uuid = $this_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + } + } + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid}, }}); @@ -15300,9 +15355,26 @@ sub query } elsif (not defined $anvil->data->{cache}{database_handle}{$uuid}) { - # Database handle is gone. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0073", variables => { uuid => $uuid }}); - return("!!error!!"); + # Database handle is gone. Switch to the read_uuid + my $old_uuid = $uuid; + $uuid = $anvil->data->{sys}{database}{read_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + old_uuid => $old_uuid, + uuid => $uuid, + }}); + if (not defined $anvil->data->{cache}{database_handle}{$uuid}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0073", variables => { uuid => $uuid }}); + return("!!error!!"); + } + else + { + # Warn that we switched. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0073", variables => { + old_uuid => $old_uuid, + new_uuid => $uuid, + }}); + } } if (not $query) { @@ -15332,12 +15404,29 @@ sub query } # Do the query. - my $DBreq = $anvil->data->{cache}{database_handle}{$uuid}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => { + local $@; + my $DBreq = eval { $anvil->data->{cache}{database_handle}{$uuid}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => { query => (not $secure) ? $query : $anvil->Log->is_secure($query), server => $say_server, db_error => $DBI::errstr, + }}); }; + if ($@) + { + ### TODO: Report back somehow that the handle is dead. + $anvil->Database->disconnect({debug => $debug}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0675", variables => { + query => (not $secure) ? $query : $anvil->Log->is_secure($query), + server => $say_server, + eval_error => $@, }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { DBreq => $DBreq }}); + return("!!error!!"); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + uuid => $uuid, + query => (not $secure) ? $query : $anvil->Log->is_secure($query), + say_server => $say_server, + DBreq => $DBreq, + }}); # Execute on the query $DBreq->execute() or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0076", variables => { @@ -15562,9 +15651,10 @@ sub refresh_timestamp my $parameter = shift; my $anvil = $self->parent; - my $query = "SELECT cast(now() AS timestamp with time zone);"; - $anvil->data->{sys}{database}{timestamp} = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $query = "SELECT cast(now() AS timestamp with time zone);"; + my $new_time = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->data->{sys}{database}{timestamp} = $new_time; return($anvil->data->{sys}{database}{timestamp}); } @@ -15601,10 +15691,33 @@ sub resync_databases return(0); } + # If we're not a striker, don't resync ever. + my $host_type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); + if ($host_type ne "striker") + { + # Not a dashboard, don't resync + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0686"}); + return(1); + } + + # If we're hosting servers, don't resync. Too high of a risk of oom-killer being triggered. + my $server_count = $anvil->Server->count_servers({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_count => $server_count }}); + if ($server_count) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0680", variables => { count => $server_count }}); + return(0); + } + + # Before resync, age out the data in each DB + $anvil->Database->_age_out_data({debug => $debug}); + ### NOTE: Don't sort this array, we need to resync in the order that the user passed the tables to us ### to avoid trouble with primary/foreign keys. # We're going to use the array of tables assembles by _find_behind_databases() stored in # 'sys::database::check_tables' + my $start_time = time; foreach my $table (@{$anvil->data->{sys}{database}{check_tables}}) { # We don't sync 'states' as it's transient and sometimes per-DB. @@ -16055,6 +16168,10 @@ sub resync_databases $anvil->data->{sys}{database}{resync_needed} = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'sys::database::resync_needed' => $anvil->data->{sys}{database}{resync_needed} }}); + my $time_taken = time - $start_time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { time_taken => $time_taken }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0674", variables => { took => $time_taken }}); + return(0); } @@ -16372,6 +16489,77 @@ sub write # Private functions # ############################################################################################################# +=head2 _add_to_local_config + +This adds this machine to the local C<< /etc/anvil/anvil.conf >> file. + +If successful, the host's UUID will be returned. If there's a problem, C<< !!error!! >> will be returned. + +=cut +sub _add_to_local_config +{ + 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->_add_to_local_config()" }}); + + my $host_uuid = $anvil->Get->host_uuid(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }}); + if ((not exists $anvil->data->{database}{$host_uuid}{password}) or (not $anvil->data->{database}{$host_uuid}{password})) + { + # Use the default password used in kickstart scripts. + $anvil->data->{database}{$host_uuid}{password} = $anvil->data->{defaults}{kickstart}{password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 1, level => $debug, list => { + "database::${host_uuid}::password" => $anvil->data->{database}{$host_uuid}{password}, + }}); + } + + # Write the password to a file. + my $password_file = "/tmp/striker-manage-peers.".$anvil->Get->uuid; + $anvil->Storage->write_file({ + debug => $debug, + secure => 1, + file => $password_file, + body => $anvil->data->{database}{$host_uuid}{password}, + mode => "0600", + overwrite => 1, + }); + + # Make the shell call, and parse the output looking for our own entry + my $shell_call = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$anvil->Get->host_uuid." --host localhost --port 5432 --password-file ".$password_file." --ping 0".$anvil->Log->switches; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host_uuid => $host_uuid, + shell_call => $shell_call, + }}); + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + + # Remove the password. + unlink $password_file; + + # Re-read the config and make sure we have our own entry. + $anvil->refresh(); + + # If we still don't have a local_uuid, something went wrong. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "database::${host_uuid}::host" => $anvil->data->{database}{$host_uuid}{host}, + "database::${host_uuid}::port" => $anvil->data->{database}{$host_uuid}{port}, + "database::${host_uuid}::password" => $anvil->Log->is_secure($anvil->data->{database}{$host_uuid}{password}), + "database::${host_uuid}::ping" => $anvil->data->{database}{$host_uuid}{ping}, + }}); + if (not $anvil->data->{database}{$host_uuid}{host}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0010"}); + return('!!error!!'); + } + + return($host_uuid); +} + =head2 _age_out_data @@ -16513,10 +16701,12 @@ sub _age_out_data # We don't use 'anvil->data' to prevent injecting SQL queries in anvil.conf my $to_clean = {}; - # Power, temperatures and ip addresses - $to_clean->{table}{temperature}{child_table}{temperature}{uuid_column} = "temperature_uuid"; - $to_clean->{table}{power}{child_table}{power}{uuid_column} = "power_uuid"; - $to_clean->{table}{ip_addresses}{child_table}{ip_addresses}{uuid_column} = "ip_address_uuid"; + # Power, temperatures, ip addresses and variables + $to_clean->{table}{temperature}{child_table}{temperature}{uuid_column} = "temperature_uuid"; + $to_clean->{table}{power}{child_table}{power}{uuid_column} = "power_uuid"; + $to_clean->{table}{ip_addresses}{child_table}{ip_addresses}{uuid_column} = "ip_address_uuid"; + $to_clean->{table}{variables}{child_table}{variables}{uuid_column} = "variable_uuid"; + $to_clean->{table}{network_interfaces}{child_table}{network_interfaces}{uuid_column} = "network_interface_uuid"; # scan_apc_pdu $to_clean->{table}{scan_apc_pdus}{child_table}{scan_apc_pdu_phases}{uuid_column} = "scan_apc_pdu_phase_uuid"; @@ -16549,7 +16739,7 @@ sub _age_out_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { table => $table }}); # Does the table exist? - $query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename='scan_apc_pdus' AND schemaname='public';"; + $query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename=".$anvil->Database->quote($table)." AND schemaname='public';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; @@ -16596,7 +16786,7 @@ sub _age_out_data count => $count, }}); - if ($count) + if ($count > 1) { # Find how many records will be left. If it's 0, we'll use an OFFSET 1. my $query = "SELECT history_id FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." AND modified_date > '".$old_timestamp."';"; @@ -16617,16 +16807,17 @@ sub _age_out_data } else { - # This would delete everything, reserve at least one record. - foreach my $row (@{$results}) - { - my $history_id = $row->[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { history_id => $history_id }}); - - my $query = "DELETE FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." AND history_id = '".$history_id."';"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - push @{$queries}, $query; - } + # This would delete everything, reserve at + # least one record. + my $query = "SELECT history_id FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." ORDER BY modified_date DESC LIMIT 1;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); + + my $history_id = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); + + $query = "DELETE FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." AND modified_date <= '".$old_timestamp."' AND history_id != '".$history_id."';"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); + push @{$queries}, $query; } } } @@ -17391,6 +17582,8 @@ This method takes a database UUID and tests the connection to it using the DBD ' This exists to handle the loss of a database mid-run where a normal query, which isn't wrapped in a query, could hang indefinately. +B<< Note >>: If there is no active handle, this returns 0 immediately. + =cut sub _test_access { @@ -17401,7 +17594,16 @@ sub _test_access $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->_test_access()" }}); my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + uuid => $uuid, + "cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid}, + }}); + + # If the handle is down, return 0. + if ((not exists $anvil->data->{cache}{database_handle}{$uuid}) or (not $anvil->data->{cache}{database_handle}{$uuid})) + { + return(0); + } # Make logging code a little cleaner my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name}; diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 19564b66..187eef77 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -31,6 +31,7 @@ my $THIS_FILE = "Get.pm"; # host_uuid_from_name # host_type # host_uuid +# kernel_release # md5sum # os_type # server_uuid_from_name @@ -1777,6 +1778,94 @@ sub host_uuid return($anvil->{HOST}{UUID}); } + +=head2 kernel_release + +This returns the kernel release (same output as C<>) on the local or remote host. If there is a problem, C<< !!error!! >> is returned. + +Parameters; + +=head3 password (optional) + +This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made. + +=head3 port (optional) + +This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used. + +=head3 remote_user (optional, default root) + +If C<< target >> is set, this will be the user we connect to the remote machine as. + +=head3 target (optional) + +This is the IP or host name of the machine to read the kernel release. If this is not set, the local system's kernel release is checked. + +=cut +sub kernel_release +{ + 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->kernel_release()" }}); + + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $port = defined $parameter->{port} ? $parameter->{port} : ""; + my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; + my $target = defined $parameter->{target} ? $parameter->{target} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + target => $target, + port => $port, + remote_user => $remote_user, + password => $anvil->Log->is_secure($password), + }}); + + my $kernel_release = ""; + my $return_code = ""; + my $shell_call = $anvil->data->{path}{exe}{uname}." --kernel-release"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + if ($anvil->Network->is_local({host => $target})) + { + # Local call + ($kernel_release, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + kernel_release => $kernel_release, + return_code => $return_code, + }}); + } + else + { + # Remote call + ($kernel_release, my $error, $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + kernel_release => $kernel_release, + error => $error, + return_code => $return_code, + }}); + + if ($return_code) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "err", key => "error_0356", variables => { + target => $target, + output => $kernel_release, + return_code => $return_code, + }}); + $kernel_release = "!!error!!"; + } + } + + return($kernel_release); +} + + =head2 md5sum This returns the C<< md5sum >> of a given file. diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 4cb7cd2a..98853fc9 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -2876,22 +2876,34 @@ sub ping $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); } $shell_call .= " || ".$anvil->data->{path}{exe}{echo}." timeout"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); my $pinged = 0; my $average_ping_time = 0; foreach my $try (1..$count) { last if $pinged; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count, try => $try }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + count => $count, + try => $try, + }}); my $output = ""; my $error = ""; # If the 'target' is set, we'll call over SSH unless 'target' is our host name. - if ($anvil->Network->is_local({host => $target})) + my $is_local = $anvil->Network->is_local({host => $target}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + target => $target, + is_local => $is_local, + }}); + if ($is_local) { ### Local calls - ($output, my $return_code) = $anvil->System->call({shell_call => $shell_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 => { output => $output, return_code => $return_code }}); } else diff --git a/Anvil/Tools/ScanCore.pm b/Anvil/Tools/ScanCore.pm index 9b50f8c0..1fe867b4 100644 --- a/Anvil/Tools/ScanCore.pm +++ b/Anvil/Tools/ScanCore.pm @@ -21,6 +21,7 @@ my $THIS_FILE = "ScanCore.pm"; # check_health # check_power # check_temperature +# check_temperature_direct # count_servers # post_scan_analysis # post_scan_analysis_dr @@ -198,7 +199,7 @@ sub agent_startup if (($anvil->data->{scancore}{$agent}{disable}) && (not $anvil->data->{switches}{force})) { # Exit. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0646", variables => { program => $THIS_FILE }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0646", variables => { program => $agent }}); $anvil->nice_exit({exit_code => 0}); } @@ -1160,6 +1161,109 @@ ORDER BY } +=head2 check_temperature_direct + +This calls a target's IPMI interface to check the temperature sensors that are available. The status is returns as; + + 0 = Failed to read temperature sensors / IPMI unavailable + 1 = All available temperatures are nominal. + 2 = One of more sensors are in warning or critical. + +Parameters; + +=head3 host_uuid (Optional, default Get->host_uuid() ) + +This is the host's UUID to look at. + +=cut +sub check_temperature_direct +{ + 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 => "ScanCore->check_temperature_direct()" }}); + + my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host_uuid => $host_uuid, + }}); + + # * 0 - Failed to read temperature sensors / IPMI unavailable + # * 1 - All available temperatures are nominal + # * 2 - One of more sensors are in warning or critical. + my $status = 0; + if ((not defined $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi}) or (not $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi})) + { + $anvil->Database->get_hosts_info({debug => $debug}); + } + my $host_ipmi = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi}; + my $host_name = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + host_ipmi => $host_ipmi, + host_name => $host_name, + }}); + + my ($ipmitool_command, $ipmi_password) = $anvil->Convert->fence_ipmilan_to_ipmitool({ + debug => 2, + fence_ipmilan_command => $host_ipmi, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + ipmitool_command => $ipmitool_command, + ipmi_password => $anvil->Log->is_secure($ipmi_password), + }}); + + if ((not $ipmitool_command) or ($ipmitool_command eq "!!error!!")) + { + # No IPMI tool to call. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0573", variables => { host_name => $host_name }}); + return($status); + } + + $anvil->System->collect_ipmi_data({ + debug => $debug, + host_name => $host_name, + ipmitool_command => $ipmitool_command, + ipmi_password => $ipmi_password, + }); + + # Now look for thermal values. + foreach my $sensor_name (sort {$a cmp $b} keys %{$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}}) + { + my $current_value = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_value_sensor_value}; + my $units = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_units}; + my $sensor_status = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + current_value => $current_value, + sensor_name => $sensor_name, + units => $units, + sensor_status => $sensor_status, + }}); + + # If this is a temperature, check to see if it is outside its nominal range and, if + # so, record it into a hash for loading into ScanCore's 'temperature' table. + if ($units eq "C") + { + if ($sensor_status eq "ok") + { + # We've found at least one temperature sensor. Set status to '1' if not previously set + $status = 1 if not $status; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); + } + else + { + # Sensor isn't OK yet. + $status = 2 if not $status; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); + } + } + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); + return($status); +} + + =head2 count_servers This returns the number of servers running on a given host, as reported by ScanCore (specifically, by counting the number of servers running on the host from the C<< servers >> table). It also counts the total amount of RAM in use by hosted servers. @@ -2527,9 +2631,7 @@ LIMIT 1;"; if (not $stop_reason) { $stop_reason = "unknown"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { stop_reason => $stop_reason }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0565", variables => { host_name => $host_name }}); - } if ($stop_reason eq "user") @@ -2538,7 +2640,71 @@ LIMIT 1;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0566", variables => { host_name => $host_name }}); next; } - elsif (($stop_reason eq "power") or ($stop_reason eq "unknown")) + elsif ($stop_reason eq "unknown") + { + # Check both power and temp. + if ((not defined $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'}) or (not exists $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'}) or ($anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'} eq "")) + { + $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'} = 1; + } + if (not $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'}) + { + # Ignore. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0671", variables => { host_name => $host_name }}); + } + else + { + # Evaluate for boot. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0672", variables => { host_name => $host_name }}); + + # Check power + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0567", variables => { host_name => $host_name }}); + my ($power_health, $shortest_time_on_batteries, $highest_charge_percentage, $estimated_hold_up_time) = $anvil->ScanCore->check_power({ + debug => $debug, + anvil_uuid => $anvil_uuid, + anvil_name => $anvil_name, + host_uuid => $host_uuid, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + power_health => $power_health, + shortest_time_on_batteries => $shortest_time_on_batteries, + highest_charge_percentage => $highest_charge_percentage, + estimated_hold_up_time => $estimated_hold_up_time, + }}); + + # Check temp. + my ($temp_health) = $anvil->ScanCore->check_temperature_direct({ + debug => $debug, + host_uuid => $host_uuid, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { temp_health => $temp_health }}); + + ### Temp + # * 0 = Failed to read temperature sensors / IPMI unavailable + # * 1 = All available temperatures are nominal. + # * 2 = One of more sensors are in warning or critical. + ### Power + # * 0 = No UPSes found for the host + # * 1 = One or more UPSes found and at least one has input power from mains. + # * 2 = One or more UPSes found, all are running on battery. + if (($temp_health eq "1") && ($power_health eq "1")) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0673", variables => { host_name => $host_name }}); + + $shell_call =~ s/--action status/ --action on/; + my ($output, $return_code) = $anvil->System->call({debug => $debug, timeout => 30, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + # Mark it as booting. + $anvil->Database->update_host_status({ + debug => $debug, + host_uuid => $host_uuid, + host_status => "booting", + }); + } + } + } + elsif ($stop_reason eq "power") { # Check now if the power is OK $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0567", variables => { host_name => $host_name }}); @@ -2590,72 +2756,20 @@ LIMIT 1;"; } elsif ($stop_reason eq "thermal") { - ### TODO: Switch to ->check_temperature() # Check now if the temperature is OK. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0568", variables => { host_name => $host_name }}); - - my ($ipmitool_command, $ipmi_password) = $anvil->Convert->fence_ipmilan_to_ipmitool({ - debug => 2, - fence_ipmilan_command => $host_ipmi, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - ipmitool_command => $ipmitool_command, - ipmi_password => $anvil->Log->is_secure($ipmi_password), - }}); - - if ((not $ipmitool_command) or ($ipmitool_command eq "!!error!!")) - { - # No IPMI tool to call. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0573", variables => { host_name => $host_name }}); - next; - } - - $anvil->System->collect_ipmi_data({ - host_name => $host_name, - ipmitool_command => $ipmitool_command, - ipmi_password => $ipmi_password, + my ($temp_health) = $anvil->ScanCore->check_temperature_direct({ + debug => $debug, + host_uuid => $host_uuid, }); - # Now look for thermal values. - my $sensor_found = 0; - my $temperatures_ok = 1; - foreach my $sensor_name (sort {$a cmp $b} keys %{$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}}) - { - my $current_value = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_value_sensor_value}; - my $units = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_units}; - my $status = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_status}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - current_value => $current_value, - sensor_name => $sensor_name, - units => $units, - status => $status, - }}); - - # If this is a temperature, check to see if it is outside its nominal range and, if - # so, record it into a hash for loading into ScanCore's 'temperature' table. - if ($units eq "C") - { - if (not $sensor_found) - { - # We've found at least one temperature sensor. - $sensor_found = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { sensor_found => $sensor_found }}); - } - - if ($status ne "ok") - { - # Sensor isn't OK yet. - $temperatures_ok = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { temperatures_ok => $temperatures_ok }}); - } - } - } + ### Temp + # * 0 = Failed to read temperature sensors / IPMI unavailable + # * 1 = All available temperatures are nominal. + # * 2 = One of more sensors are in warning or critical. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { temp_health => $temp_health }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - sensor_found => $sensor_found, - temperatures_ok => $temperatures_ok, - }}); - if (($sensor_found) && ($temperatures_ok)) + if ($temp_health eq "1") { ### TODO: We'll want to revisit M2's restart cooldown logic. It never ### actually proved useful in M2, but it doesn't mean it wouldn't help diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index 97d9a189..7ca03ec1 100644 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -14,6 +14,7 @@ my $THIS_FILE = "Server.pm"; ### Methods; # active_migrations # boot_virsh +# count_servers # find # get_definition # get_runtime @@ -263,6 +264,74 @@ WHERE return($success); } + +=head2 count_servers + +This method counts the number of hosted servers and returns that number. If C<< virsh >> is not available, C<< 0 >> is returned. Note that it's B< possible >>, though unlikely on an Anvil!, that a qemu server is running outside C<< libvirtd >>. + +This method takes no parameters. + +=cut +sub count_servers +{ + 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 => "Server->count_servers()" }}); + + my $count = 0; + if (-e $anvil->data->{path}{exe}{virsh}) + { + my $shell_call = $anvil->data->{path}{exe}{virsh}." list"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + + foreach my $line (split/\n/, $output) + { + $line = $anvil->Words->clean_spaces({string => $line}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + + if ($line =~ /^\d+ (.*) (.*?)$/) + { +=cut +* Server states; +running - The domain is currently running on a CPU +idle - The domain is idle, and not running or runnable. This can be caused because the domain is waiting on IO (a traditional wait state) or has gone to sleep because there was nothing else for it to do. +paused - The domain has been paused, usually occurring through the administrator running virsh suspend. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor. +in shutdown - The domain is in the process of shutting down, i.e. the guest operating system has been notified and should be in the process of stopping its operations gracefully. +shut off - The domain is not running. Usually this indicates the domain has been shut down completely, or has not been started. +crashed - The domain has crashed, which is always a violent ending. Usually this state can only occur if the domain has been configured not to restart on crash. +pmsuspended - The domain has been suspended by guest power management, e.g. entered into s3 state. +=cut + my $name = $1; + my $status = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + status => $status, + name => $name, + }}); + + if ((lc($status) eq "running") or + (lc($status) eq "paused") or + (lc($status) eq "in shutdown") or + (lc($status) eq "pmsuspended")) + { + $count++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); + } + } + } + + } + + return($count); +} + + =head2 find This will look on the local or a remote machine for the list of servers that are running. diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index d29a7fca..7afbc752 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -2177,6 +2177,7 @@ sub get_storage_group_from_path } # Is this a DRBD path? + my $gathered_data = 0; my $logical_volume = ""; if ($path !~ /drbd/) { @@ -2188,8 +2189,9 @@ sub get_storage_group_from_path # Looks like it. If the device path is '/dev/drbd/by-res/...' we'll need to pull out the # resource name (server name) and volume number as the path only actually exists when DRBD is # up and isn't referenced in the config file. - my $resource = ""; - my $volume = ""; + my $resource = ""; + my $volume = ""; + $gathered_data = 1; $anvil->DRBD->gather_data({debug => $debug}); if ($path =~ /\/dev\/drbd\/by-res\/(.*)\/(\d+)$/) { @@ -2342,10 +2344,13 @@ LIMIT 1 scan_drbd_resource_xml => $scan_drbd_resource_xml, }}); - $anvil->DRBD->gather_data({ - debug => 3, - xml => $scan_drbd_resource_xml, - }); + if (not $gathered_data) + { + $anvil->DRBD->gather_data({ + debug => 3, + xml => $scan_drbd_resource_xml, + }); + } # Dig out the LV behind the volume. foreach my $this_host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{host}}) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index e4483c6c..f4198021 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -654,6 +654,159 @@ sub check_memory } +=head2 check_ram_use + +This is meant to be used by daemons to check how much RAM it is using. It returns an anonymous array with the first value being C<< 0 >> if the in-use RAM is below the maximum, and C<< 1 >> it the in-use RAM is too high. The second value is the amount of RAM in use, in bytes. If the program is not found to be running, C<< 2, 0 >> is returned. + + my ($problem, $used_ram) = $anvil->System->check_ram_use({ + program => $THIS_FILE, + max_ram => 1073741824, + }); + +Parameters; + +=head3 program (required) + +This is generally C<< $THIS_FILE >>. Though this could be used to check the RAM use of other programs. + +=head3 max_ram (optional, default '1073741824' (1 GiB)) + +This is the limit allowed. If the in-use RAM is greater than this amount, an alert will be generated and sent. + +=cut +sub check_ram_use +{ + 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->check_ram_use()" }}); + + my $program = defined $parameter->{program} ? $parameter->{program} : ""; + my $max_ram = defined $parameter->{max_ram} ? $parameter->{max_ram} : 1073741824; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + program => $program, + max_ram => $max_ram, + }}); + + # Find the PID(s) of the program. + my $problem = 0; + my $ram_used = 0; + + # See if we're a daemon running under systemctl. If so, the memory reported includes all spawned + # child programs, swap, etc. Much more thorough. + my $shell_call = $anvil->data->{path}{exe}{systemctl}." status ".$program." --lines=0"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + if ($line =~ /Memory: (.*)?/) + { + my $memory = $1; + my $in_bytes = $anvil->Convert->human_readable_to_bytes({size => $memory, base2 => 1}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + memory => $memory, + in_bytes => $anvil->Convert->add_commas({number => $in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $in_bytes}).")", + }}); + if ($in_bytes =~ /^\d+$/) + { + $ram_used = $in_bytes; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")", + }}); + } + last; + } + } + + # If we didn't get the RAM from systemctl, read smaps + if (not $ram_used) + { + my $pids = $anvil->System->pids({debug => $debug, program_name => $program}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids => $pids }}); + + my $pids_found = @{$pids}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids_found => $pids_found }}); + + if (not $pids_found) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0135", variables => { program => $program }}); + return(2, 0); + } + + # Read in the smaps for each pid + foreach my $pid (sort {$a cmp $b} @{$pids}) + { + my $smaps_path = "/proc/".$pid."/smaps"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smaps_path => $smaps_path }}); + + # This will store the amount of RAM used by this specific PID. + $anvil->data->{memory}{pid}{$pid} = 0; + + if (not -e $smaps_path) + { + # It is possible that the program just closed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0433", variables => { pid => $pid }}); + next; + } + + # Read in the file. + my $body = $anvil->Storage->read_file({debug => $debug, file => $smaps_path}); + foreach my $line (split/\n/, $body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + if ($line =~ /^Private_Dirty:\s+(\d+) (.*B)$/) + { + my $size = $1; + my $type = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + type => $type, + size => $size, + }}); + next if not $size; + next if $size =~ /\D/; + + # This uses 'kB' for 'KiB' >_> + $type = lc($type); + $type =~ s/b$/ib/ if $type !~ /ib$/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); + + my $size_in_bytes = $anvil->Convert->human_readable_to_bytes({size => $size, type => $type, base2 => 1}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + size_in_bytes => $anvil->Convert->add_commas({number => $size_in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size_in_bytes}).")", + }}); + + $anvil->data->{memory}{pid}{$pid} += $size_in_bytes; + $ram_used += $size_in_bytes; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "memory::pid::${pid}" => $anvil->Convert->add_commas({number => $anvil->data->{memory}{pid}{$pid}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{memory}{pid}{$pid}}).")", + ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")", + }}); + } + } + } + } + + # Are we using too much RAM? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + max_ram => $anvil->Convert->add_commas({number => $max_ram})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_ram}).")", + ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")", + }}); + if ($ram_used > $max_ram) + { + $problem = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { problem => $problem }}); + } + + return($problem, $ram_used); +} + =head2 check_ssh_keys This method does several things; @@ -728,10 +881,29 @@ sub check_ssh_keys $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0270", variables => { user => $user }}); my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{'ssh-keygen'}." -t rsa -N \"\" -b 8191 -f ".$ssh_private_key_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + output => $output, + return_code => $return_code, + }}); if (-e $ssh_public_key_file) { # Success! $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0271", variables => { user => $user, output => $output }}); + + # Set the ownership + foreach my $file ($ssh_private_key_file, $ssh_public_key_file) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0682", variables => { + file => $file, + user => $user, + }}); + $anvil->Storage->change_owner({ + debug => 2, + path => $file, + user => $user, + group => $user, + }); + } } else { @@ -1770,6 +1942,16 @@ LIMIT 1 password_length => $password_length, }}); + # If the password has spaces, some IPMI BMCs won't allow them. If we need to use it, we'll take out + # the spaces and shrink the length. + my $ipmi_no_space_password = ""; + if ($ipmi_password =~ /\s/) + { + $ipmi_no_space_password = $ipmi_password; + $ipmi_no_space_password =~ s/\s//g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { ipmi_no_space_password => $ipmi_no_space_password }}); + } + my $subnet_mask = ""; my $gateway = ""; my $in_network = ""; @@ -1858,7 +2040,7 @@ LIMIT 1 if (not $has_ipmi) { # Return - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "err", key => "log_0499"}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, priority => "err", key => "log_0499"}); return(0); } @@ -2075,6 +2257,7 @@ LIMIT 1 my $wait_until = time + 120; while ($waiting) { + my $debug = 2; my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{ipmitool}." user list ".$lan_channel}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, @@ -2118,6 +2301,8 @@ LIMIT 1 } } } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user_name => $user_name }}); + last if $user_name; # Try again later or give up? if (time > $wait_until) @@ -2137,6 +2322,7 @@ LIMIT 1 sleep 10; } } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { user_name => $user_name }}); if (not $user_name) { # Failed to find a user. @@ -2225,6 +2411,13 @@ LIMIT 1 } else { + # If we used the no-space password, set it as the ipmi_password now. + if ($ipmi_no_space_password) + { + $ipmi_password = $ipmi_no_space_password; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { ipmi_password => $ipmi_password }}); + } + # Change the password and then try again. my $escaped_ipmi_password = shell_quote($ipmi_password); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { escaped_ipmi_password => $escaped_ipmi_password }}); @@ -3152,6 +3345,7 @@ sub host_name return($host_name, $descriptive); } + =head2 maintenance_mode This sets, clears or checks if the local system is in maintenance mode. Any system in maintenance mode will not be used by normal Anvil! tasks. diff --git a/anvil.conf b/anvil.conf index a292cebe..15eb02e8 100644 --- a/anvil.conf +++ b/anvil.conf @@ -11,6 +11,11 @@ sys::privacy::strong = 0 # feature, set this to '1'. feature::scancore::disable::preventative-live-migration = 0 +# If a node is found to be powered off, and there is no reason recorded in the database, it will be booted. +# The assumption is that an accidental power off occurred. If you would like to have nodes that power off +# stay off until manually started, set this to '0' +#feature::scancore::disable::boot-unknown-stop = 1 + ### Database # Database connections; # diff --git a/anvil.spec.in b/anvil.spec.in index d1952b3b..8489e2e4 100644 --- a/anvil.spec.in +++ b/anvil.spec.in @@ -63,6 +63,7 @@ Requires: mailx Requires: mlocate Requires: net-snmp-utils Requires: nvme-cli +Requires: pciutils Requires: perl-Capture-Tiny Requires: perl-Data-Dumper Requires: perl-Data-Validate-Domain @@ -131,6 +132,7 @@ Requires: gdm Requires: gnome-terminal Requires: httpd Requires: nmap +Requires: openssh-askpass Requires: postgresql-server Requires: syslinux Requires: syslinux-nonlinux @@ -237,6 +239,8 @@ systemctl enable chronyd.service systemctl start chronyd.service systemctl enable anvil-daemon.service systemctl restart anvil-daemon.service +systemctl enable scancore.service +systemctl restart scancore.service %post striker @@ -252,9 +256,10 @@ then systemctl enable gdm.service fi -echo "Preparing the database" -striker-prep-database -anvil-update-states +### This is handled by anvil-daemon now +#echo "Preparing the database" +#striker-prep-database +#anvil-update-states # Touch the system type file. echo "Touching the system type file" diff --git a/cgi-bin/striker b/cgi-bin/striker index 85bc0858..807767b2 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -265,7 +265,7 @@ sub process_task $anvil->data->{cgi}{login}{value} = "" if not defined $anvil->data->{cgi}{login}{value}; $anvil->data->{cgi}{logout}{value} = "" if not defined $anvil->data->{cgi}{logout}{value}; $anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::login::value" => $anvil->data->{cgi}{login}{value}, "cgi::logout::value" => $anvil->data->{cgi}{logout}{value}, "cgi::save::value" => $anvil->data->{cgi}{save}{value}, @@ -297,14 +297,14 @@ sub process_task # 1 - No cookie was found or read. The user needs to log in # 2 - There was a problem reading the user's UUID (it wasn't found in the database), so the # cookies were deleted (via C<< Account->logout() >>. The user needs to log back in. - # 3 - There user's hash is invalid, it is probably expired. The user has been logged out and + # 3 - Their user's hash is invalid, it is probably expired. The user has been logged out and # needs to log back in. - my $cookie_problem = $anvil->Account->read_cookies(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { cookie_problem => $cookie_problem }}); + my $cookie_problem = $anvil->Account->read_cookies({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cookie_problem => $cookie_problem }}); if (not $cookie_problem) { $logged_in = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { logged_in => $logged_in }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { logged_in => $logged_in }}); } } @@ -3500,7 +3500,12 @@ sub sanity_check_manifest_step3 # Is the IP valid? if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$machine_ip_key}{value}, debug => 2})) { - # Bad subnet + # Bad subnet. If this is DR IFN 1, and the value was empty, ignore it + # as there simply is no DR on this cluster. + if (($machine eq "dr1") && ($anvil->data->{cgi}{$machine_ip_key}{value} eq "")) + { + next; + } my $say_network = "#!string!striker_0255!#"; if ($machine eq "node2") { $say_network = "#!string!striker_0256!#"; } elsif ($machine eq "dr1") { $say_network = "#!string!striker_0257!#"; } @@ -4798,7 +4803,7 @@ sub process_fences # We add in 'name' $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{unique} = "0"; - $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required} = "0"; + $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required} = "1"; $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description} = "#!string!striker_0223!#"; $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type} = "string"; $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'} = ""; @@ -6446,6 +6451,7 @@ sub process_power my $job_description = "job_0006"; my $say_title = "#!string!job_0005!#"; my $say_description = "#!string!job_0006!#"; + my $say_reason = "log_0199"; if ($task eq "poweroff") { $job_command = $anvil->data->{path}{exe}{'anvil-manage-power'}." --poweroff -y".$anvil->Log->switches; @@ -6453,7 +6459,9 @@ sub process_power $job_description = "job_0008"; $say_title = "#!string!job_0007!#"; $say_description = "#!string!job_0008!#"; + $say_reason = "log_0200"; } + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => $say_reason }}); my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ file => $THIS_FILE, line => __LINE__, diff --git a/configure.ac b/configure.ac index 6b8de709..657aff01 100644 --- a/configure.ac +++ b/configure.ac @@ -103,9 +103,9 @@ AC_SUBST([OCFROOT]) ANVIL_PKG_CHECK_VAR([FASEXECPREFIX_TMP], [fence-agents], [exec_prefix], [${prefix}]) if test "${prefix}" != "/usr"; then - FASEXECPREFIX="${prefix}/$FASEXECPREFIX_TMP" + FASEXECPREFIX="${prefix}/${FASEXECPREFIX_TMP}" else - FASEXECPREFIX="FASEXECPREFIX_TMP" + FASEXECPREFIX="${FASEXECPREFIX_TMP}" fi AC_SUBST([FASEXECPREFIX]) diff --git a/notes b/notes index 7fa37928..85a9cc5a 100644 --- a/notes +++ b/notes @@ -1,3 +1,29 @@ +# Configure APC PDUs and UPSes +tcpip -i 10.201.2.3 -s 255.255.0.0 -g 10.201.255.254 +web -h enable +web -s enable +snmp -S enable -c1 private -a1 writeplus +snmp -S enable -c2 public -a2 writeplus + +Anvil! to Anvil! live migration; +1. Create LVs +2. Make sure /etc/hosts is populated +3. If DR is used, disconnect first to stay within the max-peers=3 +3. Update dbrd config, A:1 -> A:2, A:1 -> B:1, B:1 -> B:2 (if both online and UpToDate, otherwise both from UpToDate) +4. Create drbd md on new Anvil! +5. drbdadm adjust on old nodes. +6. Wait for DRBD resource to sync to node 1 (it can sync to node 2 later) +7. Copy server's XML to new cluster +8. pcs resource unmanage srv01-cs8 +9. Allow dual primary between A1:B1 (or A2:B1) - +[root@an-a01n01 ~]# pcs resource disable srv01-cs8 +Warning: 'srv01-cs8' is unmanaged +[root@an-a01n01 ~]# pcs resource manage srv01-cs8 +[root@an-a01n01 ~]# pcs resource delete srv01-cs8 +Deleting Resource - srv01-cs8 +10. + + TODO: - Remove this; (step 2) "This is the user name that you will log into Striker as and the name of the user that owns the database" - Being set to the gateway, not the default DNS - "This is the domain name server(s) to use when resolving domain names. You can specify 2 or more, separated by commas." @@ -18,6 +44,8 @@ SELECT a.scan_apc_ups_name AS name, a.scan_apc_ups_serial_number AS sn, a.scan_a ============ +dnf -y install augeas + Jenkins; @@ -742,9 +770,11 @@ mediawiki on EL8 install notes (starting from a minimal install); dnf module reset php dnf module enable php:7.4 + +# All dnf install httpd php php-gd php-xml php-mbstring php-json \ vim bash-completion wget tar rsync mlocate php-pecl-apcu \ - memcached php-pear icu php-intl php-pgsql bzip2 + memcached php-pear icu php-intl php-pgsql bzip2 mod_ssl ### PostgreSQL dnf install postgresql-server postgresql-plperl @@ -753,7 +783,9 @@ systemctl start postgresql.service systemctl enable postgresql.service ### MariaDB -dnf install php-mysqlnd php-gd php-xml mariadb-server mariadb +dnf install httpd php php-gd php-xml php-mbstring php-json \ + php-mysqlnd php-gd php-xml mariadb-server mariadb \ + systemctl start mariadb mysql_secure_installation |Set root password? [Y/n] y @@ -766,40 +798,30 @@ mysql_secure_installation |Reload privilege tables now? [Y/n] y mysql -u root -p ### In mariadb -MariaDB [(none)]> CREATE DATABASE digimer_wiki; -MariaDB [(none)]> CREATE USER 'digimer'@'localhost' IDENTIFIED BY 'Initial1'; -MariaDB [(none)]> GRANT ALL PRIVILEGES ON digimer_wiki.* TO 'digimer'@'localhost'; +MariaDB [(none)]> CREATE DATABASE an_wiki; +MariaDB [(none)]> CREATE USER 'alteeve'@'localhost' IDENTIFIED BY 'experience tell mineral'; +MariaDB [(none)]> GRANT ALL PRIVILEGES ON an_wiki.* TO 'alteeve'@'localhost'; MariaDB [(none)]> FLUSH PRIVILEGES; MariaDB [(none)]> SHOW DATABASES; +--------------------+ | Database | +--------------------+ -| digimer_wiki | +| an_wiki | | information_schema | | mysql | | performance_schema | +--------------------+ -MariaDB [(none)]> SHOW GRANTS FOR 'digimer'@'localhost'; +MariaDB [(none)]> SHOW GRANTS FOR 'alteeve'@'localhost'; +----------------------------------------------------------------------------------------------------------------+ | Grants for digimer@localhost | +----------------------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO `digimer`@`localhost` IDENTIFIED BY PASSWORD '*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | -| GRANT ALL PRIVILEGES ON `digimer_wiki`.* TO `digimer`@`localhost` | +| GRANT ALL PRIVILEGES ON `an_wiki`.* TO `digimer`@`localhost` | +----------------------------------------------------------------------------------------------------------------+ MariaDB [(none)]> exit # Back to terminal systemctl enable mariadb -# Common -systemctl start httpd.service -systemctl enable httpd.service -systemctl start memcached.service -systemctl enable memcached.service -firewall-cmd --permanent --zone=public --add-service=http -firewall-cmd --permanent --zone=public --add-service=https -systemctl restart firewalld - - # diff -u /var/lib/pgsql/data/pg_hba.conf.orig /var/lib/pgsql/data/pg_hba.conf ==== --- /var/lib/pgsql/data/pg_hba.conf.orig 2021-02-17 02:50:10.959000000 -0500 @@ -834,6 +856,47 @@ systemctl restart firewalld ;;;; ; Note: packaged extension modules are now loaded via the .ini files + + +# Download and install +cd /var/www/ +wget https://releases.wikimedia.org/mediawiki/1.37/mediawiki-1.37.1.tar.gz +tar -xvzf mediawiki-1.37.1.tar.gz +cd /var/www/html +ln -s ../mediawiki-1.37.1 ./w + +systemctl enable httpd.service +systemctl enable memcached.service +systemctl start httpd.service +systemctl start memcached.service + +firewall-cmd --zone=public --add-service=http --permanent +firewall-cmd --zone=public --add-service=https --permanent +firewall-cmd --reload + +### Certbot / Let's Encrypt +# EPEL / snapd +dnf config-manager --set-enabled powertools +dnf install epel-release epel-next-release +dnf install snapd +systemctl enable --now snapd.socket +ln -s /var/lib/snapd/snap /snap + +### Setup vhost +# httpd.conf + + +### Log out and back in to ensure snapd path +# If the next step fails with "too early for operation, device not yet seeded or device model not acknowledged", restart snapd +snap install core +snap refresh core +snap install --classic certbot + +# certbot +certbot --apache + +# answer questions + ==== Dell S4128T-ON Configuration @@ -960,19 +1023,24 @@ OS10(config)# write memory OS10(config)# hostname zo-switch01 zo-switch01(config)# interface vlan 100 zo-switch01(conf-if-vl-100)# description BCN1 +zo-switch01(config)# exit zo-switch01(conf-if-vl-100)# interface range ethernet 1/1/1-1/1/14 zo-switch01(conf-range-eth1/1/1-1/1/10)# switchport access vlan 100 zo-switch01(conf-range-eth1/1/1-1/1/10)# no shutdown zo-switch01(conf-range-eth1/1/1-1/1/10)# exit + zo-switch01(config)# interface vlan 200 zo-switch01(conf-if-vl-200)# description SN1 -zo-switch01(conf-if-vl-200)# interface range ethernet 1/1/11-1/1/14 +zo-switch01(conf-if-vl-200)# exit +zo-switch01(config)# interface range ethernet 1/1/11-1/1/14 zo-switch01(conf-range-eth1/1/11-1/1/14)# switchport access vlan 200 zo-switch01(conf-range-eth1/1/11-1/1/14)# no shutdown zo-switch01(conf-range-eth1/1/11-1/1/14)# exit + zo-switch01(config)# interface vlan 300 zo-switch01(conf-if-vl-300)# description IFN1 -zo-switch01(conf-if-vl-300)# interface range ethernet 1/1/15-1/1/24 +zo-switch01(conf-if-vl-300)# exit +zo-switch01(config)# interface range ethernet 1/1/15-1/1/24 zo-switch01(conf-range-eth1/1/15-1/1/24)# switchport access vlan 300 zo-switch01(conf-range-eth1/1/15-1/1/24)# no shutdown zo-switch01(conf-range-eth1/1/15-1/1/24)# exit @@ -1223,13 +1291,33 @@ rs-striker03(config-if)#switchport access vlan 100 rs-striker03(config-if)#no shutdown rs-striker03(config-if)#exit -rs-striker03(config)#interface vlan 300 -rs-striker03(config)#name IFN -rs-striker03(config-if-vlan300)#interface range gigabitethernet1/0/15-24,gigabitethernet2/0/15-24 -rs-striker03(config-if)#switchport access vlan 300 -rs-striker03(config-if)#no shutdown -rs-striker03(config-if)#exit -rs-striker03(config)#exit +#### NOTE: Put IP on VID 1! + +rs-switch03(config)#show vlan + +VLAN Name Ports Type +----- --------------- ------------- -------------- +1 default Po1-128, Default + Gi1/0/1-12, + Te1/0/1-4, + Gi2/0/1-12, + Te2/0/1-4 +300 IFN1 Gi1/0/13-24, Static + Gi2/0/13-24 + +rs-switch03(config)#interface vlan 1 + +rs-switch03(config-if-vlan1)#ip address 10.201.1.3 255.255.0.0 + +rs-switch03(config-if-vlan1)#exit + +rs-switch03(config)#exit + +rs-switch03#copy running-config startup-config + +########################### + + rs-striker03#show vlan @@ -1412,3 +1500,33 @@ totem.transport (str) = knet Gi1/0/24 + Gi2/0/24 +Dell LACP Config (OS10 - https://www.dell.com/support/kbdoc/en-us/000102901/dell-emc-networking-os10-how-to-set-up-virtual-link-trunking-vlt) + +* On both switches; +zo-switch02# configure terminal + +* IFN Port channel is 3 +zo-switch02(config)# interface port-channel 3 +zo-switch02(conf-if-po-3)# <165>1 2021-10-19T04:58:56.022086+00:00 zo-switch02 dn_alm 920 - - Node.1-Unit.1:PRI [event], Dell EMC (OS10) %IFM_ASTATE_UP: Interface admin state up :port-channel3 +<165>1 2021-10-19T04:58:56.022722+00:00 zo-switch02 dn_alm 920 - - Node.1-Unit.1:PRI [event], Dell EMC (OS10) %IFM_OSTATE_DN: Interface operational state is down :port-channel3 +zo-switch02(conf-if-po-3)# lacp fallback enable +zo-switch02(conf-if-po-3)# description IFN1 +zo-switch02(conf-if-po-3)# exit +zo-switch02(config)# exit +zo-switch02# show port-channel summary + +Flags: D - Down I - member up but inactive P - member up and active + U - Up (port-channel) F - Fallback Activated +-------------------------------------------------------------------------------- +Group Port-Channel Type Protocol Member Ports +-------------------------------------------------------------------------------- +3 port-channel3 (D) Eth STATIC +1000 port-channel1000 (U) Eth STATIC 1/1/25(P) 1/1/26(P) + +zo-switch02# configure terminal +zo-switch02(config)# interface ethernet 1/1/24 +zo-switch02(conf-if-eth1/1/24)# channel-group 3 +zo-switch02(conf-if-eth1/1/24)# <165>1 2021-10-19T05:09:41.237808+00:00 zo-switch02 dn_alm 920 - - Node.1-Unit.1:PRI [event], Dell EMC (OS10) %IFM_OSTATE_UP: Interface operational state is up :port-channel3 +exit +exit + diff --git a/scancore-agents/scan-apc-ups/scan-apc-ups b/scancore-agents/scan-apc-ups/scan-apc-ups index 3c5b2b15..94c5c2fe 100755 --- a/scancore-agents/scan-apc-ups/scan-apc-ups +++ b/scancore-agents/scan-apc-ups/scan-apc-ups @@ -1480,8 +1480,8 @@ WHERE my $alert_sent = 0; my $variables = { ups_name => $scan_apc_ups_name, - new_value => $scan_apc_ups_battery_model, - old_value => $old_scan_apc_ups_battery_model, + new_value => $scan_apc_ups_battery_percentage_charge, + old_value => $old_scan_apc_ups_battery_percentage_charge, battery_number => $battery_number, low_charge_clear => $anvil->data->{'scan-apc-ups'}{low_charge_percentage_ok}, low_charge_alert => $anvil->data->{'scan-apc-ups'}{low_charge_percentage_warning}, diff --git a/scancore-agents/scan-cluster/scan-cluster b/scancore-agents/scan-cluster/scan-cluster index 6bf45ce9..9e13d4d6 100755 --- a/scancore-agents/scan-cluster/scan-cluster +++ b/scancore-agents/scan-cluster/scan-cluster @@ -214,7 +214,7 @@ sub check_fence_delay }}); if ((not $local_server_count) && (not $peer_server_count)) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0636"}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0636"}); return(0); } elsif (($local_server_count) && ($peer_server_count)) diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 71fc5b73..249db986 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -565,6 +565,13 @@ sub collect_data { $media = lc($1); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + + # This can be 'tp mii', which breaks json. + if ($media =~ /\t/) + { + $media =~ s/\t/,/g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + } last; } } @@ -791,18 +798,303 @@ sub read_last_scan return(0); } -# There is a bug somewhere where interfaces and ip addresses are periodically being added twice per host. -# This checks for / cleans those up. Remove this when the core issue is resolved. +# There is a bug somewhere where interfaces, bridges and ip addresses are periodically being added twice per +# host. This checks for / cleans those up. Remove this when the core issue is resolved. sub clear_duplicates { my ($anvil) = @_; + # Look for duplicate bridges. my $query = " +SELECT + bridge_uuid, + bridge_name, + bridge_id, + bridge_mac_address +FROM + bridges +WHERE + bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +ORDER BY + bridge_name ASC, + bridge_id DESC +;"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $bridge_uuid = $row->[0]; + my $bridge_name = $row->[1]; + my $bridge_id = $row->[2]; + my $bridge_mac_address = $row->[3]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_uuid => $bridge_uuid, + bridge_name => $bridge_name, + bridge_id => $bridge_id, + bridge_mac_address => $bridge_mac_address, + }}); + + if (not exists $anvil->data->{duplicate_bridges}{seen}{$bridge_name}) + { + $anvil->data->{duplicate_bridges}{seen}{$bridge_name} = []; + } + push @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}, $bridge_uuid; + + $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name} = $bridge_name; + $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address} = $bridge_mac_address; + $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id} = $bridge_id; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_name" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}, + "duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_id" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, + "duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_mac_address" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, + }}); + + $anvil->data->{deleted_bridges}{$bridge_uuid} = 0; + } + foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bridges}{seen}}) + { + my $count = @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:bridge_name' => $bridge_name, + 's2:count' => $count, + }}); + + if ($count > 1) + { + # Duplicate! Is one of them marked as DELETED? + foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}) + { + # Is this one deleted? + my $bridge_mac_address = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}; + my $bridge_id = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_uuid => $bridge_uuid, + bridge_mac_address => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, + bridge_id => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, + }}); + if ($bridge_id eq "DELETED") + { + # Take this one out. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { + name => $bridge_name, + uuid => $bridge_uuid, + }}); + + my $queries = []; + push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + + # Write it out. + $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); + + $count--; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + $anvil->data->{deleted_bridges}{$bridge_uuid} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid}, + }}); + } + last if $count == 1; + } + + # If count is still > 1, we need to arbitrarily delete an interface. + if ($count > 1) + { + foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { + name => $bridge_name, + uuid => $bridge_uuid, + }}); + + my $queries = []; + push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + + # Write it out. + $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); + + $count--; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + $anvil->data->{deleted_bridges}{$bridge_uuid} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid}, + }}); + } + last if $count == 1; + } + } + } + delete $anvil->data->{duplicate_bridges}; + + # Load the bridges again. + $anvil->Database->get_bridges({include_deleted => 1}); + + # Look for duplicate bonds. + $query = " +SELECT + bond_uuid, + bond_name, + bond_operational, + bond_mac_address, + bond_bridge_uuid +FROM + bonds +WHERE + bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +ORDER BY + bond_name ASC, + bond_operational DESC +;"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $bond_uuid = $row->[0]; + my $bond_name = $row->[1]; + my $bond_operational = $row->[2]; + my $bond_mac_address = $row->[3]; + my $bond_bridge_uuid = defined $row->[4] ? $row->[4] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bond_uuid => $bond_uuid, + bond_name => $bond_name, + bond_operational => $bond_operational, + bond_mac_address => $bond_mac_address, + bond_bridge_uuid => $bond_bridge_uuid, + }}); + + if (not exists $anvil->data->{duplicate_bonds}{seen}{$bond_name}) + { + $anvil->data->{duplicate_bonds}{seen}{$bond_name} = []; + } + push @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}, $bond_uuid; + + $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name} = $bond_name; + $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address} = $bond_mac_address; + $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational} = $bond_operational; + $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid} = $bond_bridge_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "duplicate_bonds::bond_uuid::${bond_uuid}::bond_name" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name}, + "duplicate_bonds::bond_uuid::${bond_uuid}::bond_operational" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational}, + "duplicate_bonds::bond_uuid::${bond_uuid}::bond_mac_address" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}, + "duplicate_bonds::bond_uuid::${bond_uuid}::bond_bridge_uuid" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}, + }}); + + $anvil->data->{deleted_bonds}{$bond_uuid} = 0; + } + foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bonds}{seen}}) + { + my $count = @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:bond_name' => $bond_name, + 's2:count' => $count, + }}); + + if ($count > 1) + { + # Duplicate! Is one of them marked as DELETED? + foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}) + { + # Is this one deleted? + my $bond_mac_address = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}; + my $bond_operational = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational}; + my $bond_bridge_uuid = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bond_uuid => $bond_uuid, + bond_mac_address => $bond_mac_address, + bond_operational => $bond_operational, + bond_bridge_uuid => $bond_bridge_uuid, + }}); + if ((($bond_bridge_uuid) && ($anvil->data->{deleted_bridges}{$bond_bridge_uuid})) or ($bond_operational eq "DELETED")) + { + # Take this one out. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { + name => $bond_name, + uuid => $bond_uuid, + }}); + + my $queries = []; + push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + + # Write it out. + $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); + + $count--; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + $anvil->data->{deleted_bonds}{$bond_uuid} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid}, + }}); + } + } + + # If count is still > 1, we need to arbitrarily delete an interface. + if ($count > 1) + { + foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { + name => $bond_name, + uuid => $bond_uuid, + }}); + + my $queries = []; + push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; + + # Write it out. + $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); + + $count--; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + $anvil->data->{deleted_bonds}{$bond_uuid} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid}, + }}); + } + last if $count == 1; + } + } + } + delete $anvil->data->{duplicate_bonds}; + + + # Look for duplicate network interfaces + $query = " SELECT network_interface_uuid, network_interface_name, network_interface_mac_address, - network_interface_operational + network_interface_operational, + network_interface_bond_uuid, + network_interface_bridge_uuid FROM network_interfaces WHERE @@ -810,23 +1102,27 @@ WHERE ORDER BY network_interface_name ASC;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); - my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - my $count = @{$results}; + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { - my $network_interface_uuid = $row->[0]; - my $network_interface_name = $row->[1]; - my $network_interface_mac_address = $row->[2]; - my $network_interface_operational = $row->[3]; + my $network_interface_uuid = $row->[0]; + my $network_interface_name = $row->[1]; + my $network_interface_mac_address = $row->[2]; + my $network_interface_operational = $row->[3]; + my $network_interface_bond_uuid = defined $row->[4] ? $row->[4] : ""; + my $network_interface_bridge_uuid = defined $row->[5] ? $row->[5] : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, network_interface_name => $network_interface_name, network_interface_mac_address => $network_interface_mac_address, network_interface_operational => $network_interface_operational, + network_interface_bond_uuid => $network_interface_bond_uuid, + network_interface_bridge_uuid => $network_interface_bridge_uuid, }}); if (not exists $anvil->data->{duplicate_nics}{seen}{$network_interface_name}) @@ -838,10 +1134,14 @@ ORDER BY $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $network_interface_operational; + $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = $network_interface_bond_uuid; + $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = $network_interface_bridge_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_operational" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}, + "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}, + "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}, }}); } foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_nics}{seen}}) @@ -860,12 +1160,18 @@ ORDER BY # Is this one deleted? my $network_interface_mac_address = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; my $network_interface_operational = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; + my $network_interface_bond_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; + my $network_interface_bridge_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, - network_interface_mac_address => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, - network_interface_operational => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}, + network_interface_mac_address => $network_interface_mac_address, + network_interface_operational => $network_interface_operational, + network_interface_bond_uuid => $network_interface_bond_uuid, + network_interface_bridge_uuid => $network_interface_bridge_uuid, }}); - if ($network_interface_operational eq "DELETED") + if ((($network_interface_bond_uuid) && ($anvil->data->{deleted_bonds}{$network_interface_bond_uuid})) or + (($network_interface_bridge_uuid) && ($anvil->data->{deleted_bridges}{$network_interface_bridge_uuid})) or + ($network_interface_operational eq "DELETED")) { # Take this one out. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0647", variables => { @@ -880,7 +1186,6 @@ ORDER BY $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); } - last if $count == 1; } # If count is still > 1, we need to arbitrarily delete an interface. @@ -894,6 +1199,7 @@ ORDER BY }}); my $query = "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); $count--; @@ -997,6 +1303,7 @@ ORDER BY }}); my $query = "DELETE FROM ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); $count--; @@ -1007,6 +1314,7 @@ ORDER BY } } + return(0); } @@ -3450,9 +3758,11 @@ AND # Don't set / clear interfaces that appear down but aren't named ifn/bcn/sn as they're probably # unconfigured/unusued interfaces. - my $problem = 0; - my $check = 0; - if ($anvil->Network->is_our_interface({interface => $network_interface_name})) + my $problem = 0; + my $check = 0; + my $monitored = $anvil->Network->is_our_interface({interface => $network_interface_name}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { monitored => $monitored }}); + if ($monitored) { # One we monitor $check = 1; diff --git a/share/words.xml b/share/words.xml index 8b6c8946..dcf027fa 100644 --- a/share/words.xml +++ b/share/words.xml @@ -16,7 +16,7 @@ Author: Madison Kelly Anvil! Striker ScanCore - Alteeve's Niche! Inc., Toronto, Ontario, Canada]]> + Alteeve's Niche! Inc., Toronto, Ontario, Canada]]> Anvil!]]> Node DR Host @@ -501,6 +501,8 @@ The output, if any, was; ==== Failed to load the database file: [#!variable!file!#]. Deleting it so it's not considered in the next load attempt. + Failed to read the kernel release on the host: [#!variable!target!#]. The return code was: [#!variable!return_code!#] (expected '0') and the release output, if any, was: [#!variable!output!#]. + The program: [#!variable!program!#] is using: [#!variable!ram_used!#] (#!variable!ram_used_bytes!# Bytes). This is probably caused by a memory leak, so we will now exit so that systemctl can restart us. If this is happening repeatedly, please contact support. @@ -1364,7 +1366,7 @@ Connecting to Database with configuration ID: [#!variable!uuid!#] Updated: [#!variable!file!#] to require passwords for access. call() was called but the port: [#!variable!port!#] is invalid. It must be a digit between '1' and '65535'.]]> Started the PostgreSQL database server. - Database user: [#!variable!user!#] already exists with UUID: [#!variable!uuid!#]. + Database user: [#!variable!user!#] already exists with UUID: [#!variable!id!#]. users_home() was asked to find the home directory for the user: [#!variable!user!#], but was unable to do so.]]> SSH session opened without a password to: [#!variable!target!#]. #!variable!name!#] with the UUID: [#!variable!uuid!#] did not respond to pings and 'database::#!variable!uuid!#::ping' is not set to '0' in '#!data!path::configs::anvil.conf!#', skipping it.]]> @@ -1421,7 +1423,7 @@ The database connection error was: - Record Locator: [#!variable!record_locator!#] - Timestamp: .... [#!variable!modified_date!#] - [ Error ] - There is no #!string!brand_0002!# database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!uuid!#]. + [ Warning ] - There is no #!string!brand_0002!# database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!uuid!#]. Using 'admin'. Database user: [#!variable!user!#] password has been set/updated. Failed to connect to: [#!variable!target!#:#!variable!port!#], sleeping for a second and then trying again. I am not recording the alert with message_key: [#!variable!message_key!#] to the database because its log level was lower than any recipients. @@ -1521,8 +1523,8 @@ The database connection error was: Failed to reconnect to the database, and now no connections remail. Exiting. maintenance_mode() was passed an invalid 'set' value: [#!variable!set!#]. No action taken.]]> The user: [#!variable!user!#] logged out successfully. - A system reboot is required, setting the database flag. - A system reboot is required, setting the database flag. + A system reboot has been requested via the Striker UI. + A system power-off has been requested via the Striker UI. Unable to connect to any database. Will try to initialize the local system and then try again. Failed to connect to any databases. Skipping the loop of the daemon. Disconnected from all databases. Will reconnect when entering the main loop. @@ -1947,7 +1949,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The host: [#!variable!host_name!#] is up, no need to check if it needs booting. The host: [#!variable!host_name!#] couldn't be reached directly, but IPMI reports that it is up. Could the IPMI BMC be hung or unplugged? The host: [#!variable!host_name!#] is off. Will check now if it should be booted. - The host: [#!variable!host_name!#] has no stop reason, so we'll boot it up in case it lost power without warning. + The host: [#!variable!host_name!#] has no stop reason, so we'll check to see if we should power it on, in case it lost power or overheated without warning. The host: [#!variable!host_name!#] was stopped by the user, so we'll leave it off. The host: [#!variable!host_name!#] was powered off because of power loss. Checking to see if it is now safe to restart it. The host: [#!variable!host_name!#] was powered off because of thermal issues. Checking to see if it is now safe to restart it. @@ -1955,7 +1957,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: Unable to parse the install manifest uuid: [#!variable!manifest_uuid!#] for the Anvil! [#!variable!anvil_name!#]. As such, unable to determine what UPSes power the machine: [#!variable!host_name!#]. Unable to determine if the power feeding this node is OK or not. The UPS referenced by the 'power_uuid': [#!variable!power_uuid!#] under the host: [#!variable!host_name!#] has no record of being on mains power, so we can't determine how long it's been on batteries. Setting the "shortest time on batteries" to zero seconds. Marking the host as 'online' and clearing the host's stop reason. - The host: [#!variable!host_name!#] is off, but there appears to be a problem translating the 'fence_ipmilan' into a workable 'ipmitool' command. Unable to check the thermal data of the host, and so, unable to determine if it's safe to boot the node. + There appears to be a problem translating the 'fence_ipmilan' into a workable 'ipmitool' command for the host: [#!variable!host_name!#]. Unable to check the thermal data of the host. The host: [#!variable!host_name!#] was powered off because of power loss. Power is back and the UPSes are sufficiently charged. Booting it back up now. The host: [#!variable!host_name!#] was powered off for thermal reasons. All available thermal sensors read as OK now. Booting it back up now. The file: [#!variable!file_path!#] isn't on (or isn't the right size on) Striker: [#!variable!host_name!#]. Not using it to pull from. @@ -2056,6 +2058,33 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The target can be reached on the dedicated migration network: [#!variable!target!#] via the IP address: [#!variable!ip!#], switching to use that for the RAM copy. [ Note ] - The IP address: [#!variable!ip!#] with 'ip_address_uuid': [#!variable!uuid!#] is a duplicate, removing it from the database(s). The database dump file: [#!variable!file!#] exists, skipping database setup. + query() was asked to query the database with UUID: [#!variable!old_uuid!#] but there is no file handle open to the database. Switched the read to: [#!variable!new_uuid!#].]]> + Opening the firewall zone: [#!variable!zone!#] to allow the service: [#!variable!service!#]. + No password for the database on the host with UUID: [#!variable!uuid!#], skipping it. + The firewalld daemon isn't running, skipping firewall setup. + The postgresql server is installed. + The host: [#!variable!host_name!#] was powered off for an unknown reason, and 'feature::scancore::disable::boot-unknown-stop' is set to: [#!data!feature::scancore::disable::boot-unknown-stop!#]. Will not boot this host. + The host: [#!variable!host_name!#] was powered off for an unknown reason, and 'feature::scancore::disable::boot-unknown-stop' is set to: [#!data!feature::scancore::disable::boot-unknown-stop!#]. If power and temperature looks good, we'll boot it. + The host: [#!variable!host_name!#] has good power and temperature readings. Booting it back up now. + The resync has completed in: [#!variable!took!#] second(s). + Log->secure' is not set. ]]> + [ Note ] - The DRBD kernel module failed to load. It is possible the kernel was updated. We will check to see if we can install a pre-built RPM, or if we need to build one ourselves. + Found an installable DRBD kernel module RPM that matches the current kernel. Installing it now. + [ Note ] - We need to build the DRBD kernel module. This can take a few minutes, please be patient! Use 'journalctl -f' to monitor the build process. + Successfully built and installed the new DRBD kernel module! + We were asked to resync the database, but this host is hosting: [#!variable!count!#] server(s). Resync is not allowed when servers are running to reduce the risk the kernel's out of memory handler shooting a VM if the resync consumes too much RAM. You can see which servers are running with 'virsh list' and look for servers whose states are "running", "paused", "in shutdown" or "pmsuspended". + Testing that our short host name resolves to one of our IP prior to starting the cluster. + Changing the ownership of: [#!variable!file!#] to be owned by: [#!variable!user!#:#!variable!user!#]. + Enabling 'ping' for all users. + The network interface: [#!variable!nic!#] on the host: [#!variable!host!#] is recorded in the 'history.network_interfaces' table, but has not corresponding entry in the public table. Removing it. + [ Note ] - The network bridge: [#!variable!name!#] with 'bridge_uuid': [#!variable!uuid!#] is a duplicate, removing it from the database(s). + Skipping resync, not a Striker dashboard. + ### REBOOT REQUESTED ### - [#!variable!reason!#] + Reboot flag set by command line switch to 'anvil-manage-power'. + Poweroff flag set by command line switch to 'anvil-manage-power'. + Kernel updated, reboot queued. + Requested to power-off as part of the anvil-safe-stop job. + The anvil-safe-stop job has completed and will now power off. The host name: [#!variable!target!#] does not resolve to an IP address. @@ -2419,6 +2448,8 @@ Are you sure that you want to delete the server: [#!variable!server_name!#]? [Ty Failed to get server VM screenshot; got non-zero return code. Finished attempting to get server VM screenshot; no operations happened because requirements not met.>>> master Preparing to manage DR for a server. + UUID Column counts for: [history.#!variable!table!#]: + Counting entries for each unique: [#!variable!column!#] in the table [#!variable!table!#]. Please be patient. Saved the mail server information successfully! @@ -3080,6 +3111,11 @@ The error was: We will sleep a bit and try again. [ Warning ] - The storage group: [#!variable!storage_group_name!#] had the host: [#!variable!host_name!#] as a member. This host is not a member (anymore?) of the Anvil!: [#!variable!anvil_name!#]. Removing it from the storage group now. + [ Warning ] - The postgresql server is not installed yet. Sleeping for a bit, then will check again. + [ Warning ] - Failed to build or install the DRBD kernel module! It is very unlikely that this machine will be able to run any servers until this is fixed. + [ Warning ] - Table: [history.#!variable!table!#] not found. + [ Warning ] - Holding off starting the cluster. Tested access to ourself, and failed. Is '/etc/hosts' populated? Will try again in ten seconds. + [ Warning ] - The program: [#!variable!program!#] was not found to be running. @@ -3809,7 +3845,7 @@ We will sleep a bit and try again. Anvil! ストライカ スカンコア - Alteeve's Niche! Inc., トロント、オンタリオ、カナダ]]> + Alteeve's Niche! Inc., トロント、オンタリオ、カナダ]]> diff --git a/striker-ui/package-lock.json b/striker-ui/package-lock.json index c1c49d7f..94c2fba3 100644 --- a/striker-ui/package-lock.json +++ b/striker-ui/package-lock.json @@ -68,9 +68,9 @@ }, "dependencies": { "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" } } }, @@ -437,9 +437,9 @@ } }, "@hapi/hoek": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", - "integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug==" + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", + "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" }, "@material-ui/core": { "version": "4.11.4", @@ -518,14 +518,14 @@ } }, "@napi-rs/triples": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.0.3.tgz", - "integrity": "sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz", + "integrity": "sha512-XQr74QaLeMiqhStEhLn1im9EOMnkypp7MZOwQhGzqp2Weu5eQJbpPxWxixxlYRKWPOmJjsk6qYfYH9kq43yc2w==" }, "@next/env": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-11.1.1.tgz", - "integrity": "sha512-UEAzlfKofotLmj9LIgNixAfXpRck9rt/1CU9Q4ZtNDueGBJQP3HUzPHlrLChltWY2TA5MOzDQGL82H0a3+i5Ag==" + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-11.1.3.tgz", + "integrity": "sha512-5+vaeooJuWmICSlmVaAC8KG3O8hwKasACVfkHj58xQuCB5SW0TKW3hWxgxkBuefMBn1nM0yEVPKokXCsYjBtng==" }, "@next/eslint-plugin-next": { "version": "11.1.0", @@ -537,14 +537,14 @@ } }, "@next/polyfill-module": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-11.1.1.tgz", - "integrity": "sha512-9FyVSnz00WGdlLsgc2w1xL1Lm/Q25y6FYIyA+1WlJvT6LA2lbR78GKiHgedzUvrAatVGAcg/Og+d0d7B4tsJOg==" + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-11.1.3.tgz", + "integrity": "sha512-7yr9cr4a0SrBoVE8psxXWK1wTFc8UzsY8Wc2cWGL7qA0hgtqACHaXC47M1ByJB410hFZenGrpE+KFaT1unQMyw==" }, "@next/react-dev-overlay": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-11.1.1.tgz", - "integrity": "sha512-CXc/A0DbSk5VXYu4+zr0fHm52Zh/LhPlLyVPEctJOZL64ccxkls5xGoXvgolJCku9L0pLjJzvdfAmhNLOp5dyw==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-11.1.3.tgz", + "integrity": "sha512-zIwtMliSUR+IKl917ToFNB+0fD7bI5kYMdjHU/UEKpfIXAZPnXRHHISCvPDsczlr+bRsbjlUFW1CsNiuFedeuQ==", "requires": { "@babel/code-frame": "7.12.11", "anser": "1.4.9", @@ -592,32 +592,32 @@ } }, "@next/react-refresh-utils": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.1.1.tgz", - "integrity": "sha512-j186y+lWc8BHAuysAWvlOqO9Bp7E3BLK/d/Ju3W2sP5BCH5ZLyLG/p308zSy/O0MGTag0B038ZA1dCy/msouRQ==" + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.1.3.tgz", + "integrity": "sha512-144kD8q2nChw67V3AJJlPQ6NUJVFczyn10bhTynn9o2rY5DEnkzuBipcyMuQl2DqfxMkV7sn+yOCOYbrLCk9zg==" }, "@next/swc-darwin-arm64": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-11.1.1.tgz", - "integrity": "sha512-KyB0aLpfQ+B2dsyGYpkM0ZwK3PV0t4C4b9yjgQc1VoTVnIjzXdDPnNOuVvmD849ZNOHfj3x8e2rlbxkj0lPm3A==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-11.1.3.tgz", + "integrity": "sha512-TwP4krjhs+uU9pesDYCShEXZrLSbJr78p12e7XnLBBaNf20SgWLlVmQUT9gX9KbWan5V0sUbJfmcS8MRNHgYuA==", "optional": true }, "@next/swc-darwin-x64": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-11.1.1.tgz", - "integrity": "sha512-B3ZXgrGx0bQplbrk2oggPjKPPsmyg8Fl0PJLMTVQ+erQ8g1m5QzyS9P6tB3SiIZa180JgENuguTHlVK5qEj4UA==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-11.1.3.tgz", + "integrity": "sha512-ZSWmkg/PxccHFNUSeBdrfaH8KwSkoeUtewXKvuYYt7Ph0yRsbqSyNIvhUezDua96lApiXXq6EL2d1THfeWomvw==", "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-11.1.1.tgz", - "integrity": "sha512-qvZL7gSKF+E+GZ3L1XiTnE3cOh9rk0wkqimT/q+wwcZA4E720Lu4lrT79I3HPuj6i/JPgGvmNskcnYrDeaoFaw==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-11.1.3.tgz", + "integrity": "sha512-PrTBN0iZudAuj4jSbtXcdBdmfpaDCPIneG4Oms4zcs93KwMgLhivYW082Mvlgx9QVEiRm7+RkFpIVtG/i7JitA==", "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-11.1.1.tgz", - "integrity": "sha512-jhnCiA1De1L+kA0gmHG1AJijHoxOcrETWziDWy8fcqSrM1NlC4aJ5Mnu6k0QMcM9MnmXTA4TQZOEv3kF7vhJUQ==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-11.1.3.tgz", + "integrity": "sha512-mRwbscVjRoHk+tDY7XbkT5d9FCwujFIQJpGp0XNb1i5OHCSDO8WW/C9cLEWS4LxKRbIZlTLYg1MTXqLQkvva8w==", "optional": true }, "@node-rs/helper": { @@ -959,9 +959,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "3.2.1", @@ -1307,9 +1307,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001252", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz", - "integrity": "sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw==" + "version": "1.0.30001285", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz", + "integrity": "sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q==" }, "chalk": { "version": "2.4.2", @@ -1871,9 +1871,9 @@ } }, "electron-to-chromium": { - "version": "1.3.826", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.826.tgz", - "integrity": "sha512-bpLc4QU4B8PYmdO4MSu2ZBTMD8lAaEXRS43C09lB31BvYwuk9UxgBRXbY5OJBw7VuMGcg2MZG5FyTaP9u4PQnw==" + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.14.tgz", + "integrity": "sha512-RsGkAN9JEAYMObS72kzUsPPcPGMqX1rBqGuXi9aa4TBKLzICoLf+DAAtd0fVFzrniJqYzpby47gthCUoObfs0Q==" }, "elliptic": { "version": "6.5.4", @@ -2897,6 +2897,15 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "git-raw-commits": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", @@ -3340,6 +3349,11 @@ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", "dev": true }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -3381,21 +3395,24 @@ }, "dependencies": { "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", @@ -3404,6 +3421,11 @@ "unbox-primitive": "^1.0.1" } }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3422,9 +3444,9 @@ } }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", + "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==" }, "unbox-primitive": { "version": "1.0.1", @@ -3445,6 +3467,14 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "requires": { + "call-bind": "^1.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -4092,9 +4122,9 @@ "dev": true }, "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==" + "version": "3.1.30", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", + "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" }, "native-url": { "version": "0.3.4", @@ -4111,20 +4141,20 @@ "dev": true }, "next": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/next/-/next-11.1.1.tgz", - "integrity": "sha512-vfLJDkwAHsZUho5R1K4w49nfYhftUMWNmeNSjCtulOvnRBuEFb7ROyRZOQk7f29rMz02eLQrPZ9yiAmPsexL2g==", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/next/-/next-11.1.3.tgz", + "integrity": "sha512-ud/gKmnKQ8wtHC+pd1ZiqPRa7DdgulPkAk94MbpsspfNliwZkYs9SIYWhlLSyg+c661LzdUI2nZshvrtggSYWA==", "requires": { "@babel/runtime": "7.15.3", "@hapi/accept": "5.0.2", - "@next/env": "11.1.1", - "@next/polyfill-module": "11.1.1", - "@next/react-dev-overlay": "11.1.1", - "@next/react-refresh-utils": "11.1.1", - "@next/swc-darwin-arm64": "11.1.1", - "@next/swc-darwin-x64": "11.1.1", - "@next/swc-linux-x64-gnu": "11.1.1", - "@next/swc-win32-x64-msvc": "11.1.1", + "@next/env": "11.1.3", + "@next/polyfill-module": "11.1.3", + "@next/react-dev-overlay": "11.1.3", + "@next/react-refresh-utils": "11.1.3", + "@next/swc-darwin-arm64": "11.1.3", + "@next/swc-darwin-x64": "11.1.3", + "@next/swc-linux-x64-gnu": "11.1.3", + "@next/swc-win32-x64-msvc": "11.1.3", "@node-rs/helper": "1.2.1", "assert": "2.0.0", "ast-types": "0.13.2", @@ -4162,7 +4192,7 @@ "stream-browserify": "3.0.0", "stream-http": "3.1.1", "string_decoder": "1.3.0", - "styled-jsx": "4.0.0", + "styled-jsx": "4.0.1", "timers-browserify": "2.0.12", "tty-browserify": "0.0.1", "use-subscription": "1.5.1", @@ -4356,9 +4386,9 @@ } }, "node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==" + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" }, "normalize-package-data": { "version": "3.0.2", @@ -5634,9 +5664,9 @@ "dev": true }, "styled-jsx": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-4.0.0.tgz", - "integrity": "sha512-2USeoWMoJ/Lx5s2y1PxuvLy/cz2Yrr8cTySV3ILHU1Vmaw1bnV7suKdblLPjnyhMD+qzN7B1SWyh4UZTARn/WA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-4.0.1.tgz", + "integrity": "sha512-Gcb49/dRB1k8B4hdK8vhW27Rlb2zujCk1fISrizCcToIs+55B4vmUM0N9Gi4nnVfFZWe55jRdWpAqH1ldAKWvQ==", "requires": { "@babel/plugin-syntax-jsx": "7.14.5", "@babel/types": "7.15.0", @@ -6031,21 +6061,24 @@ }, "dependencies": { "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", @@ -6054,6 +6087,11 @@ "unbox-primitive": "^1.0.1" } }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6072,9 +6110,9 @@ } }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", + "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==" }, "unbox-primitive": { "version": "1.0.1", diff --git a/striker-ui/package.json b/striker-ui/package.json index aec5d45b..c99d4c3d 100644 --- a/striker-ui/package.json +++ b/striker-ui/package.json @@ -17,7 +17,7 @@ "@material-ui/icons": "^4.11.2", "@material-ui/styles": "^4.11.4", "@novnc/novnc": "^1.2.0", - "next": "^11.1.1", + "next": "^11.1.3", "pretty-bytes": "^5.6.0", "react": "17.0.2", "react-dom": "17.0.2", diff --git a/tools/Makefile.am b/tools/Makefile.am index d2b6c074..d2d1c3ba 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -50,7 +50,7 @@ dist_sbin_SCRIPTS = \ striker-show-db-counts \ striker-auto-initialize-all -fencedir = $(FASEXECPREFIX)/sbin +fencedir = ${FASEXECPREFIX}/sbin dist_fence_SCRIPTS = \ fence_delay \ diff --git a/tools/anvil-boot-server b/tools/anvil-boot-server index 134c3fb8..90ee9b19 100755 --- a/tools/anvil-boot-server +++ b/tools/anvil-boot-server @@ -321,12 +321,16 @@ sub boot_all_servers ### TODO: Manage the boot order here. # We top out at 90, bottom is 20. my $server_count = keys %{$anvil->data->{cib}{parsed}{data}{server}}; - my $increment = int(70 / $server_count); - my $percent = 15; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - server_count => $server_count, - increment => $increment, - }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }}); + if (not $server_count) + { + # No servers exist yet. + return(0); + } + + my $increment = int(70 / $server_count); + my $percent = 15; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { increment => $increment }}); foreach my $server (sort {$a cmp $b} keys %{$anvil->data->{cib}{parsed}{data}{server}}) { my $status = $anvil->data->{cib}{parsed}{data}{server}{$server}{status}; diff --git a/tools/anvil-check-memory b/tools/anvil-check-memory index ecce13b0..b6fc0ef6 100755 --- a/tools/anvil-check-memory +++ b/tools/anvil-check-memory @@ -50,10 +50,10 @@ if (not $anvil->data->{switches}{program}) # Find the PID(s) of the program. $anvil->data->{sys}{pids} = $anvil->System->pids({ignore_me => 1, program_name => $anvil->data->{switches}{program}}); -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { 'sys::pids' => $anvil->data->{sys}{pids} }}); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::pids' => $anvil->data->{sys}{pids} }}); my $pids_found = @{$anvil->data->{sys}{pids}}; -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { pids_found => $pids_found }}); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pids_found => $pids_found }}); if (not $pids_found) { @@ -66,7 +66,7 @@ if (not $pids_found) foreach my $pid (sort {$a cmp $b} @{$anvil->data->{sys}{pids}}) { my $smaps_path = "/proc/".$pid."/smaps"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { smaps_path => $smaps_path }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { smaps_path => $smaps_path }}); # This will store the amount of RAM used by this specific PID. $anvil->data->{memory}{pid}{$pid} = 0; diff --git a/tools/anvil-daemon b/tools/anvil-daemon index c7fb3226..a3be7169 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -91,7 +91,10 @@ $anvil->System->_check_anvil_conf(); # Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks # is to setup the database server. -$anvil->Database->connect({check_if_configured => 1, check_for_resync => 1}); +$anvil->Database->connect({ + check_if_configured => 1, + check_for_resync => 1, +}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"}); # If I have no databases, sleep for a second and then exit (systemd will restart us). @@ -105,8 +108,7 @@ if (not $anvil->data->{sys}{database}{connections}) prep_database($anvil); # Try connecting again - $anvil->refresh(); - $anvil->Database->connect(); + $anvil->Database->connect({check_if_configured => 1, check_for_resync => 1}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { @@ -244,6 +246,9 @@ while(1) $anvil->nice_exit({exit_code => 0}); } + # Check how much RAM we're using. + check_ram($anvil); + # Disconnect from the database(s) and sleep now. $anvil->Database->disconnect(); sleep(2); @@ -256,6 +261,41 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# +# If we're using too much ram, send an alert and exit. +sub check_ram +{ + my ($anvil) = @_; + + # Problem 0 == ok, 1 == too much ram used, 2 == no pid found + my ($problem, $ram_used) = $anvil->System->check_ram_use({program => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + problem => $problem, + ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")", + }}); + if ($problem) + { + # Send an alert and exit. + $anvil->Alert->register({alert_level => "notice", message => "error_0357", variables => { + program => $THIS_FILE, + ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}), + ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}), + }, set_by => $THIS_FILE, sort_position => 0}); + $anvil->Email->send_alerts(); + + # Log the same + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0357", variables => { + program => $THIS_FILE, + ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}), + ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}), + }}); + + # Exit with RC0 so that systemctl restarts + $anvil->nice_exit({exit_code => 0}); + } + + return(0); +} + # Check to see if we're mapping the network on this host. sub check_if_mapping { @@ -274,7 +314,7 @@ sub check_if_mapping # shouldn't fire in practice). my $expire_age = 86400; my $map_network_age = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:map_network_value' => $map_network_value, 's2:map_network_mtime' => $map_network_mtime, 's3:map_network_modified_date' => $map_network_modified_date, @@ -411,6 +451,39 @@ sub check_network check_firewall($anvil); } + # Check that all users can ping. + if (1) + { + my $shell_call = $anvil->data->{path}{exe}{sysctl}." net.ipv4.ping_group_range"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }}); + + if ($output =~ /net.ipv4.ping_group_range = (\d+)\t(\d+)$/) + { + my $lowest_uid = $1; + my $highest_uid = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + lowest_uid => $lowest_uid, + highest_uid => $highest_uid, + }}); + + if ($highest_uid < 2000) + { + # Tell the user we're enabling ping for all users. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0683"}); + + my $shell_call = $anvil->data->{path}{exe}{sysctl}." -w net.ipv4.ping_group_range=\"0 2147483647\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { output => $output }}); + + } + } + } + return(0); } @@ -439,7 +512,7 @@ sub handle_periodic_tasks check_install_target($anvil); # Check that the users we care about have ssh public keys and they're recorded in ssh_keys. - $anvil->System->check_ssh_keys({debug => 3}); + $anvil->System->check_ssh_keys({debug => 2}); $anvil->System->update_hosts({debug => 3}); @@ -506,6 +579,9 @@ sub handle_periodic_tasks # Check mail server config. my $problem = $anvil->Email->check_config({debug => 3}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { problem => $problem }}); + + # Check if any files have been uploaded to /mnt/shared/incoming on striker + check_incoming($anvil); } # Now check to see if it's time to run less frequent tasks. @@ -533,6 +609,9 @@ sub handle_periodic_tasks { $first_uuid = $uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { first_uuid => $first_uuid }}); + + # Skip the first UUID so it doesn't evaluate for shutdown. + next; } elsif ($uuid eq $host_uuid) { @@ -693,6 +772,77 @@ sub handle_periodic_tasks return(0); } +# On dashboards, this checks to see if any files are in /mnt/shared/incoming and, if so, that they've been processed. +sub check_incoming +{ + my ($anvil) = @_; + + my $system_type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { system_type => $system_type }}); + if ($system_type eq "striker") + { + # Look for files in /mnt/shared/incoming that are not yet in the database. + my $directory = $anvil->data->{path}{directories}{shared}{incoming}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); + local(*DIRECTORY); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); + next if $file eq "."; + next if $file eq ".."; + next if $file =~ /^\./; # This is files being rsync'ed still + my $full_path = $directory."/".$file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); + + # Skip anything that is not a file. + next if not -f $full_path; + + # Is this file already in the DB? + my $query = "SELECT file_uuid FROM files WHERE file_name = ".$anvil->Database->quote($file).";"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + if (not $count) + { + # Add it to the database. + my $size = (stat($full_path))[7]; + my $say_size_human = $anvil->Convert->bytes_to_human_readable({'bytes' => $size}); + my $say_size_comma = $anvil->Convert->add_commas({number => $size}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + size => $size, + say_size_human => $say_size_human, + say_size_comma => $say_size_comma, + }}); + + # Register a job to call anvil-sync-shared + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + file => $THIS_FILE, + line => __LINE__, + job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}, + job_data => "file=".$full_path, + job_name => "storage::move_incoming", + job_title => "job_0132", + job_description => "job_0133", + job_progress => 0, + job_host_uuid => $anvil->data->{sys}{host_uuid}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + } + + } + closedir(DIRECTORY); + } + + return(0); +} + # This calls striker-manage-install-target to see if the dhcpd is running or not. If it is or isn't, the config # variable 'install-target::enabled' is set/updated. On non-Striker hosts, this simply returns without doing # anything. @@ -761,7 +911,7 @@ sub run_once # Check the ssh stuff. # NOTE: This actually runs again in the minutes tasks, but needs to run on boot as well. - $anvil->System->check_ssh_keys(); + $anvil->System->check_ssh_keys({debug => 2}); # Check setuid wrappers check_setuid_wrappers($anvil); @@ -1124,11 +1274,12 @@ sub handle_special_cases { my ($anvil) = @_; - # RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16 my $host_type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); if ($host_type ne "striker") { + ### TODO: Test that this is fixed. The bug is now ERRATA + # RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16 # We're a node or DR host. We need to touch this file. my $work_around_file = "/etc/qemu/firmware/50-edk2-ovmf-cc.json"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { work_around_file => $work_around_file }}); @@ -1145,6 +1296,9 @@ sub handle_special_cases group => "root", }); } + + # Make sure DRBD compiled after a kernel upgrade. + $anvil->DRBD->_initialize_kmod({debug => 2}); } return(0); @@ -1156,6 +1310,7 @@ sub prep_database my ($anvil) = @_; # If there's a backup file, we're configured and possibly just off. + my $prep_database = 1; foreach my $uuid (keys %{$anvil->data->{database}}) { my $dump_file = $anvil->data->{path}{directories}{pgsql}."/".$anvil->data->{sys}{database}{name}."_db_dump.".$uuid.".sql"; @@ -1165,7 +1320,8 @@ sub prep_database { # No need to prepare. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0665", variables => { file => $dump_file }}); - return(0); + $prep_database = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { prep_database => $prep_database }}); } } @@ -1174,13 +1330,37 @@ sub prep_database $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); if ($host_type eq "striker") { - ### NOTE: This failed once, in case / until it happens again, we'll force log level 2 and secure logging. - #my ($database_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'striker-prep-database'}.$anvil->Log->switches, source => $THIS_FILE, line => __LINE__ }); - my ($database_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'striker-prep-database'}." -vv --log-secure", source => $THIS_FILE, line => __LINE__ }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - database_output => $database_output, - return_code => $return_code, + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + prep_database => $prep_database, + "sys::database::connections" => $anvil->data->{sys}{database}{connections}, }}); + if ($prep_database) + { + ### NOTE: This failed once, in case / until it happens again, we'll force log level 2 and secure logging. + my $shell_call = $anvil->data->{path}{exe}{'striker-prep-database'}." -vv --log-secure"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($database_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call, source => $THIS_FILE, line => __LINE__ }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + database_output => $database_output, + return_code => $return_code, + }}); + } + elsif (not $anvil->data->{sys}{database}{connections}) + { + # Start the daemon locally, if needed. + my $running = $anvil->System->check_daemon({daemon => "postgresql"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }}); + if ($running == 2) + { + # Not installed, nothing to do. + } + elsif (not $running) + { + # Start it. + my $return_code = $anvil->System->start_daemon({daemon => "postgresql"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { return_code => $return_code }}); + } + } } return(0); diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index 8c874e2f..6e75fff4 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -2190,7 +2190,7 @@ sub check_local_network # Configure SSH by adding ours and our peer's SSH keys to ~/.ssh/known_hosts $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0113"}); update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0113"); - $anvil->System->check_ssh_keys({debug => 3}); + $anvil->System->check_ssh_keys({debug => 2}); # Setup IPMI, if needed. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0114"}); diff --git a/tools/anvil-manage-power b/tools/anvil-manage-power index 4b4b9934..8786b572 100755 --- a/tools/anvil-manage-power +++ b/tools/anvil-manage-power @@ -130,6 +130,7 @@ if ($anvil->data->{switches}{'reboot-needed'} eq "1") # Enable if (not $reboot_needed) { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0688" }}); $reboot_needed = $anvil->System->reboot_needed({debug => 2, set => 1}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reboot_needed => $reboot_needed }}); print $anvil->Words->string({key => "message_0048"})."\n"; @@ -246,6 +247,8 @@ sub do_poweroff # Make sure the 'reboot needed' flag is set. When 'anvil-daemon' starts, it will use this to confirm # that it is starting post-reboot and clear it. + my $say_reason = $task eq "poweroff" ? "log_0689" : "log_0688"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => $say_reason }}); $reboot_needed = $anvil->System->reboot_needed({debug => 2, set => 1}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reboot_needed => $reboot_needed }}); diff --git a/tools/anvil-manage-server b/tools/anvil-manage-server index 07c37325..975a8cdf 100755 --- a/tools/anvil-manage-server +++ b/tools/anvil-manage-server @@ -661,6 +661,7 @@ sub interactive_configure_main print "[ 3 ] - Storage\n"; print "[ 4 ] - Network\n"; print "[ 5 ] - Boot Order\n"; + print "[ 6 ] - Cluster Management\n"; print "\n"; print "[ B ] - Back\n"; print "[ Q ] - Quit\n"; @@ -696,6 +697,11 @@ sub interactive_configure_main print "Going to Boot order menu\n"; sleep 1; } + elsif ($answer eq "6") + { + print "Going to cluster manager menu\n"; + sleep 1; + } elsif (lc($answer) eq "b") { $anvil->data->{target_server}{server_name} = ""; @@ -815,7 +821,7 @@ sub interactive_configure_storage }}); my $this_storage_group_uuid = $anvil->Storage->get_storage_group_from_path({ - debug => 3, + debug => 2, anvil_uuid => $anvil_uuid, path => $this_path, }); diff --git a/tools/anvil-safe-start b/tools/anvil-safe-start index e88672f0..cb4f50d2 100755 --- a/tools/anvil-safe-start +++ b/tools/anvil-safe-start @@ -237,6 +237,51 @@ sub start_pacemaker # Nope, start it. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0608"}); + # NOTE: In some odd cases, this can try to run before /etc/hosts has been populated. So wait + # until we can access ourself. + my $ok = 0; + until ($ok) + { + # Convert out short host name to an IP and verify that the IP is one of ours. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0681"}); + my $local_bcn1_ip = $anvil->Convert->host_name_to_ip({debug => 2, host_name => $short_host_name}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_bcn1_ip => $local_bcn1_ip }}); + + if ($local_bcn1_ip) + { + # Is this one of our IPs, or is DNS being a little shit? + if (exists $anvil->data->{network}{$short_host_name}) + { + delete $anvil->data->{network}{$short_host_name}; + } + $anvil->Network->get_ips(); + + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$short_host_name}{interface}}) + { + next if $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip} eq ""; + next if $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip} =~ /^127\.0\.0\./; + my $this_ip = $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:interface' => $interface, + 's2:this_ip' => $this_ip, + }}); + if ($this_ip eq $local_bcn1_ip) + { + $ok = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ok => $ok }}); + last; + } + } + } + + if (not $ok) + { + # Sleep 10 seconds. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "warning_0134"}); + sleep 10; + } + } + ### TODO: A lot more testing is needed for degraded single-node start later. ### Should we use --all, or wait for our peer? For now, we wait. #my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster start --all"; diff --git a/tools/anvil-safe-stop b/tools/anvil-safe-stop index 6f30a1c8..b2b68ff2 100755 --- a/tools/anvil-safe-stop +++ b/tools/anvil-safe-stop @@ -101,6 +101,7 @@ if ($anvil->data->{switches}{'job-uuid'}) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'switches::power-off' => $anvil->data->{switches}{'power-off'}, }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0691" }}); } if ($line =~ /stop-reason=(.*?)$/) { @@ -156,6 +157,7 @@ if ($anvil->data->{switches}{'power-off'}) host_status => "stopping", }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0692" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0325"}); $anvil->Job->update_progress({progress => 100, message => "job_0325"}); diff --git a/tools/anvil-sync-shared b/tools/anvil-sync-shared index d88294fe..a1cb6965 100755 --- a/tools/anvil-sync-shared +++ b/tools/anvil-sync-shared @@ -48,7 +48,7 @@ if (not $anvil->data->{switches}{'job-uuid'}) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }}); } -# If we still don't have a job-uuit, go into interactive mode. +# If we still don't have a job-uuid, go into interactive mode. if ($anvil->data->{switches}{'job-uuid'}) { # Load the job data. diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 5fa381d2..759a891d 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -42,6 +42,10 @@ process_interface_cache($anvil); update_network($anvil); # Write out the interface cache +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + "cache::new_file" => $anvil->data->{cache}{new_file}, + "path::data::network_cache" => $anvil->data->{path}{data}{network_cache}, +}}); $anvil->Storage->write_file({ debug => 3, body => $anvil->data->{cache}{new_file}, @@ -446,7 +450,14 @@ sub update_network if ($line =~ /Supported ports: \[ (.*?) \]/i) { $media = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { media => $media }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + + # This can be 'tp mii', which breaks json. + if ($media =~ /\t/) + { + $media =~ s/\t/,/g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + } last; } } @@ -948,7 +959,7 @@ ORDER BY network_interface_bond_uuid => defined $row->[9] ? $row->[9] : 'NULL', network_interface_bridge_uuid => defined $row->[10] ? $row->[10] : 'NULL', }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}, "network_interfaces::${network_interface_uuid}::network_interface_name" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}, "network_interfaces::${network_interface_uuid}::network_interface_speed" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}, diff --git a/tools/anvil-update-system b/tools/anvil-update-system index 0f8147ee..a8626705 100755 --- a/tools/anvil-update-system +++ b/tools/anvil-update-system @@ -173,8 +173,7 @@ sub run_os_update if ($line =~ /^kernel /) { # Reboot will be needed. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0199"}); - + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0690" }}); my $reboot_needed = $anvil->System->reboot_needed({set => 1}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { reboot_needed => $reboot_needed }}); } diff --git a/tools/scancore b/tools/scancore index 9b131e53..8a27054f 100755 --- a/tools/scancore +++ b/tools/scancore @@ -163,6 +163,9 @@ while(1) # Clean up cleanup_after_run($anvil); + # Check how much RAM we're using. + check_ram($anvil); + # Sleep until it's time to run again. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0249", variables => { run_interval => $run_interval, @@ -181,6 +184,41 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# +# If we're using too much ram, send an alert and exit. +sub check_ram +{ + my ($anvil) = @_; + + # Problem 0 == ok, 1 == too much ram used, 2 == no pid found + my ($problem, $ram_used) = $anvil->System->check_ram_use({program => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + problem => $problem, + ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")", + }}); + if ($problem) + { + # Send an alert and exit. + $anvil->Alert->register({alert_level => "notice", message => "error_0357", variables => { + program => $THIS_FILE, + ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}), + ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}), + }, set_by => $THIS_FILE, sort_position => 0}); + $anvil->Email->send_alerts(); + + # Log the same + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0357", variables => { + program => $THIS_FILE, + ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}), + ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}), + }}); + + # Exit with RC0 so that systemctl restarts + $anvil->nice_exit({exit_code => 0}); + } + + return(0); +} + # This cleans things up after a scan run has completed. sub cleanup_after_run { diff --git a/tools/striker-auto-initialize-all b/tools/striker-auto-initialize-all index c6a58c7c..acaf3356 100755 --- a/tools/striker-auto-initialize-all +++ b/tools/striker-auto-initialize-all @@ -1425,7 +1425,7 @@ sub striker_stage1 { my ($anvil) = @_; - ### TODO: Validate all steps up front before starting anything. + # Validate if ((not defined $anvil->data->{base}{organization_name}) or (not $anvil->data->{base}{organization_name})) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::organization_name' }}); diff --git a/tools/striker-db-report b/tools/striker-db-report new file mode 100755 index 00000000..b738c468 --- /dev/null +++ b/tools/striker-db-report @@ -0,0 +1,381 @@ +#!/usr/bin/perl +# +# This tool looks at the database and counts how many records are in each database. Optionally, if given a +# table name, it will count the number of entries exist in the history schema for each record in the public +# schema. The goal being to help quickly identifying rapidly growing tables. +# + +use strict; +use warnings; +use Anvil::Tools; +use Data::Dumper; +use Text::Diff; + +$| = 1; + +my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; +my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; +if (($running_directory =~ /^\./) && ($ENV{PWD})) +{ + $running_directory =~ s/^\./$ENV{PWD}/; +} + +my $anvil = Anvil::Tools->new(); + +$anvil->Database->connect({debug => 3, check_for_resync => 0}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); +if (not $anvil->data->{sys}{database}{connections}) +{ + # No databases, exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"}); + $anvil->nice_exit({exit_code => 1}); +} + +# When set, records are counted in the public table, the the number of history entries for each columng is +# shown, sorted by frequency. +$anvil->data->{switches}{table} = ""; +# When set, tables with less than the minium are ignored. +$anvil->data->{switches}{minimum} = 0; +$anvil->Get->switches(); +$anvil->data->{switches}{minimum} =~ s/,//g; + +if ($anvil->data->{switches}{table}) +{ + count_table($anvil); +} +else +{ + count_all($anvil); +} + +$anvil->nice_exit({exit_code => 0}); + + + +############################################################################################################# +# Functions # +############################################################################################################# + +sub count_table +{ + my ($anvil) = @_; + + # Make sure the table exists. + my $table = $anvil->Database->quote($anvil->data->{switches}{table}); + $table =~ s/^\s+//; + $table =~ s/\s.*//; + $table =~ s/^'(.*)'$/$1/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { table => $table }}); + my $query = " +SELECT + COUNT(*) +FROM + information_schema.tables +WHERE + table_schema = 'history' +AND + table_name = '".$table."' +AND + table_catalog = 'anvil' +;"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + if (not $count) + { + # Table doesn't exist. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "warning_0133", variables => { table => $table }}); + $anvil->nice_exit({exit_code => 1}); + } + + my $uuid_width = 0; + my $count_width = 0; + my $column1 = $table."_uuid"; + my $column2 = ""; + my $column3 = ""; + my $column4 = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column1 => $column1 }}); + if ($table =~ /^(.*)s$/) + { + $column2 = $1."_uuid"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column2 => $column2 }}); + } + if ($table =~ /^(.*)es$/) + { + $column3 = $1."_uuid"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column3 => $column3 }}); + } + if ($table =~ /^(.*)ies$/) + { + $column4 = $1."y_uuid"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column4 => $column4 }}); + } + $query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND column_name = ".$anvil->Database->quote($column1).";"; + if ($column4) + { + $query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->Database->quote($column1)." OR column_name = ".$anvil->Database->quote($column2)." OR column_name = ".$anvil->Database->quote($column3)." OR column_name = ".$anvil->Database->quote($column4).");"; + } + elsif ($column3) + { + $query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->Database->quote($column1)." OR column_name = ".$anvil->Database->quote($column2)." OR column_name = ".$anvil->Database->quote($column3).");"; + } + elsif ($column2) + { + $query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->Database->quote($column1)." OR column_name = ".$anvil->Database->quote($column2).");"; + } + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $uuid_column = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $uuid_column = "" if not defined $uuid_column; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid_column => $uuid_column }}); + if (not $uuid_column) + { + # This is a problem + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "err", key => "error_0311", variables => { table => $table }}); + $anvil->nice_exit({exit_code => 1}); + } + + # This can take a while, ask the user to be patient. + print $anvil->Words->string({key => "message_0269", variables => { + table => $table, + column => $uuid_column, + }})."\n"; + + # Count how many entries exist for each UUID. + $query = " +SELECT + DISTINCT ".$uuid_column." +FROM + history.".$table." +;"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $column_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column_uuid => $column_uuid }}); + + if (length($column_uuid) > $uuid_width) + { + $uuid_width = length($column_uuid); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid_width => $uuid_width }}); + } + + my $query = " +SELECT + COUNT(*) +FROM + history.".$table." +WHERE + ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." +;"; + my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $comma_count = $anvil->Convert->add_commas({number => $count}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + count => $count, + comma_count => $comma_count, + }}); + + $anvil->data->{db_counts}{count}{$count}{$column_uuid} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "db_counts::count::${count}::${column_uuid}" => $anvil->data->{db_counts}{count}{$count}{$column_uuid}, + }}); + + if (length($comma_count) > $count_width) + { + $count_width = length($comma_count); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count_width => $count_width }}); + } + print "."; + } + print "\n"; + + my $queries = []; + my $divider = "-"; + for (1..$uuid_width) { $divider .= "-"; } + $divider .= "-+-"; + for (1..$count_width) { $divider .= "-"; } + $divider .= "-"; + print $anvil->Words->string({key => "message_0268", variables => { table => $table }})."\n"; + print $divider."\n"; + foreach my $count (sort {$a <=> $b} keys %{$anvil->data->{db_counts}{count}}) + { + my $comma_count = $anvil->Convert->add_commas({number => $count}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + count => $count, + comma_count => $comma_count, + }}); + + if (($anvil->data->{switches}{minimum}) && ($anvil->data->{switches}{minimum} =~ /^\d+$/) && ($count < $anvil->data->{switches}{minimum})) + { + # Skip it. + next; + } + + # Sorting by UUID doesn't really make sense, but it provides consistency run over run. + foreach my $column_uuid (sort {$a cmp $b} keys %{$anvil->data->{db_counts}{count}{$count}}) + { + print " ".sprintf("%${uuid_width}s", $column_uuid)." | ".sprintf("%${count_width}s", $comma_count)." \n"; + + # This will need to be updated by the person debugging a table. + #push @{$queries}, "SELECT variable_name, variable_value, variable_source_table, variable_source_uuid FROM variables WHERE variable_uuid = '".$column_uuid."';"; + } + } + print $divider."\n"; + + # Enable this if you're trying to figure out what data is growing, it needs to be edited on a + # per-table basis. + if (0) + { + foreach my $query (@{$queries}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $variable_name = $row->[0]; + my $variable_value = $row->[1]; + my $source_table = $row->[2]; + my $source_uuid = $row->[3]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable_name' => $variable_name, + 's2:variable_value' => $variable_value, + 's3:source_table' => $source_table, + 's4:source_uuid' => $source_uuid, + }}); + + if ($source_table eq "hosts") + { + my $host_name = $anvil->Get->host_name_from_uuid({host_uuid => $source_uuid}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }}); + } + } + } + } + + return(0); +} + +sub count_all +{ + my ($anvil) = @_; + + my $longest_table = 0; + my $longest_public = 0; + my $longest_history = 0; + my $query = " +SELECT + table_schema, + table_name +FROM + information_schema.tables +WHERE + (table_schema = 'public' OR table_schema = 'history') +AND + table_catalog = 'anvil' +ORDER BY + table_name ASC, + table_schema DESC; +;"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $table_schema = $row->[0]; + my $table_name = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + table_schema => $table_schema, + table_name => $table_name, + }}); + + if (not exists $anvil->data->{db_counts}{table}{$table_name}) + { + $anvil->data->{db_counts}{table}{$table_name}{public} = 0; + $anvil->data->{db_counts}{table}{$table_name}{history} = -1; + } + + if (length($table_name) > $longest_table) + { + $longest_table = length($table_name); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { longest_table => $longest_table }}); + } + + my $query = "SELECT COUNT(*) FROM ".$table_schema.".".$table_name.";"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + my $comma_count = $anvil->Convert->add_commas({number => $count}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + count => $count, + comma_count => $comma_count, + }}); + + if ($table_schema eq "public") + { + if (length($comma_count) > $longest_public) + { + $longest_public = length($comma_count); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { longest_public => $longest_public }}); + } + } + else + { + if (length($comma_count) > $longest_history) + { + $longest_history = length($comma_count); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { longest_history => $longest_history }}); + } + } + + $anvil->data->{db_counts}{table}{$table_name}{$table_schema} = $count; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "db_counts::table::${table_name}::${table_schema}" => $anvil->data->{db_counts}{table}{$table_name}{$table_schema}, + }}); + } + + my $say_table = $anvil->Words->string({key => "header_0062"}); + my $say_public = $anvil->Words->string({key => "header_0063"}); + my $say_history = $anvil->Words->string({key => "header_0064"}); + my $divider = "-"; + for (1..$longest_table) { $divider .= "-"; } + $divider .= "-+-"; + for (1..$longest_public) { $divider .= "-"; } + $divider .= "-+-"; + for (1..$longest_history) { $divider .= "-"; } + $divider .= "-"; + + print " ".sprintf("%${longest_table}s", "Table")." | ".sprintf("%${longest_public}s", $say_public)." | ".sprintf("%${longest_history}s", $say_history)." \n"; + print $divider."\n"; + foreach my $table_name (sort {$a cmp $b} keys %{$anvil->data->{db_counts}{table}}) + { + if (($anvil->data->{switches}{minimum}) && ($anvil->data->{switches}{minimum} =~ /^\d+$/)) + { + if (($anvil->data->{db_counts}{table}{$table_name}{public} < $anvil->data->{switches}{minimum}) && + ($anvil->data->{db_counts}{table}{$table_name}{history} < $anvil->data->{switches}{minimum})) + { + # Skip it. + next; + } + } + my $public = $anvil->Convert->add_commas({number => $anvil->data->{db_counts}{table}{$table_name}{public}}); + my $history = $anvil->data->{db_counts}{table}{$table_name}{history} == -1 ? "--" : $anvil->Convert->add_commas({number => $anvil->data->{db_counts}{table}{$table_name}{history}}); + print " ".sprintf("%${longest_table}s", $table_name)." | ".sprintf("%${longest_public}s", $public)." | ".sprintf("%${longest_history}s", $history)." \n"; + } + print $divider."\n"; + + return(0); +} + diff --git a/tools/striker-file-manager b/tools/striker-file-manager new file mode 100755 index 00000000..aed0d50c --- /dev/null +++ b/tools/striker-file-manager @@ -0,0 +1,318 @@ +#!/usr/bin/perl +# +# This is the command line user interface for managing files on /mnt/shared/files on Strikers and made +# available on Anvil! systems. +# + +use strict; +use warnings; +use Anvil::Tools; +use Data::Dumper; +require POSIX; +use Term::Cap; + +my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; +my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; +if (($running_directory =~ /^\./) && ($ENV{PWD})) +{ + $running_directory =~ s/^\./$ENV{PWD}/; +} + +# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. +$| = 1; + +my $anvil = Anvil::Tools->new(); + +# Read switches (target ([user@]host[:port]) and the file with the target's password. +$anvil->Get->switches; +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); + +# Connect to the database(s). +$anvil->Database->connect; +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"}); + + +my $termios = new POSIX::Termios; +$termios->getattr; +my $ospeed = $termios->getospeed; + +my $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed }; +$terminal->Trequire(qw/ce ku kd/); + +interactive_menu($anvil, $termios); + +$anvil->nice_exit({exit_code => 0}); + + + +############################################################################################################# +# Functions # +############################################################################################################# + +sub interactive_menu +{ + my ($anvil, $termios) = @_; + + # This has to run on a striker, so is this a Striker? + my $host_type = $anvil->Get->host_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); + if ($host_type ne "striker") + { + print "Managing files must be run on a Striker dashboard. Exiting\n"; + $anvil->nice_exit({exit_code => 1}); + } + + $anvil->data->{manaing}{file} = ""; + $anvil->data->{manaing}{anvil} = ""; + while(1) + { + # Get a list of files we already know about. Database->get_anvils() also loads files and + # file_locations data + $anvil->Database->get_anvils; + my $longest_file_name = 0; + + print $terminal->Tputs('cl'); + print "-=] Anvil! File Management\n\n"; + # Show the main menu. + print "[ 1 ] - Add a new file.\n"; + print "[ 2 ] - Manage an existing file.\n"; + print "[ 3 ] - Manage files on an Anvil!\n"; + print "\n"; + print "[ Q ] - Quit\n"; + print "\n"; + print $terminal->Tgoto('cm', 0, 8)."? "; + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + + if ($answer eq "1") + { + interactive_menu_add_file($anvil, $terminal); + } + elsif ($answer eq "2") + { + interactive_menu_manage_file($anvil, $terminal); + } + elsif ($answer eq "2") + { + interactive_menu_manage_anvil($anvil, $terminal); + } + elsif (lc($answer) eq "q") + { + print "NO CARRIER, good bye.\n"; + $anvil->nice_exit({exit_code => 0}); + } + } + + return(0); +} + +sub interactive_menu_add_file +{ + my ($anvil, $terminal) = @_; + + print $terminal->Tputs('cl'); + print "-=] Anvil! File Management - Add a new file\n\n"; + + # Build a list of files in /mnt/shared/incoming/ that are not yet in the database. + get_file_list($anvil); + + # Start the array with an empty entry so that users can answer '1' for the first file. + my $files = [""]; + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{manage_files}}) + { + if ($anvil->data->{manage_files}{$file_name}{file_new}) + { + push @{$files}, $file_name; + } + } + my $file_count = (@{$files} - 1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_count => $file_count }}); + + if (not $file_count) + { + print "data->{path}{directories}{shared}{incoming}."]>\n"; + # Show the main menu. + print "\n"; + print "[ B ] - Back\n"; + print "[ Q ] - Quit\n"; + print "\n"; + print $terminal->Tgoto('cm', 0, 7)."? "; + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + if (lc($answer) eq "b") + { + interactive_menu($anvil, $terminal); + } + elsif (lc($answer) eq "q") + { + print "NO CARRIER, good bye.\n"; + $anvil->nice_exit({exit_code => 0}); + } + else + { + interactive_menu_add_file($anvil, $terminal); + } + } + else + { + my $pad = 1; + if ($file_count > 9) + { + $pad = 2; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pad => $pad }}); + + foreach my $i (0..$file_count) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "files->[".$i."]" => $files->[$i] }}); + next if $files->[$i] eq ""; + my $file_name = $files->[$i]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_name => $file_name }}); + print "[ ".sprintf("%${pad}s", $i)." ] - ".$file_name."\n"; + } + print "\n"; + print "[ B ] - Back\n"; + print "[ Q ] - Quit\n"; + print "\n"; + print $terminal->Tgoto('cm', 0, ($file_count + 6))."Which file would you like to add? "; + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + if (($answer =~ /^\d+$/) && (exists $files->[$answer]) and ($files->[$answer])) + { + my $file_name = $files->[$answer]; + print $terminal->Tputs('cl'); + print "-=] Anvil! File Management - Add a new file\n\n"; + print "Confirm addition of: [".$file_name."] [y/N] ?\n"; + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + if ($answer =~ /^y/i) + { + print "Creating a job to add the file. Please be patient, it should be added shortly.\n"; + my $out_file = $anvil->data->{path}{directories}{shared}{incoming}."/".$file_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { out_file => $out_file }}); + + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + file => $THIS_FILE, + line => __LINE__, + job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}, + job_data => "file=".$out_file, + job_name => "storage::move_incoming", + job_title => "job_0132", + job_description => "job_0133", + job_progress => 0, + job_host_uuid => $anvil->data->{sys}{host_uuid}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + print "- Job created as: [".$job_uuid."]\n\n"; + print "Press any key to return to the main menu.\n"; + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + interactive_menu($anvil, $terminal); + } + else + { + print "Aborted.\n"; + sleep 1; + interactive_menu_add_file($anvil, $terminal); + } + } + elsif (lc($answer) eq "b") + { + interactive_menu($anvil, $terminal); + } + elsif (lc($answer) eq "q") + { + print "NO CARRIER, good bye.\n"; + $anvil->nice_exit({exit_code => 0}); + } + else + { + interactive_menu_add_file($anvil, $terminal); + } + } + + return(0); +} + +sub interactive_menu_manage_file +{ + my ($anvil, $terminal) = @_; + + print $terminal->Tputs('cl'); + print "-=] Anvil! File Management - Manage an existing file\n\n"; + + if (0) + { + } + else + { + print "NO CARRIER, good bye.\n"; + $anvil->nice_exit({exit_code => 0}); + } + + return(0); +} + +sub interactive_menu_manage_anvil +{ + my ($anvil, $terminal) = @_; + + + print $terminal->Tputs('cl'); + print "-=] Anvil! File Management - Manage Files on an Anvil!\n\n"; + + if (0) + { + } + else + { + print "NO CARRIER, good bye.\n"; + $anvil->nice_exit({exit_code => 0}); + } + + return(0); +} + +# This looks for files in /mnt/shared/incoming and collects their file_uuid, if found in the database. +sub get_file_list +{ + my ($anvil) = @_; + + if (exists $anvil->data->{manage_files}) + { + delete $anvil->data->{manage_files}; + } + my $directory = $anvil->data->{path}{directories}{shared}{incoming}; + local(*DIRECTORY); + opendir(DIRECTORY, $directory); + while(my $file_name = readdir(DIRECTORY)) + { + next if $file_name eq "."; + next if $file_name eq ".."; + # Ignore hidden files (which includes files still being copied) + next if $file_name =~ /^\./; + my $full_path = $directory."/".$file_name; + + # No file should match, but just in case... + if (exists $anvil->data->{files}{file_name}{$file_name}) + { + ### TODO: Log that this is a duplicate. + $anvil->data->{manage_files}{$file_name}{file_uuid} = $anvil->data->{files}{file_name}{$file_name}{file_uuid}; + $anvil->data->{manage_files}{$file_name}{file_new} = 0; + + } + else + { + $anvil->data->{manage_files}{$file_name}{file_uuid} = ""; + $anvil->data->{manage_files}{$file_name}{file_new} = 1; + } + } + closedir(DIRECTORY); + + return(0); +} diff --git a/tools/striker-get-peer-data b/tools/striker-get-peer-data index 52ed6b97..cb6119d2 100755 --- a/tools/striker-get-peer-data +++ b/tools/striker-get-peer-data @@ -340,7 +340,7 @@ sub get_password } my $query = "SELECT state_note FROM states WHERE state_uuid = ".$anvil->Database->quote($anvil->data->{switches}{'state-uuid'}).";"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $password = $anvil->Database->query({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $password = "" if not defined $password; diff --git a/tools/striker-manage-install-target b/tools/striker-manage-install-target index 6fa6f859..cbf97873 100755 --- a/tools/striker-manage-install-target +++ b/tools/striker-manage-install-target @@ -176,7 +176,7 @@ if ($anvil->data->{switches}{disable}) # Exit if we're not configured yet my $configured = $anvil->System->check_if_configured; -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }}); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }}); if (not $configured) { print $anvil->Words->string({key => "error_0046"})."\n"; diff --git a/tools/striker-prep-database b/tools/striker-prep-database index e5b62cc0..abbb4034 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -10,6 +10,9 @@ # 3 = ScanCore user not set in the local ID in anvil.conf # 4 = Failed to create the database user. # 5 = PostgreSQL not installed. +# +# TODO: Much of this logic is duplicated in Database->configure_pgsql(), we should remove this tool entirely +# and use that. use strict; use warnings; @@ -29,7 +32,9 @@ $| = 1; my $anvil = Anvil::Tools->new(); $anvil->Get->switches; -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); $anvil->System->_check_anvil_conf({debug => 2}); @@ -39,8 +44,14 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list # If we didn't get the $local_uuid, then there is no entry for this system in anvil.conf yet, so we'll add it. if (not $local_uuid) { - $local_uuid = add_to_local_config($anvil); + $local_uuid = $anvil->Database->_add_to_local_config({debug => 2}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }}); + + if ($local_uuid eq "!!error!!") + { + # Already logged the error, exit. + $anvil->nice_exit({exit_code => 1}); + } } # Now configure! @@ -49,15 +60,39 @@ if ($local_uuid) # Start checks $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::service::postgresql" => $anvil->data->{sys}{daemon}{postgresql} }}); - my $running = $anvil->System->check_daemon({debug => 3, daemon => $anvil->data->{sys}{daemon}{postgresql}}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }}); - if ($running eq "2") + # Check that the firewall is open. + configure_firewall($anvil); + + # Wait until postgresql is installed, in case we're running during initial dnf install. + my $installed = 0; + until($installed) { - # Not installed. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0144"}); - $anvil->nice_exit({exit_code => 5}); + my $shell_call = $anvil->data->{path}{exe}{rpm}." -q postgresql-server"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 3, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + output => $output, + return_code => $return_code, + }}); + + if ($return_code) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0131"}); + sleep 5; + } + else + { + # Installed. + $installed = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { installed => $installed }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0670"}); + } } - elsif (not $running) + + my $running = $anvil->System->check_daemon({debug => 2, daemon => $anvil->data->{sys}{daemon}{postgresql}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }}); + if (not $running) { # Do we need to initialize the databae? $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::configs::pg_hba.conf" => $anvil->data->{path}{configs}{'pg_hba.conf'} }}); @@ -69,8 +104,11 @@ if ($local_uuid) else { # Initialize. - my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'postgresql-setup'}." --initdb --unit postgresql", source => $THIS_FILE, line => __LINE__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + my $shell_call = $anvil->data->{path}{exe}{'postgresql-setup'}." --initdb --unit postgresql"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { output => $output, return_code => $return_code, }}); @@ -245,10 +283,13 @@ if ($local_uuid) if (not $database_user) { # No database user defined + $database_user = "admin"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0099", variables => { uuid => $local_uuid }}); - $anvil->nice_exit({exit_code => 3}); } - my ($user_list, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"", source => $THIS_FILE, line => __LINE__}); + my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($user_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { user_list => $user_list, return_code => $return_code, @@ -259,7 +300,10 @@ if ($local_uuid) { # User exists already my $id = $1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0060", variables => { user => $database_user, id => $id }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0060", variables => { + user => $database_user, + id => $id, + }}); $create_user = 0; last; } @@ -268,13 +312,18 @@ if ($local_uuid) if ($create_user) { # Create the user - my ($create_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createuser}." --no-superuser --createdb --no-createrole $database_user\"", source => $THIS_FILE, line => __LINE__}); + my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createuser}." --no-superuser --createdb --no-createrole $database_user\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($create_output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { create_output => $create_output, user_list => $user_list, }}); - (my $user_list, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"", source => $THIS_FILE, line => __LINE__}); + undef $shell_call; + $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + (my $user_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { create_output => $create_output, user_list => $user_list, @@ -296,26 +345,28 @@ if ($local_uuid) $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0096", variables => { user => $database_user }}); $anvil->nice_exit({exit_code => 4}); } - - # Update/set the passwords. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "database::${local_uuid}::password" => $anvil->data->{database}{$local_uuid}{password} }}); - if ($anvil->data->{database}{$local_uuid}{password}) + } + + # Update/set the passwords. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "database::${local_uuid}::password" => $anvil->data->{database}{$local_uuid}{password} }}); + if ($anvil->data->{database}{$local_uuid}{password}) + { + foreach my $user ("postgres", $database_user) { - foreach my $user ("postgres", $database_user) + my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c \\\"ALTER ROLE $user WITH PASSWORD '".$anvil->data->{database}{$local_uuid}{password}."';\\\"\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($update_output, $return_code) = $anvil->System->call({secure => 1, shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { + update_output => $update_output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $user_list) { - my ($update_output, $return_code) = $anvil->System->call({secure => 1, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c \\\"ALTER ROLE $user WITH PASSWORD '".$anvil->data->{database}{$local_uuid}{password}."';\\\"\"", source => $THIS_FILE, line => __LINE__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { - update_output => $update_output, - return_code => $return_code, - }}); - foreach my $line (split/\n/, $user_list) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /ALTER ROLE/) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /ALTER ROLE/) - { - # Password set - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0100", variables => { user => $user }}); - } + # Password set + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0100", variables => { user => $user }}); } } } @@ -325,9 +376,17 @@ if ($local_uuid) my $create_database = 1; my $database_name = $anvil->data->{database}{$local_uuid}{name} ? $anvil->data->{database}{$local_uuid}{name} : $anvil->data->{sys}{database}{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_name => $database_name }}); + if (not $database_name) + { + $database_name = "anvil"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_name => $database_name }}); + } undef $return_code; - (my $database_list, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"", source => $THIS_FILE, line => __LINE__}); + undef $shell_call; + $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + (my $database_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_list => $database_list, return_code => $return_code, @@ -343,25 +402,32 @@ if ($local_uuid) last; } } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { create_database => $create_database }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { create_database => $create_database }}); if ($create_database) { - my ($create_output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createdb}." --owner ".$database_user." ".$database_name."\"", source => $THIS_FILE, line => __LINE__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createdb}." --owner ".$database_user." ".$database_name."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); + + my ($create_output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { create_output => $create_output, return_code => $return_code, }}); undef $return_code; - my $database_exists = 0; - (my $database_list, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"", source => $THIS_FILE, line => __LINE__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + undef $shell_call; + my $database_exists = 0; + $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); + + (my $database_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { database_list => $database_list, return_code => $return_code, }}); foreach my $line (split/\n/, $database_list) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { line => $line }}); if ($line =~ /^ $database_name$/) { # Database created @@ -373,11 +439,14 @@ if ($local_uuid) if (not $database_exists) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0109", variables => { database => $database_name }}); - $anvil->nice_exit({exit_code => 5}); } } # Remove the temporary password file. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + created_pgpass => $created_pgpass, + "path::secure::postgres_pgpass" => $anvil->data->{path}{secure}{postgres_pgpass}, + }}); if (($created_pgpass) && (-e $anvil->data->{path}{secure}{postgres_pgpass})) { unlink $anvil->data->{path}{secure}{postgres_pgpass}; @@ -394,6 +463,7 @@ if ($local_uuid) ### TODO: This will need to set the proper SELinux context. # Apache run scripts can't call the system UUID, so we'll write it to a text file. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::data::host_uuid" => $anvil->data->{path}{data}{host_uuid} }}); if (not -e $anvil->data->{path}{data}{host_uuid}) { $anvil->Storage->write_file({ @@ -410,6 +480,7 @@ if ($local_uuid) # Log level 3 creates so much logging that it hits journald's rate limiting (1000 logs per 30 # seconds). So we need to disable it. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::configs::journald_anvil" => $anvil->data->{path}{configs}{'journald_anvil'} }}); if (not -e $anvil->data->{path}{configs}{'journald_anvil'}) { # Write the file to disable journald rate limiting. @@ -432,7 +503,10 @@ RateLimitBurst=0 }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0012", variables => { file => $anvil->data->{path}{configs}{'journald_anvil'} }}); - my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{systemctl}." restart systemd-journald.service", source => $THIS_FILE, line => __LINE__}); + my $shell_call = $anvil->data->{path}{exe}{systemctl}." restart systemd-journald.service"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, @@ -452,48 +526,122 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# -# This adds this machine to the local anvil.conf file. -sub add_to_local_config +sub configure_firewall { my ($anvil) = @_; - # Write the password to a file. - my $password_file = "/tmp/striker-manage-peers.".$anvil->Get->uuid; - $anvil->Storage->write_file({ - debug => 3, - secure => 1, - file => $password_file, - body => "Initial1", - mode => "0600", - overwrite => 1, - }); - - # Make the shell call, and parse the output looking for our own entry - my $host_uuid = $anvil->Get->host_uuid(); - my ($output, $return_code) = $anvil->System->call({ - debug => 2, - shell_call => $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$anvil->Get->host_uuid." --host localhost --port 5432 --password-file ".$password_file." --ping 0".$anvil->Log->switches, - source => $THIS_FILE, - line => __LINE__, - }); + # What zones are there? + my $in_zone = ""; + my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --get-active-zones"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); - # Remove the password. - unlink $password_file; + # If the return code was 252, firewalld isn't running. + if ($return_code eq "252") + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0669"}); + return(0); + } + + foreach my $line (split/\n/, $output) + { + if ($line =~ /^\S/) + { + $in_zone = $line; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_zone => $in_zone }}); + + $anvil->data->{firewall}{zone}{$in_zone}{active} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "firewall::zone::${in_zone}::active" => $anvil->data->{firewall}{zone}{$in_zone}{active}, + }}); + } + elsif ($line =~ /^\s+interfaces: (.*)$/) + { + my $interfaces = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interfaces => $interfaces }}); + + $anvil->data->{firewall}{zone}{$in_zone}{interfaces} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "firewall::zone::${in_zone}::interfaces" => $anvil->data->{firewall}{zone}{$in_zone}{interfaces}, + }}); + } + } - # Re-read the config and make sure we have our own entry. - $anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}}); + my $reload = 0; + foreach my $zone (sort {$a cmp $b} keys %{$anvil->data->{firewall}{zone}}) + { + my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --info-zone=".$zone; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + if ($line =~ /^\s+services: (.*)$/) + { + my $services = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { services => $services }}); + + foreach my $service (split/ /, $services) + { + $anvil->data->{firewall}{zone}{$in_zone}{service}{$service} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "firewall::zone::${in_zone}::service::${service}" => $anvil->data->{firewall}{zone}{$in_zone}{service}{$service}, + }}); + } + } + } + + # Is postgres open? + if ((not exists $anvil->data->{firewall}{zone}{$in_zone}{service}{postgresql}) or (not $anvil->data->{firewall}{zone}{$in_zone}{service}{postgresql})) + { + ### TODO: Switch this to System->manage_firewall(). + # Enable it. + my $service = "postgresql"; + $reload = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + service => $service, + reload => $reload, + }}); + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0667", variables => { + zone => $zone, + service => $service, + }}); + + my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --zone=".$zone." --permanent --add-service=".$service; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + } - # If we still don't have a local_uuid, something went wrong. - if (not $anvil->data->{database}{$host_uuid}{host}) + # Reload the firewall? + if ($reload) { - print $anvil->Words->string({key => "error_0010"})."\n"; - $anvil->nice_exit({exit_code => 1}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0139"}); + + my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --reload"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); } - return($host_uuid); + return(0); } diff --git a/units/anvil-daemon.service b/units/anvil-daemon.service index 95169f76..c9915ceb 100644 --- a/units/anvil-daemon.service +++ b/units/anvil-daemon.service @@ -4,7 +4,6 @@ Wants=network.target [Service] Type=simple -ExecStartPre=-/bin/sh -c "if [ -f /usr/sbin/akmods ]; then /usr/sbin/modprobe drbd || /usr/sbin/akmods --force; fi" ExecStart=/usr/sbin/anvil-daemon ExecStop=/bin/kill -WINCH ${MAINPID} Restart=always