From f0ca48ccd9b8f0974d48fb4f4ccd2b9608c00304 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Wed, 6 Sep 2023 13:40:30 -0400 Subject: [PATCH 1/7] Add support for non-leapp upgrades Fix #302 Add --no-leapp option to pause the process using a touch file which should be removed once the distro is manually upgraded to continue the cpanel elevation process. --- docs-website-src/content/_index.md | 22 +++ elevate-cpanel | 213 ++++++++++++++++++++++++---- lib/Elevate/Blockers/Base.pm | 1 + lib/Elevate/Blockers/BootKernel.pm | 3 + lib/Elevate/Blockers/Grub2.pm | 3 + lib/Elevate/Blockers/IsContainer.pm | 6 +- lib/Elevate/Blockers/NICs.pm | 1 + lib/Elevate/Components/Base.pm | 1 + lib/Elevate/Usage.pm | 1 + script/elevate-cpanel.PL | 197 +++++++++++++++++++++---- t/blocker-IsContainer.t | 2 +- t/leapp_upgrade.t | 6 + 12 files changed, 395 insertions(+), 61 deletions(-) diff --git a/docs-website-src/content/_index.md b/docs-website-src/content/_index.md index bb7b2c8e..29d4ac7f 100644 --- a/docs-website-src/content/_index.md +++ b/docs-website-src/content/_index.md @@ -218,6 +218,28 @@ Remove the `elevate-cpanel` service used during the upgrade process. A final reboot is performed at the end of this stage. +## Advanced Options + +### Using an alternative tool to upgrade your distro + +By default, the elevate script runs the [leapp process](https://almalinux.org/elevate/) +to upgrade you from 7 to 8. `Leapp` may not be compatible with your system. + +Using the `--no-leapp` option gives you a way to do the actual distro upgrade in your own way. +This, for instance, can be used to allow `Virtuozzo` systems to upgrade cPanel systems, which are not supported by `Leapp`. + +A `--no-leapp` upgrade would look like: + +1. User runs `/scripts/elevate-cpanel --start --no-leapp` which starts the upgrade process. +2. `elevate-cpanel` does all preparatory steps to upgrade the system prior to the distro upgrade. +3. Elevate will then create the file `/waiting_for_distro_upgrade` to indicate that the operating system is ready for an upgrade. + * This is when you would use your distro upgrade tool. + * When you have completed upgrading your system to 8, simply remove `/waiting_for_distro_upgrade` and reboot the system into normal multi-user mode. +5. Elevate will resume upon reboot and complete the upgrade just like it would have without `--no-leapp` + +The regular workflow is the following +NOTE: `--no-leapp` is not required for helper commands like `--continue` or `--status` + ## FAQ ### How to check the current status? diff --git a/elevate-cpanel b/elevate-cpanel index e873819e..978dc4d2 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -119,6 +119,7 @@ BEGIN { # Suppress load of all of these at earliest point. update_stage_file upgrade_to_rocky upgrade_to_pretty_name + should_run_leapp ssystem ssystem_capture_output }; @@ -392,6 +393,9 @@ BEGIN { # Suppress load of all of these at earliest point. use Try::Tiny; sub check ($self) { + + return 1 unless $self->should_run_leapp; # skip when --no-leapp is provided + my $ok = 0; try { my ( $running_version, $boot_version ) = Cpanel::Kernel::Status::reboot_status()->@{ 'running_version', 'boot_version' }; @@ -928,6 +932,9 @@ EOS sub GRUB2_PREFIX_RHEL { return '/boot/grub2' } sub check ($self) { + + return 1 unless $self->should_run_leapp; # skip when --no-leapp is provided + my $ok = 1; $ok = 0 unless $self->_blocker_grub2_workaround; $ok = 0 unless $self->_blocker_blscfg; @@ -1083,9 +1090,13 @@ EOS INIT { Log::Log4perl->import(qw{:easy}); } sub check ($self) { # $self is a cpev object here + + return 0 unless $self->should_run_leapp; + if ( _is_container_envtype() ) { - return $self->has_blocker("cPanel thinks that this is a container-like environment, which this script cannot support at this time."); + return $self->has_blocker("cPanel thinks that this is a container-like environment, consider running leapp manually using the --no-leapp option."); } + return 0; } @@ -1179,6 +1190,7 @@ EOS use constant SBIN_IP => q[/sbin/ip]; sub check ($self) { + return 1 unless $self->should_run_leapp; # skip when --no-leapp is provided return $self->_blocker_bad_nics_naming; } @@ -1979,6 +1991,7 @@ EOS upgrade_to_rocky upgrade_to_pretty_name tmp_dir + should_run_leapp ssystem ssystem_and_die ssystem_capture_output @@ -4450,6 +4463,7 @@ EOS skip-cpanel-version-check skip-elevate-version-check update version upgrade-to=s + no-leapp ); } @@ -4579,6 +4593,10 @@ Helps to upgrade CentOS 7 cPanel servers to AlmaLinux 8 or Rocky Linux 8. --skip-cpanel-version-check Skip the check for whether cPanel is up to date. This option is intended only for testing! + --no-leapp Do not try to run leapp, and pause instead. + Once leapp has been run you should remove the file + /waiting_for_distro_upgrade + --help Display this documentation. =head1 COMMON USAGE @@ -4643,6 +4661,40 @@ the update process by running: =back +=head2 Advanced Options + +=head3 Using an alternative tool to upgrade your distro + +By default, the elevate script runs the [leapp process](https://almalinux.org/elevate/) +to upgrade you from 7 to 8. `Leapp` may not be compatible with your system. + +Using the `--no-leapp` option gives you a way to do the actual distro upgrade in your own way. +This, for instance, can be used to allow `Virtuozzo` systems to upgrade cPanel systems, which are not supported by `Leapp`. + +A `--no-leapp` upgrade would look like: + +=over + +=item 1. User runs `/scripts/elevate-cpanel --start --no-leapp` which starts the upgrade process. + +=item 2. `elevate-cpanel` does all preparatory steps to upgrade the system prior to the distro upgrade. + +=item 3. Elevate will then create the file `/waiting_for_distro_upgrade` to indicate that the operating system is ready for an upgrade. + +=over + +=item * This is when you would use your distro upgrade tool. + +=item * When you have completed upgrading your system to 8, simply remove `/waiting_for_distro_upgrade` and reboot the system into normal multi-user mode. + +=back + +=item 4. Elevate will resume upon reboot and complete the upgrade just like it would have without `--no-leapp` + +=back + +NOTE: `--no-leapp` is not required for helper commands like `--continue` or `--status` + =head1 WARNINGS The elevation process from CentOS 7 to AlmaLinux 8 or Rocky Linux 8 distribution @@ -4785,12 +4837,15 @@ use constant NOC_RECOMMENDATIONS_TOUCH_FILE => q[/var/cpanel/elevate-noc-recomme # XXX TODO verify that imunify reponames are in fact correct. # As of now they are straight up guesses. -use constant REBOOT_NEEDED => 4242; # just one unique id +use constant ACTION_REBOOT_NEEDED => 4242; # just one unique id +use constant ACTION_PAUSE_REQUESTED => 4243; # prefer string over integers so we can read the configuration file (no need for bitmask) use constant UPGRADE_TO_ALMALINUX => q[AlmaLinux]; use constant UPGRADE_TO_ROCKY => q[Rocky]; +use constant PAUSE_ELEVATE_TOUCHFILE => q[/waiting_for_distro_upgrade]; + use Simple::Accessor qw{ service script @@ -4889,7 +4944,7 @@ sub run ( $pkg, @args ) { return $self->run_service_and_notify(); } - monitor_upgrade(); + $self->monitor_upgrade(); return 0; } @@ -4968,18 +5023,18 @@ sub upgrade_to_pretty_name ($self) { # used by output messages return q[AlmaLinux 8]; } -sub monitor_upgrade { +sub monitor_upgrade ($self) { my $stage = get_stage(); my $tail_msg = q[Running: tail -f ] . Elevate::Constants::LOG_FILE; - my $status = read_stage_file( 'status', 'unknown' ); + my $status = $self->get_current_status(); if ( $status eq 'success' ) { Elevate::Logger::INFO_nolog("# Upgrade was successful. Showing the last lines of the update log."); } - elsif ( $status eq 'running' ) { - Elevate::Logger::INFO_nolog("# Monitoring existing upgrade (stage=$stage) ; $tail_msg"); + elsif ( $status eq 'running' || $status eq 'paused' ) { + Elevate::Logger::INFO_nolog("# Monitoring existing $status upgrade (stage=$stage) ; $tail_msg"); } elsif ( $status eq 'failed' ) { Elevate::Logger::ERROR_nolog("# Upgrade process failed at stage=$stage ; $tail_msg"); @@ -5025,6 +5080,19 @@ sub start ($self) { update_stage_file( { manual_reboots => 1 } ); } + if ( $self->getopt('no-leapp') ) { + my $touchfile = PAUSE_ELEVATE_TOUCHFILE; + WARN( <<~"EOS"); + 'leapp' checks and run are disabled. + Please wait for the file '$touchfile' to be created. + At that stage the elevation process is paused then you can upgrade from 7 to 8 on your own. + + Once the system has been successfully upgraded from 7 to 8 you can then remove that file + to let the elevation process continue and update cPanel for the updated distribution. + EOS + update_stage_file( { no_leapp => 1 } ); + } + # prefer over running step1: so status and notifications are enabled return $self->run_service_and_notify(); } @@ -5071,7 +5139,7 @@ EOS sub continue_elevation ($self) { - my $status = read_stage_file( 'status', 'unknown' ); + my $status = $self->get_current_status(); if ( $status eq 'success' ) { Elevate::Logger::INFO_nolog("Elevate process was successful. No process to continue."); return; @@ -5132,14 +5200,19 @@ sub run_service_and_notify ($self) { # FIXME: move to Elevate::Service - need my $stage = get_stage(); - update_stage_file( { status => q[running] } ) if $stage >= 2; + if ( $stage >= 2 ) { + my $status = $self->get_current_status(); + update_stage_file( { status => q[running] } ) if $status ne 'paused'; + } - my $out; + my $action_todo; my $ok = eval { - $out = $self->_run_service(); + $action_todo = $self->_run_service(); 1; }; + $action_todo //= 0; + if ($ok) { # only notify a success when reaching the last stage @@ -5148,7 +5221,12 @@ sub run_service_and_notify ($self) { # FIXME: move to Elevate::Service - need $self->_notify_success(); } - $self->reboot() if $out == REBOOT_NEEDED; + if ( $action_todo == ACTION_PAUSE_REQUESTED ) { + update_stage_file( { status => q[paused] } ); + } + elsif ( $action_todo == ACTION_REBOOT_NEEDED ) { + $self->reboot(); + } } else { my $error = $@ // q[Unknown error]; @@ -5159,7 +5237,7 @@ sub run_service_and_notify ($self) { # FIXME: move to Elevate::Service - need LOGDIE($error); } - return $out; + return $action_todo; } sub check_and_create_pidfile ($self) { @@ -5180,13 +5258,19 @@ sub check_status ($self) { return; } - my $status = read_stage_file( 'status', 'unknown' ); + my $status = $self->get_current_status(); + + my $max_stage = VALID_STAGES; if ( $status eq 'success' ) { say q[success]; } + elsif ( $status eq 'paused' ) { + my $paused_file = PAUSE_ELEVATE_TOUCHFILE; + say qq[Paused at stage $stage / $max_stage please read more from $paused_file]; + } elsif ( $status eq 'running' ) { - say qq[Running stage $stage / ] . VALID_STAGES; + say qq[Running stage $stage / $max_stage]; } elsif ( $status eq 'failed' ) { say qq[Failed during stage $stage]; @@ -5255,6 +5339,8 @@ sub _run_service ($self) { print_box( "Starting stage $stage of " . VALID_STAGES ) if $stage > 1; + $self->_wait_on_pause(); # handle pause when requested + # sanity check if ( Cpanel::OS::major() == 8 && 2 <= $stage && $stage <= 3 ) { WARN( "Detected " . Cpanel::OS::pretty_distro() . " while running stage $stage: swtiching to stage 4" ); @@ -5272,6 +5358,30 @@ sub _run_service ($self) { } +sub _wait_on_pause ($self) { + + my $pause_file = PAUSE_ELEVATE_TOUCHFILE; + return unless -e $pause_file; + + update_stage_file( { status => q[paused] } ); + + WARN( <<~"EOS" ); + The elevation process is currently paused by $pause_file + Please read the file for more details. + EOS + + while ( -e $pause_file ) { + sleep 5; + } + + update_stage_file( { status => q[running] } ); + + my $stage = get_stage(); + INFO("The pause file was removed. Continuing elevate process to stage $stage."); + + return 1; +} + sub present_noc_recommendations () { local $!; @@ -5378,7 +5488,7 @@ sub run_stage_2 ($self) { $self->run_component_once( 'KernelCare' => 'pre_leapp' ); $self->run_component_once( 'Grub2' => 'pre_leapp' ); - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; } =head2 run_stage_3 @@ -5401,7 +5511,7 @@ sub run_stage_3 ($self) { prep_for_leapp => sub { $self->run_once( - install_pkgs => sub { + install_leapp => sub { unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { # provides leapp-data-almalinux & leapp-data-rocky @@ -5413,13 +5523,14 @@ sub run_stage_3 ($self) { unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leap_data_pkg) ) { $self->ssystem_and_die( qw{/usr/bin/yum install -y leapp-upgrade }, $leap_data_pkg ); } + if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { $self->ssystem_and_die(qw{/usr/bin/yum -y remove kernel-devel}); } return; } - ); + ) if $self->should_run_leapp(); $self->run_once( rmod_ln => sub { @@ -5431,7 +5542,7 @@ sub run_stage_3 ($self) { ); # We have to do this before removing the rpms. - $self->run_once('pre_leapp_update_backup_and_cleanup'); + $self->run_once('run_final_components_pre_leapp'); # remove all arch cpanel packages # This also potentially removes @@ -5445,25 +5556,45 @@ sub run_stage_3 ($self) { $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); } - # Avoids having to do preupgrade. - setup_answer_file(); - return; } ); + if ( !$self->should_run_leapp() ) { + return $self->_request_to_upgrade_distro_manually(); + } + $self->_do_leapp_upgrade(); - WARN(<<'EOS'); -Rebooting for distro upgrade. This will take over 10 minutes to run. -Do not interrupt power during this event or you will corrupt your system. -EOS + WARN(<<~'EOS'); + Rebooting for distro upgrade. This will take over 10 minutes to run. + Do not interrupt power during this event or you will corrupt your system. + EOS - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; # This takes a while because on reboot it's installing 800 packages } +sub _request_to_upgrade_distro_manually ($self) { + + my $pause_file = PAUSE_ELEVATE_TOUCHFILE; + + my $txt = <<"EOS"; +The cPanel elevation process is currently paused. +You should upgrade the distribution manually. + +After a successful upgrade, you can then remove the file + rm -f $pause_file +to let the elevation process continue and update cPanel for the updated distribution. +EOS + + WARN($txt); + File::Slurper::write_text( $pause_file, $txt ); + + return ACTION_PAUSE_REQUESTED; +} + =head2 run_stage_4 At this stage we should now run Alamalinux 8. @@ -5571,7 +5702,7 @@ sub run_stage_4 ($self) { } ); - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; } =head2 run_stage_5 @@ -5603,7 +5734,7 @@ sub run_stage_5 ($self) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); print_box("Great SUCCESS! Your upgrade to $pretty_distro_name is complete."); - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; } sub _bq_now () { @@ -5837,6 +5968,10 @@ sub disable_all_cpanel_services ($self) { sub _do_leapp_upgrade ($self) { + return unless $self->should_run_leapp(); + + $self->run_once('setup_answer_file'); + INFO("Running leapp upgrade"); my $ok = eval { @@ -5902,8 +6037,9 @@ EOS } # remove and store -sub pre_leapp_update_backup_and_cleanup ($self) { +sub run_final_components_pre_leapp ($self) { + # order matters $self->run_component_once( 'Imunify' => 'pre_leapp' ); $self->run_component_once( 'EA4' => 'pre_leapp' ); $self->run_component_once( 'PECL' => 'pre_leapp' ); @@ -6066,6 +6202,12 @@ sub post_upgrade_check ($self) { return 0; } +=pod + > cat /var/log/leapp/answerfile + [remove_pam_pkcs11_module_check] + confirm=True +=cut + sub setup_answer_file { my $leapp_dir = '/var/log/leapp'; mkdir $leapp_dir unless -d $leapp_dir; @@ -6095,6 +6237,17 @@ sub setup_answer_file { # TODO: We're going to need to store reboot time so we know if the last reboot has happened when we re-run the script. +sub should_run_leapp ($self) { + + # we store the no_leapp option, but prefer using a positive check instead + my $no_leapp = read_stage_file( 'no_leapp', 0 ); + return !$no_leapp; +} + +sub get_current_status ($self) { + return read_stage_file( 'status', 'unknown' ); +} + sub read_stage_file ( $k = undef, $default = {} ) { my $stage_info = _read_stage_file() // {}; diff --git a/lib/Elevate/Blockers/Base.pm b/lib/Elevate/Blockers/Base.pm index 7c112459..047962ef 100644 --- a/lib/Elevate/Blockers/Base.pm +++ b/lib/Elevate/Blockers/Base.pm @@ -43,6 +43,7 @@ BEGIN { update_stage_file upgrade_to_rocky upgrade_to_pretty_name + should_run_leapp ssystem ssystem_capture_output }; diff --git a/lib/Elevate/Blockers/BootKernel.pm b/lib/Elevate/Blockers/BootKernel.pm index 38df0cc8..d189c97a 100644 --- a/lib/Elevate/Blockers/BootKernel.pm +++ b/lib/Elevate/Blockers/BootKernel.pm @@ -27,6 +27,9 @@ use Cpanel::JSON (); use Try::Tiny; sub check ($self) { + + return 1 unless $self->should_run_leapp; # skip when --no-leapp is provided + my $ok = 0; try { my ( $running_version, $boot_version ) = Cpanel::Kernel::Status::reboot_status()->@{ 'running_version', 'boot_version' }; diff --git a/lib/Elevate/Blockers/Grub2.pm b/lib/Elevate/Blockers/Grub2.pm index 7302ecaf..06632566 100644 --- a/lib/Elevate/Blockers/Grub2.pm +++ b/lib/Elevate/Blockers/Grub2.pm @@ -30,6 +30,9 @@ sub GRUB2_PREFIX_DEBIAN { return '/boot/grub' } sub GRUB2_PREFIX_RHEL { return '/boot/grub2' } sub check ($self) { + + return 1 unless $self->should_run_leapp; # skip when --no-leapp is provided + my $ok = 1; $ok = 0 unless $self->_blocker_grub2_workaround; $ok = 0 unless $self->_blocker_blscfg; diff --git a/lib/Elevate/Blockers/IsContainer.pm b/lib/Elevate/Blockers/IsContainer.pm index 300c607d..35fe7d4e 100644 --- a/lib/Elevate/Blockers/IsContainer.pm +++ b/lib/Elevate/Blockers/IsContainer.pm @@ -16,9 +16,13 @@ use parent qw{Elevate::Blockers::Base}; use Log::Log4perl qw(:easy); sub check ($self) { # $self is a cpev object here + + return 0 unless $self->should_run_leapp; + if ( _is_container_envtype() ) { - return $self->has_blocker("cPanel thinks that this is a container-like environment, which this script cannot support at this time."); + return $self->has_blocker("cPanel thinks that this is a container-like environment, consider running leapp manually using the --no-leapp option."); } + return 0; } diff --git a/lib/Elevate/Blockers/NICs.pm b/lib/Elevate/Blockers/NICs.pm index ef5bc5ea..8d7ce7e8 100644 --- a/lib/Elevate/Blockers/NICs.pm +++ b/lib/Elevate/Blockers/NICs.pm @@ -22,6 +22,7 @@ use Log::Log4perl qw(:easy); use constant SBIN_IP => q[/sbin/ip]; sub check ($self) { + return 1 unless $self->should_run_leapp; # skip when --no-leapp is provided return $self->_blocker_bad_nics_naming; } diff --git a/lib/Elevate/Components/Base.pm b/lib/Elevate/Components/Base.pm index 50153f18..75abba97 100644 --- a/lib/Elevate/Components/Base.pm +++ b/lib/Elevate/Components/Base.pm @@ -30,6 +30,7 @@ BEGIN { upgrade_to_rocky upgrade_to_pretty_name tmp_dir + should_run_leapp ssystem ssystem_and_die ssystem_capture_output diff --git a/lib/Elevate/Usage.pm b/lib/Elevate/Usage.pm index ebef6251..87d35893 100644 --- a/lib/Elevate/Usage.pm +++ b/lib/Elevate/Usage.pm @@ -21,6 +21,7 @@ sub _OPTIONS { skip-cpanel-version-check skip-elevate-version-check update version upgrade-to=s + no-leapp ); } diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index 14aead47..17b5650b 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -58,6 +58,10 @@ Helps to upgrade CentOS 7 cPanel servers to AlmaLinux 8 or Rocky Linux 8. --skip-cpanel-version-check Skip the check for whether cPanel is up to date. This option is intended only for testing! + --no-leapp Do not try to run leapp, and pause instead. + Once leapp has been run you should remove the file + /waiting_for_distro_upgrade + --help Display this documentation. =head1 COMMON USAGE @@ -122,6 +126,40 @@ the update process by running: =back +=head2 Advanced Options + +=head3 Using an alternative tool to upgrade your distro + +By default, the elevate script runs the [leapp process](https://almalinux.org/elevate/) +to upgrade you from 7 to 8. `Leapp` may not be compatible with your system. + +Using the `--no-leapp` option gives you a way to do the actual distro upgrade in your own way. +This, for instance, can be used to allow `Virtuozzo` systems to upgrade cPanel systems, which are not supported by `Leapp`. + +A `--no-leapp` upgrade would look like: + +=over + +=item 1. User runs `/scripts/elevate-cpanel --start --no-leapp` which starts the upgrade process. + +=item 2. `elevate-cpanel` does all preparatory steps to upgrade the system prior to the distro upgrade. + +=item 3. Elevate will then create the file `/waiting_for_distro_upgrade` to indicate that the operating system is ready for an upgrade. + +=over + +=item * This is when you would use your distro upgrade tool. + +=item * When you have completed upgrading your system to 8, simply remove `/waiting_for_distro_upgrade` and reboot the system into normal multi-user mode. + +=back + +=item 4. Elevate will resume upon reboot and complete the upgrade just like it would have without `--no-leapp` + +=back + +NOTE: `--no-leapp` is not required for helper commands like `--continue` or `--status` + =head1 WARNINGS The elevation process from CentOS 7 to AlmaLinux 8 or Rocky Linux 8 distribution @@ -264,12 +302,15 @@ use constant NOC_RECOMMENDATIONS_TOUCH_FILE => q[/var/cpanel/elevate-noc-recomme # XXX TODO verify that imunify reponames are in fact correct. # As of now they are straight up guesses. -use constant REBOOT_NEEDED => 4242; # just one unique id +use constant ACTION_REBOOT_NEEDED => 4242; # just one unique id +use constant ACTION_PAUSE_REQUESTED => 4243; # prefer string over integers so we can read the configuration file (no need for bitmask) use constant UPGRADE_TO_ALMALINUX => q[AlmaLinux]; use constant UPGRADE_TO_ROCKY => q[Rocky]; +use constant PAUSE_ELEVATE_TOUCHFILE => q[/waiting_for_distro_upgrade]; + use Simple::Accessor qw{ service script @@ -368,7 +409,7 @@ sub run ( $pkg, @args ) { return $self->run_service_and_notify(); } - monitor_upgrade(); + $self->monitor_upgrade(); return 0; } @@ -447,18 +488,18 @@ sub upgrade_to_pretty_name ($self) { # used by output messages return q[AlmaLinux 8]; } -sub monitor_upgrade { +sub monitor_upgrade ($self) { my $stage = get_stage(); my $tail_msg = q[Running: tail -f ] . Elevate::Constants::LOG_FILE; - my $status = read_stage_file( 'status', 'unknown' ); + my $status = $self->get_current_status(); if ( $status eq 'success' ) { Elevate::Logger::INFO_nolog("# Upgrade was successful. Showing the last lines of the update log."); } - elsif ( $status eq 'running' ) { - Elevate::Logger::INFO_nolog("# Monitoring existing upgrade (stage=$stage) ; $tail_msg"); + elsif ( $status eq 'running' || $status eq 'paused' ) { + Elevate::Logger::INFO_nolog("# Monitoring existing $status upgrade (stage=$stage) ; $tail_msg"); } elsif ( $status eq 'failed' ) { Elevate::Logger::ERROR_nolog("# Upgrade process failed at stage=$stage ; $tail_msg"); @@ -504,6 +545,19 @@ sub start ($self) { update_stage_file( { manual_reboots => 1 } ); } + if ( $self->getopt('no-leapp') ) { + my $touchfile = PAUSE_ELEVATE_TOUCHFILE; + WARN( <<~"EOS"); + 'leapp' checks and run are disabled. + Please wait for the file '$touchfile' to be created. + At that stage the elevation process is paused then you can upgrade from 7 to 8 on your own. + + Once the system has been successfully upgraded from 7 to 8 you can then remove that file + to let the elevation process continue and update cPanel for the updated distribution. + EOS + update_stage_file( { no_leapp => 1 } ); + } + # prefer over running step1: so status and notifications are enabled return $self->run_service_and_notify(); } @@ -550,7 +604,7 @@ EOS sub continue_elevation ($self) { - my $status = read_stage_file( 'status', 'unknown' ); + my $status = $self->get_current_status(); if ( $status eq 'success' ) { Elevate::Logger::INFO_nolog("Elevate process was successful. No process to continue."); return; @@ -611,14 +665,19 @@ sub run_service_and_notify ($self) { # FIXME: move to Elevate::Service - need my $stage = get_stage(); - update_stage_file( { status => q[running] } ) if $stage >= 2; + if ( $stage >= 2 ) { + my $status = $self->get_current_status(); + update_stage_file( { status => q[running] } ) if $status ne 'paused'; + } - my $out; + my $action_todo; my $ok = eval { - $out = $self->_run_service(); + $action_todo = $self->_run_service(); 1; }; + $action_todo //= 0; + if ($ok) { # only notify a success when reaching the last stage @@ -627,7 +686,12 @@ sub run_service_and_notify ($self) { # FIXME: move to Elevate::Service - need $self->_notify_success(); } - $self->reboot() if $out == REBOOT_NEEDED; + if ( $action_todo == ACTION_PAUSE_REQUESTED ) { + update_stage_file( { status => q[paused] } ); + } + elsif ( $action_todo == ACTION_REBOOT_NEEDED ) { + $self->reboot(); + } } else { my $error = $@ // q[Unknown error]; @@ -638,7 +702,7 @@ sub run_service_and_notify ($self) { # FIXME: move to Elevate::Service - need LOGDIE($error); } - return $out; + return $action_todo; } sub check_and_create_pidfile ($self) { @@ -659,13 +723,19 @@ sub check_status ($self) { return; } - my $status = read_stage_file( 'status', 'unknown' ); + my $status = $self->get_current_status(); + + my $max_stage = VALID_STAGES; if ( $status eq 'success' ) { say q[success]; } + elsif ( $status eq 'paused' ) { + my $paused_file = PAUSE_ELEVATE_TOUCHFILE; + say qq[Paused at stage $stage / $max_stage please read more from $paused_file]; + } elsif ( $status eq 'running' ) { - say qq[Running stage $stage / ] . VALID_STAGES; + say qq[Running stage $stage / $max_stage]; } elsif ( $status eq 'failed' ) { say qq[Failed during stage $stage]; @@ -734,6 +804,8 @@ sub _run_service ($self) { print_box( "Starting stage $stage of " . VALID_STAGES ) if $stage > 1; + $self->_wait_on_pause(); # handle pause when requested + # sanity check if ( Cpanel::OS::major() == 8 && 2 <= $stage && $stage <= 3 ) { WARN( "Detected " . Cpanel::OS::pretty_distro() . " while running stage $stage: swtiching to stage 4" ); @@ -751,6 +823,30 @@ sub _run_service ($self) { } +sub _wait_on_pause ($self) { + + my $pause_file = PAUSE_ELEVATE_TOUCHFILE; + return unless -e $pause_file; + + update_stage_file( { status => q[paused] } ); + + WARN( <<~"EOS" ); + The elevation process is currently paused by $pause_file + Please read the file for more details. + EOS + + while ( -e $pause_file ) { + sleep 5; + } + + update_stage_file( { status => q[running] } ); + + my $stage = get_stage(); + INFO("The pause file was removed. Continuing elevate process to stage $stage."); + + return 1; +} + sub present_noc_recommendations () { local $!; @@ -857,7 +953,7 @@ sub run_stage_2 ($self) { $self->run_component_once( 'KernelCare' => 'pre_leapp' ); $self->run_component_once( 'Grub2' => 'pre_leapp' ); - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; } =head2 run_stage_3 @@ -880,7 +976,7 @@ sub run_stage_3 ($self) { prep_for_leapp => sub { $self->run_once( - install_pkgs => sub { + install_leapp => sub { unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { # provides leapp-data-almalinux & leapp-data-rocky @@ -892,13 +988,14 @@ sub run_stage_3 ($self) { unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leap_data_pkg) ) { $self->ssystem_and_die( qw{/usr/bin/yum install -y leapp-upgrade }, $leap_data_pkg ); } + if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { $self->ssystem_and_die(qw{/usr/bin/yum -y remove kernel-devel}); } return; } - ); + ) if $self->should_run_leapp(); $self->run_once( rmod_ln => sub { @@ -910,7 +1007,7 @@ sub run_stage_3 ($self) { ); # We have to do this before removing the rpms. - $self->run_once('pre_leapp_update_backup_and_cleanup'); + $self->run_once('run_final_components_pre_leapp'); # remove all arch cpanel packages # This also potentially removes @@ -924,25 +1021,45 @@ sub run_stage_3 ($self) { $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); } - # Avoids having to do preupgrade. - setup_answer_file(); - return; } ); + if ( !$self->should_run_leapp() ) { + return $self->_request_to_upgrade_distro_manually(); + } + $self->_do_leapp_upgrade(); - WARN(<<'EOS'); -Rebooting for distro upgrade. This will take over 10 minutes to run. -Do not interrupt power during this event or you will corrupt your system. -EOS + WARN(<<~'EOS'); + Rebooting for distro upgrade. This will take over 10 minutes to run. + Do not interrupt power during this event or you will corrupt your system. + EOS - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; # This takes a while because on reboot it's installing 800 packages } +sub _request_to_upgrade_distro_manually ($self) { + + my $pause_file = PAUSE_ELEVATE_TOUCHFILE; + + my $txt = <<"EOS"; +The cPanel elevation process is currently paused. +You should upgrade the distribution manually. + +After a successful upgrade, you can then remove the file + rm -f $pause_file +to let the elevation process continue and update cPanel for the updated distribution. +EOS + + WARN($txt); + File::Slurper::write_text( $pause_file, $txt ); + + return ACTION_PAUSE_REQUESTED; +} + =head2 run_stage_4 At this stage we should now run Alamalinux 8. @@ -1050,7 +1167,7 @@ sub run_stage_4 ($self) { } ); - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; } =head2 run_stage_5 @@ -1082,7 +1199,7 @@ sub run_stage_5 ($self) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); print_box("Great SUCCESS! Your upgrade to $pretty_distro_name is complete."); - return REBOOT_NEEDED; + return ACTION_REBOOT_NEEDED; } sub _bq_now () { @@ -1316,6 +1433,10 @@ sub disable_all_cpanel_services ($self) { sub _do_leapp_upgrade ($self) { + return unless $self->should_run_leapp(); + + $self->run_once('setup_answer_file'); + INFO("Running leapp upgrade"); my $ok = eval { @@ -1381,8 +1502,9 @@ EOS } # remove and store -sub pre_leapp_update_backup_and_cleanup ($self) { +sub run_final_components_pre_leapp ($self) { + # order matters $self->run_component_once( 'Imunify' => 'pre_leapp' ); $self->run_component_once( 'EA4' => 'pre_leapp' ); $self->run_component_once( 'PECL' => 'pre_leapp' ); @@ -1545,6 +1667,12 @@ sub post_upgrade_check ($self) { return 0; } +=pod + > cat /var/log/leapp/answerfile + [remove_pam_pkcs11_module_check] + confirm=True +=cut + sub setup_answer_file { my $leapp_dir = '/var/log/leapp'; mkdir $leapp_dir unless -d $leapp_dir; @@ -1574,6 +1702,17 @@ sub setup_answer_file { # TODO: We're going to need to store reboot time so we know if the last reboot has happened when we re-run the script. +sub should_run_leapp ($self) { + + # we store the no_leapp option, but prefer using a positive check instead + my $no_leapp = read_stage_file( 'no_leapp', 0 ); + return !$no_leapp; +} + +sub get_current_status ($self) { + return read_stage_file( 'status', 'unknown' ); +} + sub read_stage_file ( $k = undef, $default = {} ) { my $stage_info = _read_stage_file() // {}; diff --git a/t/blocker-IsContainer.t b/t/blocker-IsContainer.t index 7d68a74a..80a5a641 100644 --- a/t/blocker-IsContainer.t +++ b/t/blocker-IsContainer.t @@ -34,7 +34,7 @@ my $mock = Test::MockModule->new('Elevate::Blockers::IsContainer'); $isContainer->check(), { id => q[Elevate::Blockers::IsContainer::check], - msg => "cPanel thinks that this is a container-like environment, which this script cannot support at this time.", + msg => "cPanel thinks that this is a container-like environment, consider running leapp manually using the --no-leapp option.", }, q{Block if this is a container like environment.} ); diff --git a/t/leapp_upgrade.t b/t/leapp_upgrade.t index c97e2f34..5decacd1 100644 --- a/t/leapp_upgrade.t +++ b/t/leapp_upgrade.t @@ -27,10 +27,16 @@ $mock_elevate->redefine( ssystem_and_die => sub ( $, @args ) { note "run: ", join( ' ', @args ); + return; + }, + setup_answer_file => sub { # cannot use Test::MockFile with system touch... + note "mocked setup_answer_file"; return; } ); +my $mock_elevate_file = Test::MockFile->file('/var/cpanel/elevate'); + ok( cpev->_do_leapp_upgrade(), '_do_leapp_upgrade succeeds' ); $mock_elevate->redefine( From 23a53f40f1018be86c57cb530e8b3d08a45a3ce3 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 7 Sep 2023 12:12:44 -0400 Subject: [PATCH 2/7] _cleanup_rpm_db --- elevate-cpanel | 11 ++++++++--- lib/Elevate/Components/EA4.pm | 9 +++++++++ script/elevate-cpanel.PL | 3 --- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 978dc4d2..a560197d 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -2163,6 +2163,7 @@ EOS $self->run_once('_backup_ea4_profile'); $self->run_once('_backup_ea_addons'); + $self->run_once('_cleanup_rpm_db'); return; } @@ -2175,6 +2176,13 @@ EOS return; } + sub _cleanup_rpm_db ($self) { + + $self->ssystem(q{/usr/bin/yum -y erase ea-*}); + + return; + } + sub _restore_ea_addons ($self) { return unless cpev::read_stage_file('ea4')->{'nginx'}; @@ -5548,9 +5556,6 @@ sub run_stage_3 ($self) { # This also potentially removes $self->ssystem(q{/usr/bin/rpm -e --justdb --nodeps `/usr/bin/rpm -qa | /usr/bin/egrep '^cpanel-.*\.x86_64'`}); - # remove all ea- packages - $self->ssystem(q{/usr/bin/yum -y erase ea-*}); - foreach my $rpm (qw/ yum-plugin-fastestmirror epel-release/) { next unless Cpanel::Pkgr::is_installed($rpm); $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); diff --git a/lib/Elevate/Components/EA4.pm b/lib/Elevate/Components/EA4.pm index 415c99e8..0694820e 100644 --- a/lib/Elevate/Components/EA4.pm +++ b/lib/Elevate/Components/EA4.pm @@ -42,6 +42,7 @@ sub pre_leapp ($self) { # run to perform the backup $self->run_once('_backup_ea4_profile'); $self->run_once('_backup_ea_addons'); + $self->run_once('_cleanup_rpm_db'); return; } @@ -54,6 +55,14 @@ sub post_leapp ($self) { return; } +sub _cleanup_rpm_db ($self) { + + # remove all ea- packages + $self->ssystem(q{/usr/bin/yum -y erase ea-*}); + + return; +} + sub _restore_ea_addons ($self) { return unless cpev::read_stage_file('ea4')->{'nginx'}; diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index 17b5650b..f74579d2 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -1013,9 +1013,6 @@ sub run_stage_3 ($self) { # This also potentially removes $self->ssystem(q{/usr/bin/rpm -e --justdb --nodeps `/usr/bin/rpm -qa | /usr/bin/egrep '^cpanel-.*\.x86_64'`}); - # remove all ea- packages - $self->ssystem(q{/usr/bin/yum -y erase ea-*}); - foreach my $rpm (qw/ yum-plugin-fastestmirror epel-release/) { next unless Cpanel::Pkgr::is_installed($rpm); $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); From 9ca580571297b414aca3d872d36b1455f4994720 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 7 Sep 2023 12:18:25 -0400 Subject: [PATCH 3/7] Move /scripts symlink to AbsoluteSymlinks compoment --- elevate-cpanel | 24 ++++++++++++++++---- lib/Elevate/Components/AbsoluteSymlinks.pm | 26 +++++++++++++++------- script/elevate-cpanel.PL | 2 -- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index a560197d..cb87ef34 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -2052,7 +2052,16 @@ EOS return %links; } - sub pre_leapp { + sub pre_leapp ($self) { + + $self->ssystem(qw{/usr/bin/ln -snf usr/local/cpanel/scripts /scripts}); + $self->_absolute_symlinks; + + return; + } + + sub _absolute_symlinks ($self) { + my %links = get_abs_symlinks(); return unless %links; my $chdir = Cpanel::Chdir->new("/"); @@ -2070,7 +2079,8 @@ EOS return; } - sub post_leapp { + sub post_leapp ($self) { + return; } @@ -2172,6 +2182,14 @@ EOS $self->run_once('_restore_ea4_profile'); $self->run_once('_restore_ea_addons'); + $self->run_once('_cleanup_rpm_db'); + + return; + } + + sub _cleanup_rpm_db ($self) { + + $self->ssystem(q{/usr/bin/yum -y erase ea-*}); return; } @@ -5543,8 +5561,6 @@ sub run_stage_3 ($self) { $self->run_once( rmod_ln => sub { $self->ssystem( '/usr/sbin/rmmod', $_ ) foreach qw/floppy pata_acpi/; - $self->ssystem(qw{/usr/bin/ln -snf usr/local/cpanel/scripts /scripts}); - return; } ); diff --git a/lib/Elevate/Components/AbsoluteSymlinks.pm b/lib/Elevate/Components/AbsoluteSymlinks.pm index 2871675b..bae08ece 100644 --- a/lib/Elevate/Components/AbsoluteSymlinks.pm +++ b/lib/Elevate/Components/AbsoluteSymlinks.pm @@ -20,19 +20,28 @@ use parent qw{Elevate::Components::Base}; sub get_abs_symlinks { my %links; - foreach my $entry (glob "/*") { - my $path = readlink($entry); # don't bother with stat, this is fast + foreach my $entry ( glob "/*" ) { + my $path = readlink($entry); # don't bother with stat, this is fast next unless $path && substr( $path, 0, 1 ) eq '/'; $links{$entry} = $path; } return %links; } -sub pre_leapp { +sub pre_leapp ($self) { + + $self->ssystem(qw{/usr/bin/ln -snf usr/local/cpanel/scripts /scripts}); + $self->_absolute_symlinks; + + return; +} + +sub _absolute_symlinks ($self) { + my %links = get_abs_symlinks(); return unless %links; my $chdir = Cpanel::Chdir->new("/"); - foreach my $link (keys(%links)) { + foreach my $link ( keys(%links) ) { my $updated = substr( $links{$link}, 1 ); # Now, this has probably .01% of collision chance, but let's get even @@ -40,17 +49,18 @@ sub pre_leapp { # Presumably if we can't find something by 10k tries, it just isn't # happening no matter how hard we want it. my $rand_uid = Cpanel::UUID::random_uuid(); - my $tries = 0; - while( -e "$link-$rand_uid" && $tries++ < 10000 ) { + my $tries = 0; + while ( -e "$link-$rand_uid" && $tries++ < 10000 ) { $rand_uid = Cpanel::UUID::random_uuid(); } - symlink( $updated, "$link-$rand_uid" ) or die "Can't create symlink $link-$rand_uid to $updated: $!"; + symlink( $updated, "$link-$rand_uid" ) or die "Can't create symlink $link-$rand_uid to $updated: $!"; File::Copy::move( "$link-$rand_uid", $link ) or die "Can't overwite $link: $!"; } return; } -sub post_leapp { +sub post_leapp ($self) { + return; } diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index f74579d2..13566c55 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -1000,8 +1000,6 @@ sub run_stage_3 ($self) { $self->run_once( rmod_ln => sub { $self->ssystem( '/usr/sbin/rmmod', $_ ) foreach qw/floppy pata_acpi/; - $self->ssystem(qw{/usr/bin/ln -snf usr/local/cpanel/scripts /scripts}); - return; } ); From 7de87e5bf6ea909f3d244498287a8b5a4cd27264 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 7 Sep 2023 12:31:20 -0400 Subject: [PATCH 4/7] Move some code from stage3 to components --- elevate-cpanel | 118 ++++++++++++++++++++++++-------- lib/Elevate/Components/RmMod.pm | 37 ++++++++++ lib/Elevate/Components/RpmDB.pm | 50 ++++++++++++++ script/elevate-cpanel.PL | 25 ++----- 4 files changed, 184 insertions(+), 46 deletions(-) create mode 100644 lib/Elevate/Components/RmMod.pm create mode 100644 lib/Elevate/Components/RpmDB.pm diff --git a/elevate-cpanel b/elevate-cpanel index cb87ef34..2bd61937 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -47,6 +47,8 @@ BEGIN { # Suppress load of all of these at earliest point. $INC{'Elevate/Components/PECL.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Components/PerlXS.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Components/Repositories.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/Components/RpmDB.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/Components/RmMod.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Components/WPToolkit.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Fetch.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Logger.pm'} = 'script/elevate-cpanel.PL.static'; @@ -2182,14 +2184,6 @@ EOS $self->run_once('_restore_ea4_profile'); $self->run_once('_restore_ea_addons'); - $self->run_once('_cleanup_rpm_db'); - - return; - } - - sub _cleanup_rpm_db ($self) { - - $self->ssystem(q{/usr/bin/yum -y erase ea-*}); return; } @@ -3742,6 +3736,89 @@ EOS } # --- END lib/Elevate/Components/Repositories.pm +{ # --- BEGIN lib/Elevate/Components/RpmDB.pm + + package Elevate::Components::RpmDB; + + use cPstrict; + + use Elevate::Constants (); + + use Cwd (); + use File::Copy (); + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + use Cpanel::Pkgr (); + + # use Elevate::Components::Base(); + our @ISA; + BEGIN { push @ISA, qw(Elevate::Components::Base); } + + sub pre_leapp ($self) { + + $self->run_once("_cleanup_rpms"); + + return; + } + + sub _cleanup_rpms ($self) { + + $self->ssystem(q{/usr/bin/rpm -e --justdb --nodeps `/usr/bin/rpm -qa | /usr/bin/egrep '^cpanel-.*\.x86_64'`}); + + foreach my $rpm (qw/ yum-plugin-fastestmirror epel-release/) { + next unless Cpanel::Pkgr::is_installed($rpm); + $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); + } + + return; + } + + sub post_leapp ($self) { + return; + } + + 1; + +} # --- END lib/Elevate/Components/RpmDB.pm + +{ # --- BEGIN lib/Elevate/Components/RmMod.pm + + package Elevate::Components::RmMod; + + use cPstrict; + + use Elevate::Constants (); + + use Cwd (); + use File::Copy (); + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + # use Elevate::Components::Base(); + our @ISA; + BEGIN { push @ISA, qw(Elevate::Components::Base); } + + sub pre_leapp ($self) { + + $self->run_once("_rmod_ln"); + + return; + } + + sub _rmod_ln ($self) { + + $self->ssystem( '/usr/sbin/rmmod', $_ ) foreach qw/floppy pata_acpi/; + + return; + } + + 1; + +} # --- END lib/Elevate/Components/RmMod.pm + { # --- BEGIN lib/Elevate/Components/WPToolkit.pm package Elevate::Components::WPToolkit; @@ -4831,6 +4908,8 @@ use Elevate::Components::NixStats (); use Elevate::Components::PECL (); use Elevate::Components::PerlXS (); use Elevate::Components::Repositories (); +use Elevate::Components::RpmDB (); +use Elevate::Components::RmMod (); use Elevate::Components::WPToolkit (); use Elevate::Fetch (); @@ -5558,29 +5637,12 @@ sub run_stage_3 ($self) { } ) if $self->should_run_leapp(); - $self->run_once( - rmod_ln => sub { - $self->ssystem( '/usr/sbin/rmmod', $_ ) foreach qw/floppy pata_acpi/; - return; - } - ); - - # We have to do this before removing the rpms. - $self->run_once('run_final_components_pre_leapp'); - - # remove all arch cpanel packages - # This also potentially removes - $self->ssystem(q{/usr/bin/rpm -e --justdb --nodeps `/usr/bin/rpm -qa | /usr/bin/egrep '^cpanel-.*\.x86_64'`}); - - foreach my $rpm (qw/ yum-plugin-fastestmirror epel-release/) { - next unless Cpanel::Pkgr::is_installed($rpm); - $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); - } - return; } ); + $self->run_once('run_final_components_pre_leapp'); + if ( !$self->should_run_leapp() ) { return $self->_request_to_upgrade_distro_manually(); } @@ -6061,6 +6123,7 @@ EOS sub run_final_components_pre_leapp ($self) { # order matters + $self->run_component_once( 'RmMod' => 'pre_leapp' ); $self->run_component_once( 'Imunify' => 'pre_leapp' ); $self->run_component_once( 'EA4' => 'pre_leapp' ); $self->run_component_once( 'PECL' => 'pre_leapp' ); @@ -6074,6 +6137,7 @@ sub run_final_components_pre_leapp ($self) { $self->run_component_once( 'NixStats' => 'pre_leapp' ); $self->run_component_once( 'LiteSpeed' => 'pre_leapp' ); $self->run_component_once( 'AbsoluteSymlinks' => 'pre_leapp' ); + $self->run_component_once( 'RpmDB' => 'pre_leapp' ); # remove the RPMs last return; } diff --git a/lib/Elevate/Components/RmMod.pm b/lib/Elevate/Components/RmMod.pm new file mode 100644 index 00000000..80ac368b --- /dev/null +++ b/lib/Elevate/Components/RmMod.pm @@ -0,0 +1,37 @@ +package Elevate::Components::RmMod; + +=encoding utf-8 + +=head1 NAME + +Elevate::Components::RmMod + +Run rmmod + +=cut + +use cPstrict; + +use Elevate::Constants (); + +use Cwd (); +use File::Copy (); +use Log::Log4perl qw(:easy); + +use parent qw{Elevate::Components::Base}; + +sub pre_leapp ($self) { + + $self->run_once("_rmod_ln"); + + return; +} + +sub _rmod_ln ($self) { + + $self->ssystem( '/usr/sbin/rmmod', $_ ) foreach qw/floppy pata_acpi/; + + return; +} + +1; diff --git a/lib/Elevate/Components/RpmDB.pm b/lib/Elevate/Components/RpmDB.pm new file mode 100644 index 00000000..9fc4a7d4 --- /dev/null +++ b/lib/Elevate/Components/RpmDB.pm @@ -0,0 +1,50 @@ +package Elevate::Components::RpmDB; + +=encoding utf-8 + +=head1 NAME + +Elevate::Components::RpmDB + +Perform some maintenance on the RPM database. + +=cut + +use cPstrict; + +use Elevate::Constants (); + +use Cwd (); +use File::Copy (); +use Log::Log4perl qw(:easy); + +use Cpanel::Pkgr (); + +use parent qw{Elevate::Components::Base}; + +sub pre_leapp ($self) { + + $self->run_once("_cleanup_rpms"); + + return; +} + +sub _cleanup_rpms ($self) { + + # remove all arch cpanel packages + # This also potentially removes + $self->ssystem(q{/usr/bin/rpm -e --justdb --nodeps `/usr/bin/rpm -qa | /usr/bin/egrep '^cpanel-.*\.x86_64'`}); + + foreach my $rpm (qw/ yum-plugin-fastestmirror epel-release/) { + next unless Cpanel::Pkgr::is_installed($rpm); + $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); + } + + return; +} + +sub post_leapp ($self) { + return; +} + +1; diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index 13566c55..c2cd9730 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -270,6 +270,8 @@ use Elevate::Components::NixStats (); use Elevate::Components::PECL (); use Elevate::Components::PerlXS (); use Elevate::Components::Repositories (); +use Elevate::Components::RpmDB (); +use Elevate::Components::RmMod (); use Elevate::Components::WPToolkit (); use Elevate::Fetch (); @@ -997,29 +999,12 @@ sub run_stage_3 ($self) { } ) if $self->should_run_leapp(); - $self->run_once( - rmod_ln => sub { - $self->ssystem( '/usr/sbin/rmmod', $_ ) foreach qw/floppy pata_acpi/; - return; - } - ); - - # We have to do this before removing the rpms. - $self->run_once('run_final_components_pre_leapp'); - - # remove all arch cpanel packages - # This also potentially removes - $self->ssystem(q{/usr/bin/rpm -e --justdb --nodeps `/usr/bin/rpm -qa | /usr/bin/egrep '^cpanel-.*\.x86_64'`}); - - foreach my $rpm (qw/ yum-plugin-fastestmirror epel-release/) { - next unless Cpanel::Pkgr::is_installed($rpm); - $self->ssystem( '/usr/bin/rpm', '-e', '--nodeps', $rpm ); - } - return; } ); + $self->run_once('run_final_components_pre_leapp'); + if ( !$self->should_run_leapp() ) { return $self->_request_to_upgrade_distro_manually(); } @@ -1500,6 +1485,7 @@ EOS sub run_final_components_pre_leapp ($self) { # order matters + $self->run_component_once( 'RmMod' => 'pre_leapp' ); $self->run_component_once( 'Imunify' => 'pre_leapp' ); $self->run_component_once( 'EA4' => 'pre_leapp' ); $self->run_component_once( 'PECL' => 'pre_leapp' ); @@ -1513,6 +1499,7 @@ sub run_final_components_pre_leapp ($self) { $self->run_component_once( 'NixStats' => 'pre_leapp' ); $self->run_component_once( 'LiteSpeed' => 'pre_leapp' ); $self->run_component_once( 'AbsoluteSymlinks' => 'pre_leapp' ); + $self->run_component_once( 'RpmDB' => 'pre_leapp' ); # remove the RPMs last return; } From 415f516e17d044ad2518ef2e6bcfb7edca0325fd Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 7 Sep 2023 12:35:19 -0400 Subject: [PATCH 5/7] Isolate install leap logic Simplify stage 3. --- elevate-cpanel | 57 ++++++++++++++++++---------------------- script/elevate-cpanel.PL | 57 ++++++++++++++++++---------------------- 2 files changed, 50 insertions(+), 64 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 2bd61937..4e9f0c99 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -5612,53 +5612,46 @@ In case of failure you probably want to reply to a few extra questions or remove sub run_stage_3 ($self) { - $self->run_once( - prep_for_leapp => sub { - - $self->run_once( - install_leapp => sub { - unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { - - # provides leapp-data-almalinux & leapp-data-rocky - $self->ssystem_and_die(qw{/usr/bin/yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm}); - } - - my $leap_data_pkg = $self->upgrade_to_rocky() ? 'leapp-data-rocky' : 'leapp-data-almalinux'; - - unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leap_data_pkg) ) { - $self->ssystem_and_die( qw{/usr/bin/yum install -y leapp-upgrade }, $leap_data_pkg ); - } - - if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { - $self->ssystem_and_die(qw{/usr/bin/yum -y remove kernel-devel}); - } - - return; - } - ) if $self->should_run_leapp(); - - return; - } - ); - $self->run_once('run_final_components_pre_leapp'); if ( !$self->should_run_leapp() ) { return $self->_request_to_upgrade_distro_manually(); } + $self->run_once('_install_leapp'); $self->_do_leapp_upgrade(); WARN(<<~'EOS'); - Rebooting for distro upgrade. This will take over 10 minutes to run. - Do not interrupt power during this event or you will corrupt your system. - EOS + Rebooting for distro upgrade. This will take over 10 minutes to run. + Do not interrupt power during this event or you will corrupt your system. + EOS return ACTION_REBOOT_NEEDED; # This takes a while because on reboot it's installing 800 packages } +sub _install_leapp ($self) { + + unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { + + # provides leapp-data-almalinux & leapp-data-rocky + $self->ssystem_and_die(qw{/usr/bin/yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm}); + } + + my $leap_data_pkg = $self->upgrade_to_rocky() ? 'leapp-data-rocky' : 'leapp-data-almalinux'; + + unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leap_data_pkg) ) { + $self->ssystem_and_die( qw{/usr/bin/yum install -y leapp-upgrade }, $leap_data_pkg ); + } + + if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { + $self->ssystem_and_die(qw{/usr/bin/yum -y remove kernel-devel}); + } + + return; +} + sub _request_to_upgrade_distro_manually ($self) { my $pause_file = PAUSE_ELEVATE_TOUCHFILE; diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index c2cd9730..8bd8e65c 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -974,53 +974,46 @@ In case of failure you probably want to reply to a few extra questions or remove sub run_stage_3 ($self) { - $self->run_once( - prep_for_leapp => sub { - - $self->run_once( - install_leapp => sub { - unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { - - # provides leapp-data-almalinux & leapp-data-rocky - $self->ssystem_and_die(qw{/usr/bin/yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm}); - } - - my $leap_data_pkg = $self->upgrade_to_rocky() ? 'leapp-data-rocky' : 'leapp-data-almalinux'; - - unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leap_data_pkg) ) { - $self->ssystem_and_die( qw{/usr/bin/yum install -y leapp-upgrade }, $leap_data_pkg ); - } - - if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { - $self->ssystem_and_die(qw{/usr/bin/yum -y remove kernel-devel}); - } - - return; - } - ) if $self->should_run_leapp(); - - return; - } - ); - $self->run_once('run_final_components_pre_leapp'); if ( !$self->should_run_leapp() ) { return $self->_request_to_upgrade_distro_manually(); } + $self->run_once('_install_leapp'); $self->_do_leapp_upgrade(); WARN(<<~'EOS'); - Rebooting for distro upgrade. This will take over 10 minutes to run. - Do not interrupt power during this event or you will corrupt your system. - EOS + Rebooting for distro upgrade. This will take over 10 minutes to run. + Do not interrupt power during this event or you will corrupt your system. + EOS return ACTION_REBOOT_NEEDED; # This takes a while because on reboot it's installing 800 packages } +sub _install_leapp ($self) { + + unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { + + # provides leapp-data-almalinux & leapp-data-rocky + $self->ssystem_and_die(qw{/usr/bin/yum install -y http://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm}); + } + + my $leap_data_pkg = $self->upgrade_to_rocky() ? 'leapp-data-rocky' : 'leapp-data-almalinux'; + + unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leap_data_pkg) ) { + $self->ssystem_and_die( qw{/usr/bin/yum install -y leapp-upgrade }, $leap_data_pkg ); + } + + if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { + $self->ssystem_and_die(qw{/usr/bin/yum -y remove kernel-devel}); + } + + return; +} + sub _request_to_upgrade_distro_manually ($self) { my $pause_file = PAUSE_ELEVATE_TOUCHFILE; From 38eb2b5b392c915905b84c4205984a41129bea0d Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 7 Sep 2023 15:44:28 -0400 Subject: [PATCH 6/7] Mass tidy --- elevate-cpanel | 2 +- lib/Elevate/Blockers.pm | 4 ++-- lib/Elevate/Blockers/AbsoluteSymlinks.pm | 8 ++------ lib/Elevate/Blockers/Databases.pm | 7 ++----- lib/Elevate/Blockers/Python.pm | 2 +- lib/Elevate/Motd.pm | 17 +++++++++-------- 6 files changed, 17 insertions(+), 23 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 4e9f0c99..8084dad5 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -357,7 +357,7 @@ BEGIN { # Suppress load of all of these at earliest point. use Elevate::Components::AbsoluteSymlinks (); - # use Log::Log4perl qw(:easy); + # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } # use Elevate::Blockers::Base(); diff --git a/lib/Elevate/Blockers.pm b/lib/Elevate/Blockers.pm index 65a34e2c..20511a62 100644 --- a/lib/Elevate/Blockers.pm +++ b/lib/Elevate/Blockers.pm @@ -75,7 +75,7 @@ our $_CHECK_MODE; # for now global so we can use the helper (move it later to sub _build_blockers { [] } -sub check ($self, %opts) { # do_check - main entry point +sub check ( $self, %opts ) { # do_check - main entry point if ( $self->cpev->service->is_active ) { WARN("An elevation process is already in progress."); @@ -87,7 +87,7 @@ sub check ($self, %opts) { # do_check - main entry point # If no argument passed to --check, use default path: my $blocker_file = $self->cpev->getopt('check') || ELEVATE_BLOCKER_FILE; - my $has_blockers = $self->_has_blockers($opts{'dry_run'}); + my $has_blockers = $self->_has_blockers( $opts{'dry_run'} ); $self->save( $blocker_file, { 'blockers' => $self->{'blockers'} } ); diff --git a/lib/Elevate/Blockers/AbsoluteSymlinks.pm b/lib/Elevate/Blockers/AbsoluteSymlinks.pm index 2984abc5..4a0daba8 100644 --- a/lib/Elevate/Blockers/AbsoluteSymlinks.pm +++ b/lib/Elevate/Blockers/AbsoluteSymlinks.pm @@ -14,17 +14,13 @@ correcting these before run. use cPstrict; use Elevate::Components::AbsoluteSymlinks (); -use Log::Log4perl qw(:easy); +use Log::Log4perl qw(:easy); use parent qw{Elevate::Blockers::Base}; sub check ($self) { my %links = Elevate::Components::AbsoluteSymlinks::get_abs_symlinks(); - WARN("Symlinks with absolute paths have been found in /:\n\t" - . join( ", ", sort keys(%links) ) . "\n" - ."This can cause problems during the leapp run, so\n" - .'these will be corrected to be relative symlinks before elevation.' - ) if %links; + WARN( "Symlinks with absolute paths have been found in /:\n\t" . join( ", ", sort keys(%links) ) . "\n" . "This can cause problems during the leapp run, so\n" . 'these will be corrected to be relative symlinks before elevation.' ) if %links; return; } diff --git a/lib/Elevate/Blockers/Databases.pm b/lib/Elevate/Blockers/Databases.pm index a57206ca..36b11712 100644 --- a/lib/Elevate/Blockers/Databases.pm +++ b/lib/Elevate/Blockers/Databases.pm @@ -119,11 +119,8 @@ sub _warning_mysql_not_enabled ($self) { my $enabled = Cpanel::Services::Enabled::is_enabled('mysql'); cpev::update_stage_file( { 'mysql-enabled' => $enabled } ); - WARN("MySQL is disabled. This must be enabled for MySQL upgrade to succeed.\n" - . "We temporarily will enable it when it is needed to be enabled,\n" - . "but we reccomend starting the process with MySQL enabled." - ) if !$enabled; + WARN( "MySQL is disabled. This must be enabled for MySQL upgrade to succeed.\n" . "We temporarily will enable it when it is needed to be enabled,\n" . "but we reccomend starting the process with MySQL enabled." ) if !$enabled; return 0; - } +} 1; diff --git a/lib/Elevate/Blockers/Python.pm b/lib/Elevate/Blockers/Python.pm index eae6fef9..fb68f51d 100644 --- a/lib/Elevate/Blockers/Python.pm +++ b/lib/Elevate/Blockers/Python.pm @@ -14,7 +14,7 @@ use cPstrict; use parent qw{Elevate::Blockers::Base}; -use Cpanel::Pkgr (); +use Cpanel::Pkgr (); sub check ($self) { my $pkg = Cpanel::Pkgr::what_provides('python36'); diff --git a/lib/Elevate/Motd.pm b/lib/Elevate/Motd.pm index f00de891..1a8ac054 100644 --- a/lib/Elevate/Motd.pm +++ b/lib/Elevate/Motd.pm @@ -67,14 +67,15 @@ sub cleanup { # Looks ugly, but fatpacker will just strip out lines =~ m/^\s*#/ sub _motd_notice_message { - return "# -----------------------------------------------------------------------------\n#\n". - "# /!\\ ELEVATE IN PROGRESS /!\\ \n#\n". - "# Do not make any changes until it's complete\n". - "# you can check the current process status by running:\n#\n". - "#\t\t/scripts/elevate-cpanel --status\n#\n". - "# Or monitor the progress by running:\n#\n". - "#\t\t/scripts/elevate-cpanel --log\n#\n". - "# -----------------------------------------------------------------------------\n"; + return + "# -----------------------------------------------------------------------------\n#\n" + . "# /!\\ ELEVATE IN PROGRESS /!\\ \n#\n" + . "# Do not make any changes until it's complete\n" + . "# you can check the current process status by running:\n#\n" + . "#\t\t/scripts/elevate-cpanel --status\n#\n" + . "# Or monitor the progress by running:\n#\n" + . "#\t\t/scripts/elevate-cpanel --log\n#\n" + . "# -----------------------------------------------------------------------------\n"; } sub _motd_file { # allow us to mock it, we cannot use Test::MockFile GH #77 - https://github.com/cpanel/Test-MockFile/issues/77 From b209a26d3b25a7f6c709347c60d579f778d62006 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 7 Sep 2023 17:32:55 -0400 Subject: [PATCH 7/7] Adjust IsContainer blocker message --- elevate-cpanel | 6 +++++- lib/Elevate/Blockers/IsContainer.pm | 6 +++++- t/blocker-IsContainer.t | 9 ++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 8084dad5..4c6f6af7 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -1096,7 +1096,11 @@ EOS return 0 unless $self->should_run_leapp; if ( _is_container_envtype() ) { - return $self->has_blocker("cPanel thinks that this is a container-like environment, consider running leapp manually using the --no-leapp option."); + return $self->has_blocker( <<~'EOS'); + cPanel thinks that this is a container-like environment. + This cannot be upgraded by the native leapp tool. + Consider contacting your hypervisor provider for alternative solutions. + EOS } return 0; diff --git a/lib/Elevate/Blockers/IsContainer.pm b/lib/Elevate/Blockers/IsContainer.pm index 35fe7d4e..1bf35f6e 100644 --- a/lib/Elevate/Blockers/IsContainer.pm +++ b/lib/Elevate/Blockers/IsContainer.pm @@ -20,7 +20,11 @@ sub check ($self) { # $self is a cpev object here return 0 unless $self->should_run_leapp; if ( _is_container_envtype() ) { - return $self->has_blocker("cPanel thinks that this is a container-like environment, consider running leapp manually using the --no-leapp option."); + return $self->has_blocker( <<~'EOS'); + cPanel thinks that this is a container-like environment. + This cannot be upgraded by the native leapp tool. + Consider contacting your hypervisor provider for alternative solutions. + EOS } return 0; diff --git a/t/blocker-IsContainer.t b/t/blocker-IsContainer.t index 80a5a641..59cb0c86 100644 --- a/t/blocker-IsContainer.t +++ b/t/blocker-IsContainer.t @@ -30,13 +30,20 @@ my $mock = Test::MockModule->new('Elevate::Blockers::IsContainer'); #my $cpev = bless { _abort_on_first_blocker => 1 }, 'cpev'; my $cpev = cpev->new( _abort_on_first_blocker => 1 ); + my $msg = <<~'EOS'; + cPanel thinks that this is a container-like environment. + This cannot be upgraded by the native leapp tool. + Consider contacting your hypervisor provider for alternative solutions. + EOS + is( $isContainer->check(), { id => q[Elevate::Blockers::IsContainer::check], - msg => "cPanel thinks that this is a container-like environment, consider running leapp manually using the --no-leapp option.", + msg => $msg, }, q{Block if this is a container like environment.} + ); $mock->redefine( '_is_container_envtype' => 0 );