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);