From 5c1978d5a06f0fc3ecc3b8c88cf3ad103cf49d6e Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 25 Oct 2021 19:16:01 -0400 Subject: [PATCH 01/37] Updated D-Link switch config notes. Signed-off-by: Digimer --- notes | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/notes b/notes index 7fa37928..c9234d5e 100644 --- a/notes +++ b/notes @@ -960,19 +960,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 +1228,6 @@ 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 rs-striker03#show vlan @@ -1412,3 +1410,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 + From 257a9987436ba2f672ec34c948d4c81b0f4fd624 Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 28 Oct 2021 12:07:36 -0400 Subject: [PATCH 02/37] * Updated Database->configure_pgsql() to use 'postgresql-setup --initdb --unit postgresql' instead of the deprecaded 'initdb' switch. * Updated Database->insert_or_update_states() to switch to an active UUID if the passed in UUID is not an active handle. * Updated Database->query() to swutch to 'sys::database::read_uuid' if the passed in 'uuid' is not an active handle. * Updated Database->_test_access() to return immediately if the passed in uuid is not an active handle. * Started working on a Storage->get_storage_group_from_path() bug where the storage group isn't being returned. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 53 ++++++++++++++++++++--- Anvil/Tools/Storage.pm | 17 +++++--- scancore-agents/scan-apc-ups/scan-apc-ups | 4 +- share/words.xml | 1 + tools/anvil-manage-server | 8 +++- tools/striker-get-peer-data | 2 +- 6 files changed, 69 insertions(+), 16 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 7e84ee06..bb75e94a 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -806,7 +806,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? @@ -12031,7 +12031,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 +15313,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) { @@ -17391,6 +17421,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 +17433,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/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/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/share/words.xml b/share/words.xml index 8b6c8946..43ba5578 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2056,6 +2056,7 @@ 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!#].]]> The host name: [#!variable!target!#] does not resolve to an IP address. 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/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; From 32f29861a4c8b228235841361572fd5f97240fdb Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 15 Nov 2021 01:01:23 -0500 Subject: [PATCH 03/37] * Fixed a bug (maybe) that was causing users to get immediately logged out of the WebUI * Fixed a bug (maybe) that was breaking initial DB setup on Strikers. Signed-off-by: Digimer --- Anvil/Tools/Account.pm | 10 ++++++---- Anvil/Tools/Database.pm | 4 +++- cgi-bin/striker | 10 +++++----- notes | 2 ++ 4 files changed, 16 insertions(+), 10 deletions(-) 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/Database.pm b/Anvil/Tools/Database.pm index bb75e94a..fdfee948 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1321,12 +1321,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. @@ -1708,7 +1710,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"}); diff --git a/cgi-bin/striker b/cgi-bin/striker index 85bc0858..d7f32cb5 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 }}); } } diff --git a/notes b/notes index c9234d5e..81134638 100644 --- a/notes +++ b/notes @@ -18,6 +18,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; From 090c59a8734efeeea1f2262feb9fdd528eec429f Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 16 Nov 2021 03:20:27 -0500 Subject: [PATCH 04/37] Updated striker-prep-database to enable extra logging to help diagnose a function test build failure problem. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 5 +- share/words.xml | 4 +- tools/striker-prep-database | 95 +++++++++++++++++++++++++++---------- 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index fdfee948..bea1e655 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15594,9 +15594,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}); } diff --git a/share/words.xml b/share/words.xml index 43ba5578..69dc0058 100644 --- a/share/words.xml +++ b/share/words.xml @@ -1364,7 +1364,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 +1421,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. diff --git a/tools/striker-prep-database b/tools/striker-prep-database index e5b62cc0..a534effa 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -29,6 +29,10 @@ $| = 1; my $anvil = Anvil::Tools->new(); $anvil->Get->switches; + +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); $anvil->System->_check_anvil_conf({debug => 2}); @@ -49,7 +53,7 @@ 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}}); + 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 ($running eq "2") { @@ -69,8 +73,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 +252,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 +269,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 +281,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, @@ -303,7 +321,9 @@ if ($local_uuid) { foreach my $user ("postgres", $database_user) { - 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__}); + 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, @@ -325,9 +345,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 +371,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 +408,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 => 2, 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 +432,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 +449,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 +472,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, @@ -469,13 +512,13 @@ sub add_to_local_config }); # 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__, - }); + my $host_uuid = $anvil->Get->host_uuid(); + 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 => 2, list => { + host_uuid => $host_uuid, + 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, From b517117bc1ebc92652c004bf04df2454afd75b05 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 23 Nov 2021 20:41:29 -0500 Subject: [PATCH 05/37] * Did more work on trying to figure out why iniital setup of the database was failing. I believe it was because, in anvil-daemon, after calling 'prep_database' we called ->connect() _without_ 'check_if_configured' set. Next round of function testing should help confirm is this was the case. * Added 'configure_firewall()' to 'striker-prep-database' to explicitely open the postgresql service for all active zones. * Did some general logging changes and cleanup around the same. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 24 +++++-- share/words.xml | 2 + tools/anvil-daemon | 10 +-- tools/striker-prep-database | 128 ++++++++++++++++++++++++++++++++++-- 4 files changed, 149 insertions(+), 15 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index bea1e655..479bb386 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1344,20 +1344,23 @@ sub connect foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { # Periodically, autovivication causes and empty key to appear. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); next if ((not $uuid) or (not $anvil->Validate->uuid({uuid => $uuid}))); 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 @@ -1365,7 +1368,7 @@ sub connect my $name = $anvil->data->{database}{$uuid}{name}; my $user = $anvil->data->{database}{$uuid}{user}; my $password = $anvil->data->{database}{$uuid}{password}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host => $host, port => $port, name => $name, @@ -1373,6 +1376,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}) diff --git a/share/words.xml b/share/words.xml index 69dc0058..4bc526a2 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2057,6 +2057,8 @@ The file: [#!variable!file!#] needs to be updated. The difference is: [ 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 host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index c7fb3226..a258adf7 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -105,8 +105,7 @@ if (not $anvil->data->{sys}{database}{connections}) prep_database($anvil); # Try connecting again - $anvil->refresh(); - $anvil->Database->connect(); + $anvil->Database->connect({debug => 2, 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}) { @@ -1176,8 +1175,11 @@ sub prep_database { ### 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 => { + 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 => 1, list => { database_output => $database_output, return_code => $return_code, }}); diff --git a/tools/striker-prep-database b/tools/striker-prep-database index a534effa..b8d22f9e 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -33,7 +33,7 @@ $anvil->Get->switches; $anvil->Log->level({set => 2}); $anvil->Log->secure({set => 1}); -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); $anvil->System->_check_anvil_conf({debug => 2}); @@ -53,6 +53,9 @@ if ($local_uuid) # Start checks $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::service::postgresql" => $anvil->data->{sys}{daemon}{postgresql} }}); + # Check that the firewall is open. + configure_firewall($anvil); + 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 ($running eq "2") @@ -495,6 +498,117 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# +sub configure_firewall +{ + my ($anvil) = @_; + + # 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, + }}); + 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}, + }}); + } + } + + 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, + }}); + } + } + + # Reload the firewall? + if ($reload) + { + $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(0); +} + # This adds this machine to the local anvil.conf file. sub add_to_local_config { @@ -518,7 +632,7 @@ sub add_to_local_config host_uuid => $host_uuid, shell_call => $shell_call, }}); - my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__}); + 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, return_code => $return_code, @@ -528,12 +642,18 @@ sub add_to_local_config unlink $password_file; # Re-read the config and make sure we have our own entry. - $anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}}); + $anvil->refresh(); # If we still don't have a local_uuid, something went wrong. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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}) { - print $anvil->Words->string({key => "error_0010"})."\n"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0010"}); $anvil->nice_exit({exit_code => 1}); } From 8e41814ca20ae81e69bedf43aa717383ffef1dc0 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 23 Nov 2021 21:49:24 -0500 Subject: [PATCH 06/37] * Updated anvil-daemon->prep_database() to start the postgresql daemon if it's not running and no databases are available. Signed-off-by: Digimer --- tools/anvil-daemon | 40 +++++++++++++++++++++++++++---------- tools/striker-prep-database | 4 ---- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/tools/anvil-daemon b/tools/anvil-daemon index a258adf7..1cb42c66 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1155,6 +1155,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"; @@ -1164,7 +1165,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 }}); } } @@ -1173,16 +1175,32 @@ 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 $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 => 1, list => { - database_output => $database_output, - return_code => $return_code, - }}); + if ($prep_database) + { + ### 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, + }}); + } + else + { + # 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/striker-prep-database b/tools/striker-prep-database index b8d22f9e..f0e9c02a 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -29,10 +29,6 @@ $| = 1; my $anvil = Anvil::Tools->new(); $anvil->Get->switches; - -$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}); From 6225ce194306e9afc1fc776cd190e5f47fb7e737 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 23 Nov 2021 23:32:07 -0500 Subject: [PATCH 07/37] Updated striker-prep-database to not configure the firewall if firewalld isn't running. Signed-off-by: Digimer --- share/words.xml | 1 + tools/striker-prep-database | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/share/words.xml b/share/words.xml index 4bc526a2..5c4bf03c 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2059,6 +2059,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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 host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/striker-prep-database b/tools/striker-prep-database index f0e9c02a..a2b50b8e 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -507,6 +507,14 @@ sub configure_firewall output => $output, return_code => $return_code, }}); + + # 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/) From 034c38fdebdd4498fceb10ff66f94afa74a19fc2 Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 24 Nov 2021 00:55:02 -0500 Subject: [PATCH 08/37] Disabled calling striker-prep-database from the spec file, and enabled scancore. Signed-off-by: Digimer --- anvil.spec.in | 9 ++++++--- tools/anvil-daemon | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/anvil.spec.in b/anvil.spec.in index d1952b3b..20e074fc 100644 --- a/anvil.spec.in +++ b/anvil.spec.in @@ -237,6 +237,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 +254,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/tools/anvil-daemon b/tools/anvil-daemon index 1cb42c66..29142c78 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -91,7 +91,11 @@ $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({ + debug => 2, + 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). From 958267e38f31cb1876c9f8843d0065ab561724c6 Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 24 Nov 2021 01:22:33 -0500 Subject: [PATCH 09/37] * Enabled scancore in the .spec file. Disabled calling striker-prep-database and anvil-update-state in the same. * Updated striker-prep-database to check / wait until postgresql-server is installed. Signed-off-by: Digimer --- share/words.xml | 2 ++ tools/striker-prep-database | 39 +++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/share/words.xml b/share/words.xml index 5c4bf03c..91ff0d07 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2060,6 +2060,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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 name: [#!variable!target!#] does not resolve to an IP address. @@ -3084,6 +3085,7 @@ 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. diff --git a/tools/striker-prep-database b/tools/striker-prep-database index a2b50b8e..22c3db58 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -29,6 +29,8 @@ $| = 1; my $anvil = Anvil::Tools->new(); $anvil->Get->switches; +$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}); @@ -52,15 +54,36 @@ if ($local_uuid) # Check that the firewall is open. configure_firewall($anvil); - 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 ($running eq "2") + # 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 => 2, 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'} }}); @@ -411,7 +434,7 @@ if ($local_uuid) } # Remove the temporary password file. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $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}, }}); From 36bcaa587f309dd834fb194729d031a50ebf6690 Mon Sep 17 00:00:00 2001 From: "Fabio M. Di Nitto" Date: Wed, 24 Nov 2021 21:58:16 +0100 Subject: [PATCH 10/37] [build] fix FASEXECPREFIX handling and ship fence_ in -core rpm Signed-off-by: Fabio M. Di Nitto --- configure.ac | 4 ++-- tools/Makefile.am | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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 \ From 75a4c8d709bb06904ecdaa06401277fcd3f26c33 Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 25 Nov 2021 01:47:55 -0500 Subject: [PATCH 11/37] * Moved the logic to add the local database to a Striker's anvil.conf from striker-prep-database to Database->_add_to_local_config(). * Updated striker-prep-database to always set the user's password, independent of whether the database user was created. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 90 +++++++++++++++++++++++++++++++ tools/striker-prep-database | 102 +++++++++++------------------------- 2 files changed, 120 insertions(+), 72 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 479bb386..0d274766 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 => 2, 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; @@ -16415,6 +16434,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 diff --git a/tools/striker-prep-database b/tools/striker-prep-database index 22c3db58..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; @@ -41,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! @@ -61,7 +70,7 @@ if ($local_uuid) 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 => 2, source => $THIS_FILE, line => __LINE__}); + 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, @@ -336,28 +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 $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) + $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 }}); } } } @@ -636,54 +645,3 @@ sub configure_firewall return(0); } -# This adds this machine to the local anvil.conf file. -sub add_to_local_config -{ - 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 $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 => 2, 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 => 2, 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 => 2, 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"}); - $anvil->nice_exit({exit_code => 1}); - } - - return($host_uuid); -} - From 9eec6c49779db0df9a28a75e1e3ced3e8b9aa53c Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 29 Nov 2021 22:43:23 -0500 Subject: [PATCH 12/37] * Created ScanCore->check_temperature_direct() based around that start logic from ScanCore->post_scan_analysis_striker() temperature check, and updated the later to use the former. * Updated the logic of when to boot a node or DR host that was found to be off for unknown reasons to require both poewr and temperature to be OK, and checks against the new 'feature::scancore::disable::boot-unknown-stop' config variable. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 4 +- Anvil/Tools/ScanCore.pm | 242 +++++++++++++++++++++++++++++----------- anvil.conf | 5 + share/words.xml | 7 +- 4 files changed, 190 insertions(+), 68 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 0d274766..3ee83f85 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1363,7 +1363,7 @@ sub connect foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}}) { # Periodically, autovivication causes and empty key to appear. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); next if ((not $uuid) or (not $anvil->Validate->uuid({uuid => $uuid}))); if (($db_uuid) && ($db_uuid ne $uuid)) @@ -1387,7 +1387,7 @@ sub connect my $name = $anvil->data->{database}{$uuid}{name}; my $user = $anvil->data->{database}{$uuid}{user}; my $password = $anvil->data->{database}{$uuid}{password}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host, port => $port, name => $name, diff --git a/Anvil/Tools/ScanCore.pm b/Anvil/Tools/ScanCore.pm index 9b50f8c0..7e2d6600 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 @@ -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.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/share/words.xml b/share/words.xml index 91ff0d07..1c75d45f 100644 --- a/share/words.xml +++ b/share/words.xml @@ -1947,7 +1947,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 +1955,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. @@ -2061,6 +2061,9 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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 host name: [#!variable!target!#] does not resolve to an IP address. From 65dfc22a38774a96c6cd6df320d31293b360bd3b Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 30 Nov 2021 17:58:29 -0500 Subject: [PATCH 13/37] Added an eval{} call around Database->query()'s ->prepare() DBI call to better handle lost database handle. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 26 +++++++++++++++++++++++--- share/words.xml | 2 ++ tools/anvil-daemon | 3 +-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 3ee83f85..2dfadcb9 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -803,7 +803,7 @@ sub configure_pgsql # 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 => 2, list => { local_uuid => $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) @@ -15393,12 +15393,27 @@ 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 ($@) + { + $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 => { @@ -15667,6 +15682,7 @@ sub resync_databases ### 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. @@ -16117,6 +16133,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); } diff --git a/share/words.xml b/share/words.xml index 1c75d45f..ba99971f 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2064,6 +2064,8 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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. ]]> The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 29142c78..2db260ce 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -92,7 +92,6 @@ $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({ - debug => 2, check_if_configured => 1, check_for_resync => 1, }); @@ -109,7 +108,7 @@ if (not $anvil->data->{sys}{database}{connections}) prep_database($anvil); # Try connecting again - $anvil->Database->connect({debug => 2, 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 (not $anvil->data->{sys}{database}{connections}) { From 9cfd7b9b94319c7ea938a3ba18fc3e10a99b9f74 Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 1 Dec 2021 18:43:50 -0500 Subject: [PATCH 14/37] Created the new (and still in development) striker-file-manager to manage files from a Striker dashboard's command line. So far. it will add files only. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 2 + tools/anvil-sync-shared | 2 +- tools/striker-file-manager | 318 ++++++++++++++++++++++++++++ tools/striker-manage-install-target | 2 +- 4 files changed, 322 insertions(+), 2 deletions(-) create mode 100755 tools/striker-file-manager diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 2dfadcb9..9bda9807 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15401,6 +15401,8 @@ sub query }}); }; 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, 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/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-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"; From cc4c3bd3e36e8c7d7dce5c2427d748ec2b415be2 Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 2 Dec 2021 12:41:21 -0500 Subject: [PATCH 15/37] Added ssh askpass for Striker so VMM can ask to confirm fingerprints. Signed-off-by: Digimer --- anvil.spec.in | 1 + 1 file changed, 1 insertion(+) diff --git a/anvil.spec.in b/anvil.spec.in index 20e074fc..bdf7b6ad 100644 --- a/anvil.spec.in +++ b/anvil.spec.in @@ -131,6 +131,7 @@ Requires: gdm Requires: gnome-terminal Requires: httpd Requires: nmap +Requires: openssh-askpass Requires: postgresql-server Requires: syslinux Requires: syslinux-nonlinux From 3346d31194f9563b091ed7f9a0c0f9c9a839ebb6 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 7 Dec 2021 20:03:39 -0500 Subject: [PATCH 16/37] * Created Get->kernel_release() that returns the current kernel release (version) in use on the host or on a remote system. * Created DRBD->_initialize_drbd() to makes sure the DRBD kernel module can load and tries to build the module, if necessary. This is meant to provide support for clients that can't access needed internet resource (or the internet at all). Signed-off-by: Digimer --- Anvil/Tools.pm | 2 + Anvil/Tools/DRBD.pm | 113 ++++++++++++++++++++++++++++++++++++++++++ Anvil/Tools/Get.pm | 89 +++++++++++++++++++++++++++++++++ Anvil/Tools/System.pm | 1 + share/words.xml | 6 +++ tools/anvil-daemon | 6 ++- 6 files changed, 216 insertions(+), 1 deletion(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 16d4ad8c..27f7540b 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", 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/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/System.pm b/Anvil/Tools/System.pm index e4483c6c..23004517 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -3152,6 +3152,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/share/words.xml b/share/words.xml index ba99971f..54e38203 100644 --- a/share/words.xml +++ b/share/words.xml @@ -501,6 +501,7 @@ 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!#]. @@ -2066,6 +2067,10 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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! The host name: [#!variable!target!#] does not resolve to an IP address. @@ -3091,6 +3096,7 @@ 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 likely that this machine will be able to run any servers until this is fixed. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 2db260ce..8b1aa0b0 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1126,11 +1126,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 }}); @@ -1147,6 +1148,9 @@ sub handle_special_cases group => "root", }); } + + # Make sure DRBD compiled after a kernel upgrade. + $anvil->DRBD->_initialize_kmod({debug => 2}); } return(0); From 8ded17b42dab4b7751ff9d9ae4305b4f8219f351 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 7 Dec 2021 20:13:11 -0500 Subject: [PATCH 17/37] Removed the anvil-daemon unit file attempt to compile DRBD's kernel module. Signed-off-by: Digimer --- units/anvil-daemon.service | 1 - 1 file changed, 1 deletion(-) 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 From b0a2bd812387c707fe4bb134358ea83de92b1044 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Dec 2021 04:49:25 +0000 Subject: [PATCH 18/37] chore: bump next from 11.1.1 to 11.1.3 in /striker-ui Bumps [next](https://github.com/vercel/next.js) from 11.1.1 to 11.1.3. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v11.1.1...v11.1.3) --- updated-dependencies: - dependency-name: next dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- striker-ui/package-lock.json | 194 +++++++++++++++++++++-------------- striker-ui/package.json | 2 +- 2 files changed, 117 insertions(+), 79 deletions(-) diff --git a/striker-ui/package-lock.json b/striker-ui/package-lock.json index c1c49d7f..6611351b 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": { @@ -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", From 5fcbc358846c9644f4cf1ebb2b827ee6cd40b1bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 22:40:22 +0000 Subject: [PATCH 19/37] chore: bump ansi-regex from 5.0.0 to 5.0.1 in /striker-ui Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/chalk/ansi-regex/releases) - [Commits](https://github.com/chalk/ansi-regex/compare/v5.0.0...v5.0.1) --- updated-dependencies: - dependency-name: ansi-regex dependency-type: indirect ... Signed-off-by: dependabot[bot] --- striker-ui/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/striker-ui/package-lock.json b/striker-ui/package-lock.json index 6611351b..94c2fba3 100644 --- a/striker-ui/package-lock.json +++ b/striker-ui/package-lock.json @@ -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", From 72038e83588f83178d51667ca8668f339439cb3d Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 3 Jan 2022 17:06:56 -0500 Subject: [PATCH 20/37] * Fixed a bug where ethtool's Media type contained tab characters that broke JSON when configuring the netowrk interfaces. * Updated the copywrite date to 2022. * Updated the database resync to not run on machines host VMs to help reduce the chance of oom-killer terminating a VM. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 9 +++++ Anvil/Tools/Server.pm | 69 +++++++++++++++++++++++++++++++++++++++ share/words.xml | 7 ++-- tools/anvil-daemon | 2 +- tools/anvil-update-states | 15 +++++++-- 5 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 9bda9807..4fa02d39 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15680,6 +15680,15 @@ sub resync_databases return(0); } + # 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); + } + ### 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 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/share/words.xml b/share/words.xml index 54e38203..ad92ad88 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 @@ -2071,6 +2071,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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". The host name: [#!variable!target!#] does not resolve to an IP address. @@ -3096,7 +3097,7 @@ 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 likely that this machine will be able to run any servers until this is fixed. + [ 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. @@ -3826,7 +3827,7 @@ We will sleep a bit and try again. Anvil! ストライカ スカンコア - Alteeve's Niche! Inc., トロント、オンタリオ、カナダ]]> + Alteeve's Niche! Inc., トロント、オンタリオ、カナダ]]> diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 8b1aa0b0..f4d4e6d3 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -276,7 +276,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, 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}, From 3811b9b2da715845d8aa5a45168bd72abd462aa6 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 4 Jan 2022 21:02:24 -0500 Subject: [PATCH 21/37] Minor update to make the fence device name marked as a mandatory field. Signed-off-by: Digimer --- cgi-bin/striker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cgi-bin/striker b/cgi-bin/striker index d7f32cb5..12e531bc 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -4798,7 +4798,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'} = ""; From 652f87ec74eed5f3be2289972953bd533b5d084a Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 12 Jan 2022 23:27:44 -0500 Subject: [PATCH 22/37] * Updated scan-network to also clean up the media type. * Updated anvil-daemon to check for files in /mnt/shared/incoming on striker dashboards and add them to the media library if needed. Signed-off-by: Digimer --- notes | 21 ++++--- scancore-agents/scan-network/scan-network | 7 +++ tools/anvil-daemon | 74 +++++++++++++++++++++++ 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/notes b/notes index 81134638..f4e94ab5 100644 --- a/notes +++ b/notes @@ -744,6 +744,8 @@ mediawiki on EL8 install notes (starting from a minimal install); dnf module reset php dnf module enable php:7.4 + +# PgSQL 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 @@ -792,16 +794,6 @@ 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 @@ -836,6 +828,15 @@ 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 + ==== Dell S4128T-ON Configuration diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 71fc5b73..7267fd8e 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; } } diff --git a/tools/anvil-daemon b/tools/anvil-daemon index f4d4e6d3..72ac9d04 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -508,6 +508,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. @@ -695,6 +698,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. From 0a9f81d852b756abd7fa08401a2b9397088c122d Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 13 Jan 2022 20:00:37 -0500 Subject: [PATCH 23/37] * Created the new striker-db-report that shows how many records are in each database table, and if passed a table name, report how many times each record has been recorded in the history schema. Signed-off-by: Digimer --- share/words.xml | 3 + tools/striker-db-report | 381 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100755 tools/striker-db-report diff --git a/share/words.xml b/share/words.xml index ad92ad88..bec84e10 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2435,6 +2435,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! @@ -3098,6 +3100,7 @@ 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. diff --git a/tools/striker-db-report b/tools/striker-db-report new file mode 100755 index 00000000..ace40df5 --- /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 => 3, 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); +} + From 796814531e42ef2c7a6cfbeaca85a87fe86688cc Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 13 Jan 2022 21:07:25 -0500 Subject: [PATCH 24/37] Fixed a bug in Alert->check_condition_age() where, when the 'clear' parameter was set and the value was already 'clear', it would flip to 'set' erroniously. Signed-off-by: Digimer --- Anvil/Tools/Alert.pm | 5 +++-- scancore-agents/scan-network/scan-network | 8 +++++--- tools/striker-db-report | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) 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/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 7267fd8e..78c5a2f2 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -3457,9 +3457,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/tools/striker-db-report b/tools/striker-db-report index ace40df5..b738c468 100755 --- a/tools/striker-db-report +++ b/tools/striker-db-report @@ -233,7 +233,7 @@ WHERE { foreach my $query (@{$queries}) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); + $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 => { From 032f20a267001793a5a368f5de08d6a54886372e Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 13 Jan 2022 22:49:31 -0500 Subject: [PATCH 25/37] * Fixed a bug in Database->_age_out_data() where, when all records in the history schema would be purged, the most recent record would not be preserved. The result is that nothing was purged, allow tables to grow dramatically. The 'variables' table was also added to this age-out list. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 4fa02d39..d962a618 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -16677,10 +16677,11 @@ 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 + # 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"; # scan_apc_pdu $to_clean->{table}{scan_apc_pdus}{child_table}{scan_apc_pdu_phases}{uuid_column} = "scan_apc_pdu_phase_uuid"; @@ -16760,7 +16761,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."';"; @@ -16781,16 +16782,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; } } } From e8dcb8b24c348978dc6d60553d146a71b58f9ff7 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 17 Jan 2022 11:41:51 -0500 Subject: [PATCH 26/37] Fixed a bug in System->configure_ipmi() where it would fail to find the IPMI BMC admin username in some cases. Signed-off-by: Digimer --- Anvil/Tools/System.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 23004517..e9795d8b 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -2075,6 +2075,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 +2119,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 +2140,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. From 2c76103a96b7d195c91909b5ef17535fefaf2ba2 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 17 Jan 2022 17:54:46 -0500 Subject: [PATCH 27/37] Fixed a bug where, if the host IPMI BMC wouldn't allow spaces in the password and the user had a space, IPMI would never configure or get used as a fence method. Signed-off-by: Digimer --- Anvil/Tools/System.pm | 17 +++++++++++++++++ scancore-agents/scan-cluster/scan-cluster | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index e9795d8b..d9258c55 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -1770,6 +1770,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 = ""; @@ -2229,6 +2239,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 }}); 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)) From 892a47588103c5d7eee2981c3891fce5b8edff81 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 18 Jan 2022 02:38:50 -0500 Subject: [PATCH 28/37] * Fixed a bug in Convert->format_mmddyy_to_yymmdd() where being passed '--' didn't return the same. * Fixed a divide-by-zero bug in anvil-boot-server when no servers exist yet. * Fixed a bug in anvil-daemon where the local databsae engine was being started when it shouldn't. Signed-off-by: Digimer --- Anvil/Tools/Convert.pm | 7 ++++++- Anvil/Tools/Database.pm | 11 ++++++++++ share/words.xml | 2 ++ tools/anvil-boot-server | 16 ++++++++------ tools/anvil-check-memory | 6 +++--- tools/anvil-daemon | 13 ++++++++---- tools/anvil-safe-start | 45 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 86 insertions(+), 14 deletions(-) diff --git a/Anvil/Tools/Convert.pm b/Anvil/Tools/Convert.pm index 28c50483..dc1f3538 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 '--' which is not strictly an error, so we'll return it back. + if ($date eq "--") + { + 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/Database.pm b/Anvil/Tools/Database.pm index d962a618..69cc241a 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -952,9 +952,15 @@ sub configure_pgsql } # Start or restart the daemon? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, 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 => 1, list => { initialized => $initialized }}); if ($initialized) { # Start the daemon. @@ -991,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 => 1, 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. diff --git a/share/words.xml b/share/words.xml index bec84e10..9ab7d7d2 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2072,6 +2072,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: [ 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. The host name: [#!variable!target!#] does not resolve to an IP address. @@ -3101,6 +3102,7 @@ We will sleep a bit and try again. [ 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. 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 72ac9d04..e3f75f0f 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1256,17 +1256,22 @@ sub prep_database $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); if ($host_type eq "striker") { + $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 ($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 => { + 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 => , source => $THIS_FILE, line => __LINE__ }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_output => $database_output, return_code => $return_code, }}); } - else + elsif (not $anvil->data->{sys}{database}{connections}) { # Start the daemon locally, if needed. my $running = $anvil->System->check_daemon({daemon => "postgresql"}); 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"; From 6229a0f6b67d04d925227c1d09e9282577a44c46 Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 20 Jan 2022 10:26:54 -0500 Subject: [PATCH 29/37] Added '#!no_value!#' to be handled properly by Convert->format_mmddyy_to_yymmdd. Added pciutils to the list of anvil-core requirements. Signed-off-by: Digimer --- Anvil/Tools/Convert.pm | 4 ++-- Anvil/Tools/Database.pm | 10 +++++----- anvil.spec.in | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Anvil/Tools/Convert.pm b/Anvil/Tools/Convert.pm index dc1f3538..e73d0150 100644 --- a/Anvil/Tools/Convert.pm +++ b/Anvil/Tools/Convert.pm @@ -848,8 +848,8 @@ sub format_mmddyy_to_yymmdd date => $date, }}); - # Sometimes we're passed '--' which is not strictly an error, so we'll return it back. - if ($date eq "--") + # 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); } diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 69cc241a..f0013bd2 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -952,7 +952,7 @@ sub configure_pgsql } # Start or restart the daemon? - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + $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, @@ -960,12 +960,12 @@ sub configure_pgsql if (not $running) { # Did we initialize? - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { initialized => $initialized }}); + $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. @@ -983,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. @@ -997,7 +997,7 @@ 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 => 1, list => { + $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, diff --git a/anvil.spec.in b/anvil.spec.in index bdf7b6ad..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 From e37f48770493c3b01df78bda06bbeee699b65fee Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 20 Jan 2022 14:13:27 -0500 Subject: [PATCH 30/37] Fixed a bug in System->check_ssh_keys where the 'admin' user's RSA keys were owned by root. Signed-off-by: Digimer --- Anvil/Tools/System.pm | 19 +++++++++++++++++++ share/words.xml | 1 + tools/anvil-daemon | 6 +++--- tools/anvil-join-anvil | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index d9258c55..81d14cc0 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -728,10 +728,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 { diff --git a/share/words.xml b/share/words.xml index 9ab7d7d2..a0e55e0c 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2073,6 +2073,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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!#]. The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index e3f75f0f..6a8be268 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -441,7 +441,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}); @@ -837,7 +837,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); @@ -1265,7 +1265,7 @@ sub 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 => , source => $THIS_FILE, line => __LINE__ }); + 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, 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"}); From a633ab7f63f5c4c4af707135b2a60dec7efd9416 Mon Sep 17 00:00:00 2001 From: Digimer Date: Fri, 21 Jan 2022 14:27:58 -0500 Subject: [PATCH 31/37] Added a periodic check to ensure all users can ping. This fixes a bug where a local striker dashboard whose DB was stopped wouldn't work. Signed-off-by: Digimer --- Anvil/Tools.pm | 1 + Anvil/Tools/Network.pm | 18 +++++++++++++++--- cgi-bin/striker | 2 +- share/words.xml | 1 + tools/anvil-daemon | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 27f7540b..bd24705d 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1246,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/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/cgi-bin/striker b/cgi-bin/striker index 12e531bc..a462459e 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -65,7 +65,7 @@ if (not -e $anvil->data->{path}{data}{host_uuid}) print_and_exit($anvil); } -$anvil->Database->connect({debug => 3}); +$anvil->Database->connect({debug => 2}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { diff --git a/share/words.xml b/share/words.xml index a0e55e0c..f06540d2 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2074,6 +2074,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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 host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 6a8be268..c514611e 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -413,6 +413,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); } From 831abd19817f334534c95e9310bbfc046bc3bf6d Mon Sep 17 00:00:00 2001 From: Digimer Date: Fri, 21 Jan 2022 16:57:10 -0500 Subject: [PATCH 32/37] Updated Striker to allow the DR host to not have an IP assisned. Signed-off-by: Digimer --- Anvil/Tools/System.pm | 2 +- cgi-bin/striker | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 81d14cc0..e49e9db4 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -1887,7 +1887,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); } diff --git a/cgi-bin/striker b/cgi-bin/striker index a462459e..b3b77129 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -65,7 +65,7 @@ if (not -e $anvil->data->{path}{data}{host_uuid}) print_and_exit($anvil); } -$anvil->Database->connect({debug => 2}); +$anvil->Database->connect({debug => 3}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { @@ -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!#"; } From a886653af11ae2b450aa8c2c6e088fdc68ce5c7e Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 1 Feb 2022 20:15:01 -0500 Subject: [PATCH 33/37] * Updated scan-network to purge duplicate bridges and bonds. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 9 +- notes | 26 ++ scancore-agents/scan-network/scan-network | 327 +++++++++++++++++++++- share/words.xml | 2 + 4 files changed, 347 insertions(+), 17 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index f0013bd2..f627a5fc 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -16689,10 +16689,11 @@ sub _age_out_data my $to_clean = {}; # 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}{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"; diff --git a/notes b/notes index f4e94ab5..3d21efb0 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." diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 78c5a2f2..77433a89 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -798,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.bondss WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM bondss 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.bondss WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; + push @{$queries}, "DELETE FROM bondss 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 @@ -817,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}) @@ -845,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}}) @@ -867,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 => { @@ -887,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. @@ -901,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--; @@ -1004,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--; @@ -1014,6 +1314,7 @@ ORDER BY } } + return(0); } diff --git a/share/words.xml b/share/words.xml index f06540d2..e7c122e3 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2075,6 +2075,8 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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). The host name: [#!variable!target!#] does not resolve to an IP address. From d70b9a49563bcd942083789e0f2678f2f5c6d4e7 Mon Sep 17 00:00:00 2001 From: Digimer Date: Sat, 5 Feb 2022 22:08:06 -0500 Subject: [PATCH 34/37] Updated scancore and anvil-daemon to check their RAM use at the end of each loop and, if it's using more than 1 GiB of RAM, it sends an alert and exits. * Updated Database->resync_databases() to never run on non-striker machines. On Strikers, before a resync, _age_out_data() is called to clear old data in long-off databases. * Created System->check_memory() that is loosely based on anvil-check-memory, but checks to see if it's being controlled by a systemctl started daemon and, if so, reads the RAM in use from it's status output. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 13 ++++ Anvil/Tools/ScanCore.pm | 2 +- Anvil/Tools/System.pm | 153 ++++++++++++++++++++++++++++++++++++++++ share/words.xml | 3 + tools/anvil-daemon | 40 ++++++++++- tools/scancore | 38 ++++++++++ 6 files changed, 247 insertions(+), 2 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index f627a5fc..a258e609 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15691,6 +15691,16 @@ 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 }}); @@ -15700,6 +15710,9 @@ sub resync_databases 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 diff --git a/Anvil/Tools/ScanCore.pm b/Anvil/Tools/ScanCore.pm index 7e2d6600..1fe867b4 100644 --- a/Anvil/Tools/ScanCore.pm +++ b/Anvil/Tools/ScanCore.pm @@ -199,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}); } diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index e49e9db4..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; diff --git a/share/words.xml b/share/words.xml index e7c122e3..be3625b5 100644 --- a/share/words.xml +++ b/share/words.xml @@ -502,6 +502,7 @@ 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. @@ -2077,6 +2078,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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. The host name: [#!variable!target!#] does not resolve to an IP address. @@ -3107,6 +3109,7 @@ We will sleep a bit and try 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. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index c514611e..c163a8a4 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -246,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); @@ -258,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 { @@ -1291,7 +1329,7 @@ sub prep_database { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { prep_database => $prep_database, - "sys}{database}{connections" => $anvil->data->{sys}{database}{connections}, + "sys::database::connections" => $anvil->data->{sys}{database}{connections}, }}); if ($prep_database) { 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 { From f77f486775b0f328199002fce8f40b27874f4ec4 Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 9 Feb 2022 15:52:21 -0500 Subject: [PATCH 35/37] Fixed a typo in scan-network Fixed a missing 'next' to prevent the first DB from disconnecting when down'ing excess DBs. Signed-off-by: Digimer --- scancore-agents/scan-network/scan-network | 8 ++++---- tools/anvil-daemon | 3 +++ tools/striker-auto-initialize-all | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 77433a89..249db986 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -888,8 +888,8 @@ ORDER BY 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.bondss WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; - push @{$queries}, "DELETE FROM bondss WHERE bond_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).";"; @@ -920,8 +920,8 @@ ORDER BY 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.bondss WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; - push @{$queries}, "DELETE FROM bondss WHERE bond_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).";"; diff --git a/tools/anvil-daemon b/tools/anvil-daemon index c163a8a4..a3be7169 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -609,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) { 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' }}); From ec3b3d2ac9bc6ea834cc7df5448a9c4e2460d66f Mon Sep 17 00:00:00 2001 From: Digimer Date: Sun, 13 Feb 2022 19:55:24 -0500 Subject: [PATCH 36/37] Fixed a bug in Database->_age_out_data() where checking if a table existed was hard coded to one table. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 2 +- notes | 52 ++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index a258e609..387b91bc 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -16739,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]; diff --git a/notes b/notes index 3d21efb0..73d9f1c4 100644 --- a/notes +++ b/notes @@ -771,10 +771,10 @@ mediawiki on EL8 install notes (starting from a minimal install); dnf module reset php dnf module enable php:7.4 -# PgSQL +# 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 @@ -783,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 @@ -796,25 +798,25 @@ 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 @@ -863,6 +865,38 @@ 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 From dc989f0950073cc73fa272e1df983d33b3f1dd0d Mon Sep 17 00:00:00 2001 From: Digimer Date: Wed, 16 Feb 2022 21:55:33 -0500 Subject: [PATCH 37/37] Added more logging to track when and how reboots happen in systems. Signed-off-by: Digimer --- cgi-bin/striker | 3 +++ notes | 27 +++++++++++++++++++++++++++ share/words.xml | 10 ++++++++-- tools/anvil-manage-power | 3 +++ tools/anvil-safe-stop | 2 ++ tools/anvil-update-system | 3 +-- 6 files changed, 44 insertions(+), 4 deletions(-) diff --git a/cgi-bin/striker b/cgi-bin/striker index b3b77129..807767b2 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -6451,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; @@ -6458,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/notes b/notes index 73d9f1c4..85a9cc5a 100644 --- a/notes +++ b/notes @@ -1291,6 +1291,33 @@ rs-striker03(config-if)#switchport access vlan 100 rs-striker03(config-if)#no shutdown rs-striker03(config-if)#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 diff --git a/share/words.xml b/share/words.xml index be3625b5..dcf027fa 100644 --- a/share/words.xml +++ b/share/words.xml @@ -1523,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. @@ -2079,6 +2079,12 @@ The file: [#!variable!file!#] needs to be updated. The difference is: 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. 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-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-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 }}); }