From f6cea6ae734781f6c76098d4875a91a59d62f519 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Wed, 31 Jan 2024 09:52:05 -0600 Subject: [PATCH 01/12] Add initial support for Elevating from CL7 to CL8 Case RE-18: Add initial support for Elevating from CL7 to CL8 * Add Elevate::OS library to handle the heavy lifting regarding OS related inquiries * Teach the '--upgrade-to' option about CloudLinux 7 * Do not block on python36 for CloudLinux updates * Add blocker for when MySQL Governor is installed * Update the list vetted repos for CloudLinux upgrades * Skip the Imunify component for CL upgrades * Skip the KernelCare component for CL upgrades * Update EA4 component to support CL upgrades * Execute the correct version of leapp based on the OS being upgraded Changelog: Add initial support for Elevating from CL7 to CL8 --- elevate-cpanel | 1434 +++++++++++++++++------- lib/Elevate/Blockers/Databases.pm | 21 + lib/Elevate/Blockers/Distros.pm | 18 +- lib/Elevate/Blockers/EA4.pm | 1 - lib/Elevate/Blockers/Python.pm | 4 + lib/Elevate/Blockers/Repositories.pm | 32 +- lib/Elevate/Components/Base.pm | 10 + lib/Elevate/Components/EA4.pm | 7 +- lib/Elevate/Components/Grub2.pm | 4 - lib/Elevate/Components/Imunify.pm | 5 + lib/Elevate/Components/KernelCare.pm | 5 + lib/Elevate/Components/Repositories.pm | 25 + lib/Elevate/Components/RpmDB.pm | 41 +- lib/Elevate/DNF.pm | 41 + lib/Elevate/Leapp.pm | 174 +++ lib/Elevate/OS.pm | 155 +++ lib/Elevate/OS/Base.pm | 79 ++ lib/Elevate/OS/CentOS7.pm | 38 + lib/Elevate/OS/CloudLinux7.pm | 61 + lib/Elevate/RPM.pm | 35 +- lib/Elevate/YUM.pm | 66 ++ script/elevate-cpanel.PL | 333 ++---- t/blocker-Databases.t | 130 ++- t/blocker-DiskSpace.t | 7 +- t/blocker-Distros.t | 32 +- t/blocker-JetBackup.t | 30 +- t/blocker-Python.t | 9 + t/blocker-dns.t | 50 +- t/blocker-ea4.t | 123 +- t/blocker-whm.t | 35 +- t/components-ea4.t | 288 ++--- t/leapp_upgrade.t | 34 +- t/lib/Test/Elevate.pm | 30 +- t/notify.t | 79 +- t/usage.t | 85 +- 35 files changed, 2532 insertions(+), 989 deletions(-) create mode 100644 lib/Elevate/DNF.pm create mode 100644 lib/Elevate/Leapp.pm create mode 100644 lib/Elevate/OS.pm create mode 100644 lib/Elevate/OS/Base.pm create mode 100644 lib/Elevate/OS/CentOS7.pm create mode 100644 lib/Elevate/OS/CloudLinux7.pm create mode 100644 lib/Elevate/YUM.pm diff --git a/elevate-cpanel b/elevate-cpanel index ce72f3ad..0341f703 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -51,7 +51,12 @@ BEGIN { # Suppress load of all of these at earliest point. $INC{'Elevate/Components/RmMod.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Components/WPToolkit.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Components/SSH.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/OS.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/OS/Base.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/OS/CentOS7.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/OS/CloudLinux7.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Fetch.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/Leapp.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Logger.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Motd.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Notify.pm'} = 'script/elevate-cpanel.PL.static'; @@ -61,6 +66,8 @@ BEGIN { # Suppress load of all of these at earliest point. $INC{'Elevate/Service.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/SystemctlService.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Usage.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/DNF.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/YUM.pm'} = 'script/elevate-cpanel.PL.static'; } { # --- BEGIN lib/Elevate/Constants.pm @@ -471,6 +478,7 @@ BEGIN { # Suppress load of all of these at earliest point. use cPstrict; use Cpanel::OS (); + use Cpanel::Pkgr (); use Cpanel::Version::Tiny (); use Cpanel::JSON (); use Cpanel::SafeRun::Simple (); @@ -490,6 +498,7 @@ BEGIN { # Suppress load of all of these at earliest point. $ok = 0 unless $self->_blocker_acknowledge_postgresql_datadir; $ok = 0 unless $self->_blocker_old_mysql; $ok = 0 unless $self->_blocker_mysql_upgrade_in_progress; + $ok = 0 unless $self->_blocker_mysql_governor; $self->_warning_mysql_not_enabled(); return $ok; } @@ -640,6 +649,25 @@ BEGIN { # Suppress load of all of these at earliest point. return 0; } + sub _blocker_mysql_governor ($self) { + + if ( Cpanel::Pkgr::is_installed('governor-mysql') ) { + return $self->has_blocker( <<~'EOS' ); +You have MySQL Governor installed. Upgrades with this software in place are not supported. +For more information regarding MySQL Governor, please review the documentation: + + https://docs.cloudlinux.com/shared/cloudlinux_os_components/#mysql-governor + +To remove MySQL Governor, execute the following command: + + /usr/share/lve/dbgovernor/mysqlgovernor.py --delete + +EOS + } + + return 0; + } + sub _warning_mysql_not_enabled ($self) { require Cpanel::Services::Enabled; my $enabled = Cpanel::Services::Enabled::is_enabled('mysql'); @@ -760,13 +788,15 @@ EOS our @ISA; BEGIN { push @ISA, qw(Elevate::Blockers::Base); } + use Elevate::OS (); + # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } sub check ($self) { my @checks = qw{ - _blocker_is_non_centos7 + _blocker_os_is_not_supported _blocker_is_old_centos7 _blocker_is_experimental_os }; @@ -779,16 +809,17 @@ EOS return 0; } - sub _blocker_is_non_centos7 ($self) { - unless ( Cpanel::OS::major() == 7 && Cpanel::OS::distro() eq 'centos' ) { - my $pretty_distro_name = $self->upgrade_to_pretty_name(); - return $self->has_blocker(qq[This script is only designed to upgrade CentOS 7 to $pretty_distro_name.]); + sub _blocker_os_is_not_supported ($self) { + unless ( Elevate::OS::is_supported() ) { + my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); + return $self->has_blocker(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); } return 0; } sub _blocker_is_old_centos7 ($self) { + if ( Cpanel::OS::minor() < MINIMUM_CENTOS_7_SUPPORTED ) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); return $self->has_blocker( @@ -812,8 +843,9 @@ EOS sub bail_out_on_inappropriate_distro () { - if ( !( eval { Cpanel::OS::can_be_elevated() } // ( Cpanel::OS::distro() eq 'centos' && Cpanel::OS::major() == 7 ) ) ) { - FATAL(qq[This script is designed to only run on CentOS 7 servers.\n]); + unless ( Elevate::OS::is_supported() ) { + my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); + FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); exit 1; } @@ -890,7 +922,6 @@ EOS sub _blocker_ea4_profile ($self) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); - INFO("Checking EasyApache profile compatibility with $pretty_distro_name."); $self->cpev->component('EA4')->backup; # _backup_ea4_profile(); @@ -1509,9 +1540,13 @@ EOS our @ISA; BEGIN { push @ISA, qw(Elevate::Blockers::Base); } + use Elevate::OS (); + use Cpanel::Pkgr (); sub check ($self) { + return if Elevate::OS::leapp_can_handle_python36(); + my $pkg = Cpanel::Pkgr::what_provides('python36'); return unless $pkg && Cpanel::Pkgr::is_installed($pkg); return $self->has_blocker( <<~"END" ); @@ -1536,6 +1571,7 @@ EOS use Cpanel::JSON (); use Elevate::Constants (); + use Elevate::OS (); # use Elevate::Blockers::Base(); our @ISA; @@ -1590,6 +1626,22 @@ EOS MariaDB106 }; + use constant VETTED_CLOUDLINUX_YUM_REPO => qw{ + cloudlinux + cloudlinux-base + cloudlinux-updates + cloudlinux-extras + cloudlinux-compat + cloudlinux-imunify360 + cl-ea4 + cloudlinux-ea4 + cloudlinux-ea4-rollout + cl-mysql + cl-mysql-meta + cloudlinux-elevate + cloudlinux-rollout + }; + use constant VETTED_YUM_REPO => qw{ base c7-media @@ -1728,7 +1780,10 @@ EOS $self->{_yum_repos_to_disable} = []; $self->{_yum_repos_unsupported_with_packages} = []; - my %vetted = map { $_ => 1 } VETTED_YUM_REPO; + my @vetted_repos = (VETTED_YUM_REPO); + push( @vetted_repos, VETTED_CLOUDLINUX_YUM_REPO ) if Elevate::OS::name() eq 'CloudLinux7'; + + my %vetted = map { $_ => 1 } @vetted_repos; my $repo_dir = Elevate::Constants::YUM_REPOS_D; @@ -1755,8 +1810,14 @@ EOS return unless length $current_repo_name; return unless $current_repo_enabled; + my $temp_current_repo_name = $current_repo_name; + + $current_repo_name = $1 if $current_repo_name =~ m/^(cloudlinux-(?:rollout|ea4)(?:-rollout)?)-[0-9]+$/; + my $is_vetted = $vetted{$current_repo_name} || $vetted{ lc $current_repo_name }; + $current_repo_name = $temp_current_repo_name; + if ( !$is_vetted ) { $status{'UNVETTED'} = 1; my @installed_packages = cpev::get_installed_rpms_in_repo($current_repo_name); @@ -2121,6 +2182,8 @@ EOS use Simple::Accessor qw( cpev rpm + yum + dnf ); # use Log::Log4perl qw(:easy); @@ -2154,6 +2217,14 @@ EOS return Elevate::RPM->new( cpev => $self ); } + sub _build_yum ($self) { + return Elevate::YUM->new( cpev => $self ); + } + + sub _build_dnf ($self) { + return Elevate::DNF->new( cpev => $self ); + } + sub run_once ( $self, $subname ) { my $cpev = $self->cpev; @@ -2291,7 +2362,9 @@ EOS use cPstrict; use Elevate::Constants (); + use Elevate::OS (); use Elevate::RPM (); + use Elevate::YUM (); use Cwd (); @@ -2338,7 +2411,7 @@ EOS sub _cleanup_rpm_db ($self) { - $self->ssystem(q{/usr/bin/yum -y erase ea-*}); + $self->yum->remove('ea-*'); return; } @@ -2397,7 +2470,7 @@ EOS sub _get_ea4_profile ($self) { - my $ea_alias = $self->upgrade_to_rocky() ? 'CentOS_8' : 'AlmaLinux_8'; + my $ea_alias = Elevate::OS::ea_alias(); my @cmd = ( '/usr/local/bin/ea_current_to_profile', "--target-os=$ea_alias" ); @@ -2687,6 +2760,7 @@ EOS use Elevate::Constants (); use Elevate::Fetch (); use Elevate::Notify (); + use Elevate::OS (); use Cwd (); @@ -2709,6 +2783,8 @@ EOS sub pre_leapp ($self) { + return if Elevate::OS::leapp_can_handle_imunify(); + return unless $self->is_installed; $self->run_once("_capture_imunify_features"); @@ -2720,6 +2796,8 @@ EOS sub post_leapp ($self) { + return if Elevate::OS::leapp_can_handle_imunify(); + $self->run_once('_reinstall_imunify_360'); $self->run_once('_restore_imunify_features'); $self->run_once("_restore_imunify_packages"); @@ -3122,6 +3200,7 @@ EOS use cPstrict; use Elevate::Constants (); + use Elevate::OS (); use Cwd (); use File::Copy (); @@ -3136,6 +3215,8 @@ EOS sub pre_leapp ($self) { + return if Elevate::OS::leapp_can_handle_kernelcare(); + $self->run_once("_remove_kernelcare_if_needed"); return; @@ -3143,6 +3224,8 @@ EOS sub post_leapp ($self) { + return if Elevate::OS::leapp_can_handle_kernelcare(); + $self->run_once('_restore_kernelcare'); return; @@ -3885,6 +3968,8 @@ EOS use Elevate::Constants (); use Elevate::Blockers::Repositories (); + use Elevate::OS (); + use Elevate::RPM (); use Cpanel::SafeRun::Simple (); use Cwd (); @@ -3899,6 +3984,8 @@ EOS sub pre_leapp ($self) { + $self->run_once("_disable_epel"); + $self->run_once("_disable_yum_plugin_fastestmirror"); $self->run_once("_disable_known_yum_repositories"); return; @@ -3924,6 +4011,27 @@ EOS return; } + sub _disable_yum_plugin_fastestmirror ($self) { + my $pkg = 'yum-plugin-fastestmirror'; + $self->_erase_package($pkg); + return; + } + + sub _disable_epel ($self) { + + return if Elevate::OS::leapp_can_handle_epel(); + + my $pkg = 'epel-release'; + $self->_erase_package($pkg); + return; + } + + sub _erase_package ( $self, $pkg ) { + return unless Cpanel::Pkgr::is_installed($pkg); + $self->rpm->remove_no_dependencies($pkg); + return; + } + 1; } # --- END lib/Elevate/Components/Repositories.pm @@ -3935,6 +4043,7 @@ EOS use cPstrict; use Elevate::Constants (); + use Elevate::DNF (); use Cwd (); use File::Copy (); @@ -3942,7 +4051,8 @@ EOS # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - use Cpanel::Pkgr (); + use Cpanel::Pkgr (); + use Cpanel::Yum::Vars (); # use Elevate::Components::Base(); our @ISA; @@ -3957,17 +4067,37 @@ EOS 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 ); - } + $self->rpm->remove_cpanel_arch_rpms(); return; } sub post_leapp ($self) { + + $self->run_once("_sysup"); + + return; + } + + sub _sysup ($self) { + Cpanel::Yum::Vars::install(); + $self->dnf->clean_all(); + + my $epel_url = 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm'; + + $self->dnf->install_rpm_via_url($epel_url); + + $self->dnf->config_manager_enable('powertools'); + $self->dnf->config_manager_enable('epel'); + + $self->ssystem(qw{/usr/bin/rm -f /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/X/Tiny.pm}); + { + local $ENV{'CPANEL_BASE_INSTALL'} = 1; # Don't fix more than perl itself. + $self->ssystem(qw{/usr/local/cpanel/scripts/fix-cpanel-perl}); + } + $self->dnf->update_allow_raising( '--disablerepo', 'cpanel-plugins' ); + $self->ssystem_and_die(qw{/usr/local/cpanel/scripts/sysup}); + return; } @@ -4132,238 +4262,731 @@ EOS } # --- END lib/Elevate/Components/SSH.pm -{ # --- BEGIN lib/Elevate/Fetch.pm +{ # --- BEGIN lib/Elevate/OS.pm - package Elevate::Fetch; + package Elevate::OS; use cPstrict; - use Elevate::Constants (); - use Cpanel::HTTP::Client (); - use File::Temp (); - # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - sub script ( $url, $template, $suffix = '.sh' ) { - my $response = eval { - my $http = Cpanel::HTTP::Client->new()->die_on_http_error(); - $http->get($url); - }; + use Elevate::OS::CentOS7; + use Elevate::OS::CloudLinux7; - if ( my $exception = $@ ) { - ERROR("The system could not fetch the script for $template: $exception"); - return; - } + use constant SUPPORTED_DISTROS => qw{ + CentOS7 + CloudLinux7 + }; - my $fh = File::Temp->new( - TEMPLATE => "${template}_XXXX", - SUFFIX => $suffix, - UNLINK => 0, - PERMS => 0600, - TMPDIR => 1 - ) - or do { - ERROR(qq[Cannot create a temporary file]); - return; - }; - print {$fh} $response->{'content'}; - close $fh; + use constant PRETTY_SUPPORTED_DISTROS => ( + 'CentOS 7', + 'CloudLinux 7', + ); - return "$fh"; - } + use constant AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7 => qw{ + alma + almalinux + rocky + rockylinux + }; - 1; + use constant AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7 => qw{ + cloud + cloudlinux + }; -} # --- END lib/Elevate/Fetch.pm + our $OS; -{ # --- BEGIN lib/Elevate/Logger.pm + sub factory { + my $distro_with_version = cpev::read_stage_file( 'upgrade_from', '' ); - package Elevate::Logger; + my $distro; + my $major; + if ( !$distro_with_version ) { + $distro = Cpanel::OS::distro(); + $distro = 'CentOS' if $distro eq 'centos'; + $distro = 'CloudLinux' if $distro eq 'cloudlinux'; + $major = Cpanel::OS::major(); + $distro_with_version = $distro . $major; + } - use cPstrict; + FATAL("Attempted to get factory for unsupported OS: $distro $major") unless grep { $_ eq $distro_with_version } SUPPORTED_DISTROS; - use Elevate::Constants (); + my $pkg = "Elevate::OS::" . $distro_with_version; + return $pkg->new; + } - use Term::ANSIColor (); + sub instance { + $OS //= factory(); - # use Log::Log4perl qw(:easy); - INIT { Log::Log4perl->import(qw{:easy}); } + return $OS; + } - my %colors = ( - TRACE => 'cyan', - DEBUG => 'bold white', - INFO => 'green', - WARN => 'yellow', - ERROR => 'red', - FATAL => 'bold red', - ); + sub is_supported () { + return eval { instance(); 1; } ? 1 : 0; + } - sub init ( $self, $debug_level = 'DEBUG' ) { - my $log_file = Elevate::Constants::LOG_FILE; + sub get_supported_distros () { + return PRETTY_SUPPORTED_DISTROS; + } - my $config = <<~"EOF"; - log4perl.appender.File=Log::Log4perl::Appender::File - log4perl.appender.File.filename=$log_file - log4perl.appender.File.syswrite=1 - log4perl.appender.File.utf8=1 - log4perl.appender.File.layout=Log::Log4perl::Layout::PatternLayout - log4perl.appender.File.layout.ConversionPattern=* %d{yyyy-MM-dd HH:mm:ss} (%L) [%s%p%u] %m%n - EOF + sub check_for_old_centos7 () { + return instance()->check_for_old_centos7(); + } - if ( $self->getopt('service') ) { - $config .= <<~"EOF"; - log4perl.rootLogger = $debug_level, File - EOF - } - else { - $config .= <<~"EOF"; - log4perl.appender.Screen=Log::Log4perl::Appender::Screen - log4perl.appender.Screen.stderr=0 - log4perl.appender.screen.utf8=1 - log4perl.appender.Screen.layout=Log::Log4perl::Layout::PatternLayout - log4perl.appender.Screen.layout.ConversionPattern=* %d{yyyy-MM-dd HH:mm:ss} [%s%p%u] %m{indent=2,chomp}%n - log4perl.rootLogger = $debug_level, Screen, File - EOF - } + sub default_upgrade_to () { + return instance()->default_upgrade_to(); + } - Log::Log4perl::Layout::PatternLayout::add_global_cspec( 's' => sub { Term::ANSIColor::color( $colors{ $_[3] } ) } ); - Log::Log4perl::Layout::PatternLayout::add_global_cspec( 'u' => sub { Term::ANSIColor::color('reset') } ); + sub get_available_upgrade_paths { + my $name = instance()->name(); - Log::Log4perl->init( \$config ); + if ( $name eq 'CentOS7' ) { + return AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; + } + elsif ( $name eq 'CloudLinux7' ) { + return AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; + } return; } - sub INFO_nolog ($msg) { - - return _nolog( $msg, 'INFO' ); + sub name () { + return instance()->name(); } - sub ERROR_nolog ($msg) { - - return _nolog( $msg, 'ERROR' ); + sub pretty_name () { + return instance()->pretty_name(); } - sub WARN_nolog ($msg) { + sub can_upgrade_to ($flavor) { + my $name = instance()->name(); - return _nolog( $msg, 'WARN' ); - } + if ( $name eq 'CentOS7' ) { + return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; + } + elsif ( $name eq 'CloudLinux7' ) { + return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; + } - sub _nolog ( $msg, $type = 'DEBUG' ) { + return 0; + } - return unless length $msg; + sub leapp_can_handle_epel () { + return instance()->leapp_can_handle_epel(); + } - print '# -------------------------> ['; - print Term::ANSIColor::color( $colors{$type} ); - print $type; - print Term::ANSIColor::color('reset'); - print '] '; - print Term::ANSIColor::color('bold white'); - say $msg; - print Term::ANSIColor::color('reset'); + sub leapp_can_handle_imunify () { + return instance()->leapp_can_handle_imunify(); + } - return; + sub leapp_can_handle_kernelcare () { + return instance()->leapp_can_handle_kernelcare(); } - 1; + sub ea_alias () { + return instance()->ea_alias(); + } -} # --- END lib/Elevate/Logger.pm + sub elevate_rpm_url () { + return instance()->elevate_rpm_url(); + } -{ # --- BEGIN lib/Elevate/Motd.pm + sub leapp_data_pkg () { + return instance()->leapp_data_pkg(); + } - package Elevate::Motd; + sub upgrade_to () { + return instance()->upgrade_to(); + } - use cPstrict; + sub leapp_flag () { + return instance()->leapp_flag(); + } - sub setup { + sub leapp_can_handle_python36 () { + return instance()->leapp_can_handle_python36(); + } - my $f = _motd_file(); + 1; - my $notice = _motd_notice_message(); +} # --- END lib/Elevate/OS.pm - local $/; - my $fh; - my $content = ''; +{ # --- BEGIN lib/Elevate/OS/Base.pm - if ( open( $fh, '+<', $f ) ) { - $content = <$fh> // ''; - } - elsif ( open( $fh, '>', $f ) ) { - 1; - } + package Elevate::OS::Base; - return 0 if $content =~ qr{elevate in progress}mi; + use cPstrict; - print {$fh} "\n" if length($content) && $content !~ qr{\n\z}; + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } - print {$fh} $notice; + use Simple::Accessor qw{ + ea_alias + elevate_rpm_url + default_upgrade_to + leapp_can_handle_epel + leapp_can_handle_imunify + leapp_can_handle_kernelcare + leapp_can_handle_python36 + leapp_data_pkg + leapp_flag + name + pretty_name + upgrade_to + }; - return 1; + sub _build_ea_alias ($self) { + return 'CentOS_8'; } - sub cleanup { + sub _build_elevate_rpm_url ($self) { + die "subclass must implement elevate_rpm_url\n"; + } - my $f = _motd_file(); + sub _build_default_upgrade_to ($self) { + die "subclass must implement default_upgrade_to\n"; + } - my $content; - open( my $fh, '+<', $f ) or return; - { - local $/; - $content = <$fh>; - } + sub _build_leapp_can_handle_epel ($self) { + return 0; + } - return 0 unless $content && $content =~ qr{elevate in progress}mi; + sub _build_leapp_can_handle_imunify ($self) { + return 0; + } - my $notice = _motd_notice_message(); + sub _build_leapp_can_handle_kernelcare ($self) { + return 0; + } - if ( $content =~ s{\Q$notice\E}{} ) { - seek( $fh, 0, 0 ); - print {$fh} $content; - truncate( $fh, tell($fh) ); - close($fh); + sub _build_leapp_can_handle_python36 ($self) { + return 0; + } - return 1; - } + sub _build_leapp_data_pkg ($self) { + die "subclass must implement leapp_data_pkg\n"; + } - return; + sub _build_name ($self) { + die "subclass must implement name\n"; } - 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"; + sub _build_pretty_name ($self) { + die "subclass must implment pretty_name\n"; } - sub _motd_file { # allow us to mock it, we cannot use Test::MockFile GH #77 - https://github.com/cpanel/Test-MockFile/issues/77 - return q[/etc/motd]; + sub _build_upgrade_to ($self) { + my $default = $self->default_upgrade_to(); + return cpev::read_stage_file( 'upgrade_to', $default ); } 1; -} # --- END lib/Elevate/Motd.pm +} # --- END lib/Elevate/OS/Base.pm -{ # --- BEGIN lib/Elevate/Notify.pm +{ # --- BEGIN lib/Elevate/OS/CentOS7.pm - package Elevate::Notify; + package Elevate::OS::CentOS7; use cPstrict; # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - sub warn_skip_version_check { - WARN("The --skip-cpanel-version-check option was specified! This option is provided for testing purposes only! cPanel may not be able to support the resulting conversion. Please consider whether this is what you want."); - return; + # use Elevate::OS::Base(); + our @ISA; + BEGIN { push @ISA, qw(Elevate::OS::Base); } + + sub _build_elevate_rpm_url ($self) { + return 'https://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm'; } - sub add_final_notification ( $msg, $warn_now = 0 ) { + sub _build_default_upgrade_to ($self) { + return 'almalinux'; + } + + sub _build_leapp_data_pkg ($self) { + my $upgrade_to = $self->upgrade_to(); + return $upgrade_to =~ m/^rocky/ai ? 'leapp-data-rocky' : 'leapp-data-almalinux'; + } + + sub _build_name ($self) { + return 'CentOS7'; + } + + sub _build_pretty_name ($self) { + return 'CentOS 7'; + } + + 1; + +} # --- END lib/Elevate/OS/CentOS7.pm + +{ # --- BEGIN lib/Elevate/OS/CloudLinux7.pm + + package Elevate::OS::CloudLinux7; + + use cPstrict; + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + # use Elevate::OS::Base(); + our @ISA; + BEGIN { push @ISA, qw(Elevate::OS::Base); } + + sub _build_ea_alias ($self) { + return 'CloudLinux_8'; + } + + sub _build_elevate_rpm_url ($self) { + return 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; + } + + sub _build_default_upgrade_to ($self) { + return 'CloudLinux'; + } + + sub _build_leapp_can_handle_epel ($self) { + return 1; + } + + sub _build_leapp_can_handle_imunify ($self) { + return 1; + } + + sub _build_leapp_can_handle_kernelcare ($self) { + return 1; + } + + sub _build_leapp_can_handle_python36 ($self) { + return 1; + } + + sub _build_leapp_data_pkg ($self) { + return 'leapp-data-cloudlinux'; + } + + sub _build_leapp_flag ($self) { + return '--nowarn'; + } + + sub _build_name ($self) { + return 'CloudLinux7'; + } + + sub _build_pretty_name ($self) { + return 'CloudLinux 7'; + } + + 1; + +} # --- END lib/Elevate/OS/CloudLinux7.pm + +{ # --- BEGIN lib/Elevate/Fetch.pm + + package Elevate::Fetch; + + use cPstrict; + + use Elevate::Constants (); + use Cpanel::HTTP::Client (); + use File::Temp (); + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + sub script ( $url, $template, $suffix = '.sh' ) { + my $response = eval { + my $http = Cpanel::HTTP::Client->new()->die_on_http_error(); + $http->get($url); + }; + + if ( my $exception = $@ ) { + ERROR("The system could not fetch the script for $template: $exception"); + return; + } + + my $fh = File::Temp->new( + TEMPLATE => "${template}_XXXX", + SUFFIX => $suffix, + UNLINK => 0, + PERMS => 0600, + TMPDIR => 1 + ) + or do { + ERROR(qq[Cannot create a temporary file]); + return; + }; + print {$fh} $response->{'content'}; + close $fh; + + return "$fh"; + } + + 1; + +} # --- END lib/Elevate/Fetch.pm + +{ # --- BEGIN lib/Elevate/Leapp.pm + + package Elevate::Leapp; + + use cPstrict; + + use Cpanel::JSON (); + use Cpanel::Pkgr (); + + use Elevate::OS (); + use Elevate::YUM (); + + use Config::Tiny (); + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + use constant LEAPP_REPORT_JSON => q[/var/log/leapp/leapp-report.json]; + use constant LEAPP_REPORT_TXT => q[/var/log/leapp/leapp-report.txt]; + + use Simple::Accessor qw{ + cpev + yum + }; + + sub _build_cpev { + die q[Missing cpev]; + } + + sub _build_yum ($self) { + return Elevate::YUM->new( cpev => $self->cpev() ); + } + + sub install ($self) { + + unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { + my $elevate_rpm_url = Elevate::OS::elevate_rpm_url(); + $self->yum->install_rpm_via_url($elevate_rpm_url); + } + + my $leapp_data_pkg = Elevate::OS::leapp_data_pkg(); + + unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leapp_data_pkg) ) { + $self->yum->install( 'leapp-upgrade', $leapp_data_pkg ); + } + + if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { + $self->yum->remove('kernel-devel'); + } + + return; + } + + sub upgrade ($self) { + + return unless $self->cpev->should_run_leapp(); + + $self->cpev->run_once( + setup_answer_file => sub { + $self->setup_answer_file(); + }, + ); + + my $leapp_flag = Elevate::OS::leapp_flag(); + my $leapp_bin = '/usr/bin/leapp'; + my @leapp_args = ('upgrade'); + push( @leapp_args, $leapp_flag ) if $leapp_flag; + + INFO("Running leapp upgrade"); + + my $ok = eval { + local $ENV{LEAPP_OVL_SIZE} = cpev::read_stage_file('env')->{'LEAPP_OVL_SIZE'} || 3000; + $self->cpev->ssystem_and_die( { keep_env => 1 }, $leapp_bin, @leapp_args ); + 1; + }; + + return 1 if $ok; + + $self->_report_leapp_failure_and_die(); + return; + } + + sub _report_leapp_failure_and_die ($self) { + + my $msg = <<'EOS'; +The 'leapp upgrade' process failed. + +Please investigate, resolve then re-run the following command to continue the update: + + /scripts/elevate-cpanel --continue + +EOS + + my $leapp_json_report = LEAPP_REPORT_JSON; + if ( -e $leapp_json_report ) { + my $report = eval { Cpanel::JSON::LoadFile($leapp_json_report) } // {}; + + my $entries = $report->{entries}; + if ( ref $entries eq 'ARRAY' ) { + foreach my $e (@$entries) { + next unless ref $e && $e->{title} =~ qr{Missing.*answer}i; + + $msg .= $e->{summary} if $e->{summary}; + + if ( ref $e->{detail} ) { + my $d = $e->{detail}; + + if ( ref $d->{remediations} ) { + foreach my $remed ( $d->{remediations}->@* ) { + next unless $remed->{type} && $remed->{type} eq 'command'; + next unless ref $remed->{context}; + my @hint = $remed->{context}->@*; + next unless scalar @hint; + $hint[0] = q[/usr/bin/leapp] if $hint[0] && $hint[0] eq 'leapp'; + my $cmd = join( ' ', @hint ); + + $msg .= "\n\n"; + $msg .= <<"EOS"; +Consider running this command: + + $cmd +EOS + } + } + + } + + } + } + } + + if ( -e LEAPP_REPORT_TXT ) { + $msg .= qq[\nYou can read the full leapp report at: ] . LEAPP_REPORT_TXT; + } + + die qq[$msg\n]; + return; + } + + sub setup_answer_file ($self) { + my $leapp_dir = '/var/log/leapp'; + mkdir $leapp_dir unless -d $leapp_dir; + + my $answerfile_path = $leapp_dir . '/answerfile'; + system touch => $answerfile_path unless -e $answerfile_path; + + my $do_write; # no point in overwriting the file if nothing needs to change + + my $ini_obj = Config::Tiny->read( $answerfile_path, 'utf8' ); + LOGDIE( 'Failed to read leapp answerfile: ' . Config::Tiny->errstr ) unless $ini_obj; + + my $SECTION = 'remove_pam_pkcs11_module_check'; + + if ( not defined $ini_obj->{$SECTION}->{'confirm'} or $ini_obj->{$SECTION}->{'confirm'} ne 'True' ) { + $do_write = 1; + $ini_obj->{$SECTION}->{'confirm'} = 'True'; + } + + if ($do_write) { + $ini_obj->write( $answerfile_path, 'utf8' ) # + or LOGDIE( 'Failed to write leapp answerfile: ' . $ini_obj->errstr ); + } + + return; + } + + 1; + +} # --- END lib/Elevate/Leapp.pm + +{ # --- BEGIN lib/Elevate/Logger.pm + + package Elevate::Logger; + + use cPstrict; + + use Elevate::Constants (); + + use Term::ANSIColor (); + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + my %colors = ( + TRACE => 'cyan', + DEBUG => 'bold white', + INFO => 'green', + WARN => 'yellow', + ERROR => 'red', + FATAL => 'bold red', + ); + + sub init ( $self, $debug_level = 'DEBUG' ) { + my $log_file = Elevate::Constants::LOG_FILE; + + my $config = <<~"EOF"; + log4perl.appender.File=Log::Log4perl::Appender::File + log4perl.appender.File.filename=$log_file + log4perl.appender.File.syswrite=1 + log4perl.appender.File.utf8=1 + log4perl.appender.File.layout=Log::Log4perl::Layout::PatternLayout + log4perl.appender.File.layout.ConversionPattern=* %d{yyyy-MM-dd HH:mm:ss} (%L) [%s%p%u] %m%n + EOF + + if ( $self->getopt('service') ) { + $config .= <<~"EOF"; + log4perl.rootLogger = $debug_level, File + EOF + } + else { + $config .= <<~"EOF"; + log4perl.appender.Screen=Log::Log4perl::Appender::Screen + log4perl.appender.Screen.stderr=0 + log4perl.appender.screen.utf8=1 + log4perl.appender.Screen.layout=Log::Log4perl::Layout::PatternLayout + log4perl.appender.Screen.layout.ConversionPattern=* %d{yyyy-MM-dd HH:mm:ss} [%s%p%u] %m{indent=2,chomp}%n + log4perl.rootLogger = $debug_level, Screen, File + EOF + } + + Log::Log4perl::Layout::PatternLayout::add_global_cspec( 's' => sub { Term::ANSIColor::color( $colors{ $_[3] } ) } ); + Log::Log4perl::Layout::PatternLayout::add_global_cspec( 'u' => sub { Term::ANSIColor::color('reset') } ); + + Log::Log4perl->init( \$config ); + + return; + } + + sub INFO_nolog ($msg) { + + return _nolog( $msg, 'INFO' ); + } + + sub ERROR_nolog ($msg) { + + return _nolog( $msg, 'ERROR' ); + } + + sub WARN_nolog ($msg) { + + return _nolog( $msg, 'WARN' ); + } + + sub _nolog ( $msg, $type = 'DEBUG' ) { + + return unless length $msg; + + print '# -------------------------> ['; + print Term::ANSIColor::color( $colors{$type} ); + print $type; + print Term::ANSIColor::color('reset'); + print '] '; + print Term::ANSIColor::color('bold white'); + say $msg; + print Term::ANSIColor::color('reset'); + + return; + } + + 1; + +} # --- END lib/Elevate/Logger.pm + +{ # --- BEGIN lib/Elevate/Motd.pm + + package Elevate::Motd; + + use cPstrict; + + sub setup { + + my $f = _motd_file(); + + my $notice = _motd_notice_message(); + + local $/; + my $fh; + my $content = ''; + + if ( open( $fh, '+<', $f ) ) { + $content = <$fh> // ''; + } + elsif ( open( $fh, '>', $f ) ) { + 1; + } + + return 0 if $content =~ qr{elevate in progress}mi; + + print {$fh} "\n" if length($content) && $content !~ qr{\n\z}; + + print {$fh} $notice; + + return 1; + } + + sub cleanup { + + my $f = _motd_file(); + + my $content; + open( my $fh, '+<', $f ) or return; + { + local $/; + $content = <$fh>; + } + + return 0 unless $content && $content =~ qr{elevate in progress}mi; + + my $notice = _motd_notice_message(); + + if ( $content =~ s{\Q$notice\E}{} ) { + seek( $fh, 0, 0 ); + print {$fh} $content; + truncate( $fh, tell($fh) ); + close($fh); + + return 1; + } + + return; + } + + 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"; + } + + sub _motd_file { # allow us to mock it, we cannot use Test::MockFile GH #77 - https://github.com/cpanel/Test-MockFile/issues/77 + return q[/etc/motd]; + } + + 1; + +} # --- END lib/Elevate/Motd.pm + +{ # --- BEGIN lib/Elevate/Notify.pm + + package Elevate::Notify; + + use cPstrict; + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + sub warn_skip_version_check { + WARN("The --skip-cpanel-version-check option was specified! This option is provided for testing purposes only! cPanel may not be able to support the resulting conversion. Please consider whether this is what you want."); + return; + } + + sub add_final_notification ( $msg, $warn_now = 0 ) { my $stage_info = cpev::read_stage_file(); return unless defined $msg && length $msg; @@ -4519,6 +5142,8 @@ EOS cpev }; + our $rpm = '/usr/bin/rpm'; + sub _build_cpev { die q[Missing cpev]; } @@ -4536,7 +5161,7 @@ EOS my %config_files; foreach my $pkg (@$pkgs) { - my $out = $self->cpev->ssystem_capture_output( '/usr/bin/rpm', '-qc', $pkg ) || {}; + my $out = $self->cpev->ssystem_capture_output( $rpm, '-qc', $pkg ) || {}; if ( $out->{status} != 0 ) { @@ -4575,6 +5200,37 @@ EOS return; } + sub remove_no_dependencies ( $self, $pkg ) { + $self->cpev->ssystem( $rpm, '-e', '--nodeps', $pkg ); + return; + } + + sub remove_no_dependencies_and_justdb ( $self, $pkg ) { + $self->cpev->ssystem( $rpm, '-e', '--nodeps', '--justdb', $pkg ); + return; + } + + sub get_installed_rpms ($self) { + my $out = $self->cpev->ssystem_capture_output( $rpm, '-qa' ); + return @{ $out->{stdout} }; + } + + sub get_cpanel_arch_rpms ($self) { + my @installed_rpms = $self->get_installed_rpms(); + my @cpanel_arch_rpms = grep { $_ =~ m/^cpanel-.*\.x86_64$/ } @installed_rpms; + return @cpanel_arch_rpms; + } + + sub remove_cpanel_arch_rpms ($self) { + my @rpms_to_remove = $self->get_cpanel_arch_rpms(); + + foreach my $rpm (@rpms_to_remove) { + $self->remove_no_dependencies_and_justdb($rpm); + } + + return; + } + 1; } # --- END lib/Elevate/RPM.pm @@ -4989,6 +5645,107 @@ EOS } # --- END lib/Elevate/Usage.pm +{ # --- BEGIN lib/Elevate/DNF.pm + + package Elevate::DNF; + + use cPstrict; + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + # use Elevate::YUM(); + our @ISA; + BEGIN { push @ISA, qw(Elevate::YUM); } + + sub _build_pkgmgr { + return '/usr/bin/dnf'; + } + + sub config_manager_enable ( $self, $repo ) { + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem( $pkgmgr, 'config-manager', '--enable', $repo ); + + return; + } + + sub update_allow_raising ( $self, @args ) { + my $pkgmgr = $self->pkgmgr; + + my @additional_args = scalar @args ? @args : ''; + + $self->cpev->ssystem( $pkgmgr, '-y', '--allowerasing', @additional_args, 'update' ); + + return; + } + + 1; + +} # --- END lib/Elevate/DNF.pm + +{ # --- BEGIN lib/Elevate/YUM.pm + + package Elevate::YUM; + + use cPstrict; + + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } + + use Simple::Accessor qw{ + cpev + pkgmgr + }; + + sub _build_cpev { + die q[Missing cpev]; + } + + sub _build_pkgmgr { + return '/usr/bin/yum'; + } + + sub remove ( $self, @pkgs ) { + return unless scalar @pkgs; + + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem_and_die( $pkgmgr, '-y', 'remove', @pkgs ); + + return; + } + + sub clean_all ($self) { + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem( $pkgmgr, 'clean', 'all' ); + + return; + } + + sub install_rpm_via_url ( $self, $rpm_url ) { + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem_and_die( $pkgmgr, '-y', 'install', $rpm_url ); + + return; + } + + sub install ( $self, @pkgs ) { + return unless scalar @pkgs; + + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem_and_die( $pkgmgr, '-y', 'install', @pkgs ); + + return; + } + + 1; + +} # --- END lib/Elevate/YUM.pm + package main; # Copyright 2023 cPanel L.L.C. @@ -5026,38 +5783,50 @@ package cpev; =head1 DESCRIPTION -Helps to upgrade CentOS 7 cPanel servers to AlmaLinux 8 or Rocky Linux 8. +Wrapper around the ELevate project which is designed to enable migrations +between major version of RHELĀ® derivatives. + +Currently supported upgrade paths: + +CentOS 7 => AlmaLinux 8 +CentOS 7 => Rocky Linux 8 +CloudLinux 7 => CloudLinux 8 =head1 SYNOPSIS /scripts/elevate-cpanel [OPTIONS] Optional: - --start Start the conversion process - --continue Continue the conversion: retry the last step - --check[=BLOCKER_FILE] Check if your system has any known blockers to upgrade. - --log Show the current elevation log - --status Check the current elevation status - --clean Cleanup scripts and files created by elevate-cpanel - --upgrade-to=[rocky|almalinux] Update to AlmaLinux 8 or Rocky Linux 8 - [default to 'almalinux'] - --non-interactive Skip the yes/no prompt before proceeding with the upgrade. + --start Start the conversion process + --continue Continue the conversion: retry the last step + --check[=BLOCKER_FILE] Check if your system has any known blockers to upgrade. + --log Show the current elevation log + --status Check the current elevation status + --clean Cleanup scripts and files created by elevate-cpanel + --upgrade-to=[rocky|almalinux|cloudlinux] Update to AlmaLinux 8 or Rocky Linux 8 + [Servers running CentOS 7 will default to 'almalinux'] + [Servers running CloudLinux 7 will default to 'cloudlinux'] - --update Instruct the script to replace itself on disk with a downloaded copy of the latest version. - --version Print the version number and exit. + NOTE: servers running CentOS 7 can only upgrade to almalinux or rocky + servers running CloudLinux 7 can only upgrade to cloudlinux - --skip-elevate-version-check Skip the check for whether this script is up to date. - --skip-cpanel-version-check Skip the check for whether cPanel is up to date. - This option is intended only for testing! + --non-interactive Skip the yes/no prompt before proceeding with the upgrade. - --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 + --update Instruct the script to replace itself on disk with a downloaded copy of the latest version. + --version Print the version number and exit. - --manual-reboots The script will stop and require the user to reboot manually rather than - automatically rebooting when reboots are needed + --skip-elevate-version-check Skip the check for whether this script is up to date. + --skip-cpanel-version-check Skip the check for whether cPanel is up to date. + This option is intended only for testing! - --help Display this documentation. + --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 + + --manual-reboots The script will stop and require the user to reboot manually rather than + automatically rebooting when reboots are needed + + --help Display this documentation. =head1 COMMON USAGE @@ -5067,13 +5836,17 @@ Helps to upgrade CentOS 7 cPanel servers to AlmaLinux 8 or Rocky Linux 8. You can start an elevation update by running: - # AlmaLinux 8 update + # AlmaLinux 8 update from CentOS 7 /scripts/elevate-cpanel --start /scripts/elevate-cpanel --start --upgrade-to=almalinux - # Rocky Linux 8 update + # Rocky Linux 8 update from CentOS 7 /scripts/elevate-cpanel --start --upgrade-to=rocky + # CloudLinux 8 update from CloudLinux 7 + /scripts/elevate-cpanel --start + /scripts/elevate-cpanel --start --upgrade-to=cloudlinux + =item Start an installation and skip the confirmation prompt By default, you will be asked if you wish to proceed with the upgrade. @@ -5087,13 +5860,17 @@ If you wish to skip this prompt (by assuming yes): You can check if your server is compatible with the upgrade process without starting an upgrade process. - # Check AlmaLinux 8 update + # Check AlmaLinux 8 update from CentOS 7 /scripts/elevate-cpanel --check /scripts/elevate-cpanel --check --upgrade-to=almalinux - # Check Rocky Linux 8 update + # Check Rocky Linux 8 update from CentOS 7 /scripts/elevate-cpanel --check --upgrade-to=rocky + # Check CloudLinux 8 update from CloudLinux 7 + /scripts/elevate-cpanel --check + /scripts/elevate-cpanel --check --upgrade-to=cloudlinux + This will also save a JSON representation of the blockers to a file, C by default, but passing an optional argument will use the file given instead: @@ -5133,7 +5910,7 @@ the update process by running: =head3 Using an alternative tool to upgrade your distro -By default, the elevate script runs the [leapp process](https://almalinux.org/elevate/) +By default, the elevate script runs the L 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. @@ -5165,8 +5942,7 @@ NOTE: `--no-leapp` is not required for helper commands like `--continue` or `--s =head1 WARNINGS -The elevation process from CentOS 7 to AlmaLinux 8 or Rocky Linux 8 distribution -is not a risk free update. +The elevation process to perform a major OS upgrade is not a risk free update. Depending on the state of your current distribution multiple errors can occur. We recommend updating your system to the last upstream state before starting. @@ -5199,7 +5975,6 @@ BEGIN { use Log::Log4perl qw(:easy); use Config; -use Config::Tiny (); use Carp (); use Errno (); use File::Basename (); @@ -5275,7 +6050,14 @@ use Elevate::Components::RmMod (); use Elevate::Components::WPToolkit (); use Elevate::Components::SSH (); +# - fatpack OS +use Elevate::OS (); +use Elevate::OS::Base (); +use Elevate::OS::CentOS7 (); +use Elevate::OS::CloudLinux7 (); + use Elevate::Fetch (); +use Elevate::Leapp (); use Elevate::Logger (); use Elevate::Motd (); use Elevate::Notify (); @@ -5285,6 +6067,8 @@ use Elevate::Script (); use Elevate::Service (); use Elevate::SystemctlService (); use Elevate::Usage (); +use Elevate::DNF (); +use Elevate::YUM (); #< 24; @@ -5298,9 +6082,6 @@ use constant VALID_STAGES => 5; use constant IGNORE_OUTDATED_SERVICES_FILE => q[/etc/cpanel/local/ignore_outdated_services]; -use constant LEAPP_REPORT_JSON => q[/var/log/leapp/leapp-report.json]; -use constant LEAPP_REPORT_TXT => q[/var/log/leapp/leapp-report.txt]; - use constant NOC_RECOMMENDATIONS_TOUCH_FILE => q[/var/cpanel/elevate-noc-recommendations]; # XXX TODO verify that imunify reponames are in fact correct. @@ -5310,8 +6091,9 @@ 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 UPGRADE_TO_ALMALINUX => q[AlmaLinux]; +use constant UPGRADE_TO_ROCKY => q[Rocky]; +use constant UPGRADE_TO_CLOUDLINUX => q[CloudLinux]; use constant PAUSE_ELEVATE_TOUCHFILE => q[/waiting_for_distro_upgrade]; @@ -5319,6 +6101,7 @@ use Simple::Accessor qw{ service script blockers + leapp }; # after Simple::Accessor @@ -5341,6 +6124,12 @@ sub _build_blockers ($self) { return Elevate::Blockers->new( cpev => $self ); } +sub _build_leapp ($self) { + + # FIXME weaken + return Elevate::Leapp->new( cpev => $self ); +} + sub _build_script ($self) { return Elevate::Script->new; } @@ -5370,8 +6159,6 @@ sub run ( $pkg, @args ) { return $self->do_update(); } - $self->_parse_opt_upgrade_to(); - if ( $self->getopt('start') ) { die qq[Unsupported option with --start\n] if $self->getopt('continue') || $self->getopt('service'); return 1 if $self->start(); @@ -5431,17 +6218,37 @@ sub get_blocker ( $self, $name ) { # helper for tests sub _parse_opt_upgrade_to ($self) { - return unless my $flavor = $self->getopt('upgrade-to'); + my $flavor = $self->getopt('upgrade-to'); if ( !defined $self->getopt('start') && !defined $self->getopt('check') ) { die qq[--upgrade-to option is only supported with --start or --check\n]; } + + Elevate::Blockers::Distros::bail_out_on_inappropriate_distro(); + + $flavor ||= Elevate::OS::default_upgrade_to(); + $flavor = lc $flavor; - if ( $flavor !~ m{^(?:almalinux|alma|rocky)$} ) { - die qq[Invalid --upgrade_to value '$flavor'. Only 'almalinux' or 'rocky' are supported.\n]; + if ( !Elevate::OS::can_upgrade_to($flavor) ) { + my @available_flavors = Elevate::OS::get_available_upgrade_paths(); + my $af = join( "\n", @available_flavors ); + die qq[The current OS can only upgrade to the following flavors:\n\n$af\n]; } - $self->{upgrade_to} = $flavor eq 'rocky' ? UPGRADE_TO_ROCKY : UPGRADE_TO_ALMALINUX; + $self->_set_upgrade_to($flavor); + + return; +} + +sub _set_upgrade_to ( $self, $flavor ) { + my $upgrade_to = UPGRADE_TO_ROCKY if $flavor =~ m/^rocky/a; + + $upgrade_to = UPGRADE_TO_ALMALINUX if $flavor =~ m/^alma/a; + $upgrade_to = UPGRADE_TO_CLOUDLINUX if $flavor =~ m/^cloud/a; + + die qq['$flavor' is not a valid path to upgrade to\n] unless $upgrade_to; + + $self->{upgrade_to} = $upgrade_to; return; } @@ -5477,16 +6284,20 @@ sub do_update ($self) { } sub upgrade_to ($self) { # main helper to know the upgrade_to distro - return $self->{upgrade_to} if $self->{upgrade_to}; - return read_stage_file( 'upgrade_to', UPGRADE_TO_ALMALINUX ); # default to AlmaLinux + return $self->{upgrade_to} ? $self->{upgrade_to} : Elevate::OS::upgrade_to(); } sub upgrade_to_rocky ($self) { return $self->upgrade_to() eq UPGRADE_TO_ROCKY; } +sub upgrade_to_cloudlinux ($self) { + return $self->upgrade_to() eq UPGRADE_TO_CLOUDLINUX; +} + sub upgrade_to_pretty_name ($self) { # used by output messages return q[Rocky Linux 8] if $self->upgrade_to_rocky; + return q[CloudLinux 8] if $self->upgrade_to_cloudlinux; return q[AlmaLinux 8]; } @@ -5514,7 +6325,7 @@ sub monitor_upgrade ($self) { } sub start ($self) { - Elevate::Blockers::Distros::bail_out_on_inappropriate_distro(); + $self->_parse_opt_upgrade_to(); my $stage = get_stage(); if ( $stage != 0 ) { my $header; @@ -5781,10 +6592,11 @@ sub check_status ($self) { sub _notify_success ($self) { + my $upgrade_from_name = Elevate::OS::pretty_name(); my $pretty_distro_name = $self->upgrade_to_pretty_name(); my $msg = <<"EOS"; -The cPanel & WHM server has completed the elevation process from CentOS 7 to $pretty_distro_name. +The cPanel & WHM server has completed the elevation process from $upgrade_from_name to $pretty_distro_name. EOS if ( my $warnings = read_stage_file( 'final_notifications', [] ) ) { @@ -5945,6 +6757,11 @@ sub run_stage_1 ($self) { # store 'upgrade_to' early so later stages can access it update_stage_file( { upgrade_to => $self->upgrade_to } ); + # store 'upgrade_from' early so that Elevate::OS can access it + # Elevate::OS is based on the OS we are upgrading from since the information + # that it provides is mostly based on what leapp can do when upgrading from an OS + update_stage_file( { upgrade_from => Elevate::OS::name() } ); + return $self->service->install(); } @@ -5983,15 +6800,16 @@ sub run_stage_2 ($self) { =head2 run_stage_3 -Setup the AlmaLinux elevate-release-latest-el7 repo and install leapp packages. -Prepare the cPanel packages for the update. +Setup the elevate-release-latest-el7 repo from the appropriate fork and install +leapp Packages. Prepare the cPnael packages for the update. Remove some known conflicting packages. (Reinstall later). Provide answers to a few leapp questions. Attempt to perform the leapp upgrade itself. -In case of failure you probably want to reply to a few extra questions or remove some conflicting packages. +In case of failure you probably want to reply to a few extra questions or remove +some conflicting packages. =cut @@ -6003,8 +6821,13 @@ sub run_stage_3 ($self) { return $self->_request_to_upgrade_distro_manually(); } - $self->run_once('_install_leapp'); - $self->_do_leapp_upgrade(); + $self->run_once( + install_leapp => sub { + $self->leapp->install(); + }, + ); + + $self->leapp->upgrade(); WARN(<<~'EOS'); Rebooting for distro upgrade. This will take over 10 minutes to run. @@ -6016,27 +6839,6 @@ sub run_stage_3 ($self) { # 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; @@ -6058,7 +6860,7 @@ EOS =head2 run_stage_4 -At this stage we should now run Alamalinux 8. +At this stage, we should now be run the upgraded OS (i.e. AlmaLinux 8). Update cPanel product for the new distro. Restore removed packages during the previous stage. @@ -6097,29 +6899,7 @@ sub run_stage_4 ($self) { $stash->{stage4} //= {}; # run once each blocks - $self->run_once( - sysup => sub { - Cpanel::Yum::Vars::install(); - $self->ssystem_and_die(qw{/usr/bin/dnf clean all}); - - # no failures once already installed: no need to check for the epel-release version - $self->ssystem_and_die(qw{/usr/bin/dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm}); - - $self->ssystem(qw{/usr/bin/dnf config-manager --enable powertools}); - $self->ssystem(qw{/usr/bin/dnf config-manager --enable epel}); - - # Break cpanel-perl (NOTE: This only works on perl 5.36) - $self->ssystem(qw{/usr/bin/rm -f /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/X/Tiny.pm}); - { - local $ENV{'CPANEL_BASE_INSTALL'} = 1; # Don't fix more than perl itself. - $self->ssystem(qw{/usr/local/cpanel/scripts/fix-cpanel-perl}); - } - $self->ssystem(qw{/usr/bin/dnf -y --allowerasing --disablerepo cpanel-plugins update}); - $self->ssystem_and_die(qw{/usr/local/cpanel/scripts/sysup}); - - return; - } - ); + $self->run_component_once( 'RpmDB', => 'post_leapp' ); $self->run_once( restore_cpanel_services => sub { @@ -6153,7 +6933,7 @@ sub run_stage_4 ($self) { $self->post_leapp_update_restore(); my @known_modules_that_dont_convert = qw{libtermkey msgpack btrfs-progs elevate-release - leapp leapp-data-almalinux leapp-data-rocky leapp-upgrade-el7toel8 + leapp leapp-data-almalinux leapp-data-rocky leapp-data-cloudlinux leapp-upgrade-el7toel8 python2-leapp alt-pcre802 alt-pcre802-devel}; my @to_remove = grep { Cpanel::Pkgr::is_installed($_) } @known_modules_that_dont_convert; @@ -6178,7 +6958,7 @@ The elevate-cpanel service is now removed. =cut sub run_stage_5 ($self) { - return 1 if $self->post_upgrade_check(); + return 0 if $self->post_upgrade_check(); # we cannot stop the service ( ourself ) $self->service->disable; @@ -6242,14 +7022,6 @@ sub elevation_success_marker ($self) { return; } -=pod - -Example: - - $self->run_component_once( Imunify => 'backup' ); - -=cut - sub run_component_once ( $self, $name, $function ) { my $component = $self->component($name); @@ -6431,76 +7203,6 @@ sub disable_all_cpanel_services ($self) { return; } -sub _do_leapp_upgrade ($self) { - - return unless $self->should_run_leapp(); - - $self->run_once('setup_answer_file'); - - INFO("Running leapp upgrade"); - - my $ok = eval { - local $ENV{LEAPP_OVL_SIZE} = read_stage_file('env')->{'LEAPP_OVL_SIZE'} || 3000; - $self->ssystem_and_die( { keep_env => 1 }, qw{/usr/bin/leapp upgrade} ); - 1; - }; - - return 1 if $ok; - - my $msg = <<'EOS'; -The 'leapp upgrade' process failed. - -Please investigate, resolve then re-run the following command to continue the update: - - /scripts/elevate-cpanel --continue - -EOS - - my $leapp_json_report = LEAPP_REPORT_JSON; - if ( -e $leapp_json_report ) { - my $report = eval { Cpanel::JSON::LoadFile($leapp_json_report) } // {}; - - my $entries = $report->{entries}; - if ( ref $entries eq 'ARRAY' ) { - foreach my $e (@$entries) { - next unless ref $e && $e->{title} =~ qr{Missing.*answer}i; - - $msg .= $e->{summary} if $e->{summary}; - - if ( ref $e->{detail} ) { - my $d = $e->{detail}; - - if ( ref $d->{remediations} ) { - foreach my $remed ( $d->{remediations}->@* ) { - next unless $remed->{type} && $remed->{type} eq 'command'; - next unless ref $remed->{context}; - my @hint = $remed->{context}->@*; - next unless scalar @hint; - $hint[0] = q[/usr/bin/leapp] if $hint[0] && $hint[0] eq 'leapp'; - my $cmd = join( ' ', @hint ); - - $msg .= "\n\n"; - $msg .= <<"EOS"; -Consider running this command: - - $cmd -EOS - } - } - - } - - } - } - } - - if ( -e LEAPP_REPORT_TXT ) { - $msg .= qq[\nYou can read the full leapp report at: ] . LEAPP_REPORT_TXT; - } - - die qq[$msg\n]; -} - # remove and store sub run_final_components_pre_leapp ($self) { @@ -6655,12 +7357,12 @@ sub remove_rpms_from_repos ( $self, @repo_list ) { sub post_upgrade_check ($self) { - my $expect_distro = $self->upgrade_to_rocky() ? 'rocky' : 'almalinux'; + my $expect_distro = Elevate::OS::upgrade_to(); + $expect_distro = lc $expect_distro; unless ( Cpanel::OS::major() == 8 && Cpanel::OS::distro() eq $expect_distro ) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); - FATAL("Your distro does not looks like $pretty_distro_name."); - return 1; + die "Your distro does not look like $pretty_distro_name.\n"; } # call a cpanel binary @@ -6669,40 +7371,6 @@ 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; - - my $answerfile_path = $leapp_dir . '/answerfile'; - system touch => $answerfile_path unless -e $answerfile_path; - - my $do_write; # no point in overwriting the file if nothing needs to change - - my $ini_obj = Config::Tiny->read( $answerfile_path, 'utf8' ); - LOGDIE( 'Failed to read leapp answerfile: ' . Config::Tiny->errstr ) unless $ini_obj; - - my $SECTION = 'remove_pam_pkcs11_module_check'; - - if ( not defined $ini_obj->{$SECTION}->{'confirm'} or $ini_obj->{$SECTION}->{'confirm'} ne 'True' ) { - $do_write = 1; - $ini_obj->{$SECTION}->{'confirm'} = 'True'; - } - - if ($do_write) { - $ini_obj->write( $answerfile_path, 'utf8' ) # - or LOGDIE( 'Failed to write leapp answerfile: ' . $ini_obj->errstr ); - } - - return; -} - # 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) { diff --git a/lib/Elevate/Blockers/Databases.pm b/lib/Elevate/Blockers/Databases.pm index 35635b41..a2e51a70 100644 --- a/lib/Elevate/Blockers/Databases.pm +++ b/lib/Elevate/Blockers/Databases.pm @@ -13,6 +13,7 @@ Blockers for datbase: MySQL, PostgreSQL... use cPstrict; use Cpanel::OS (); +use Cpanel::Pkgr (); use Cpanel::Version::Tiny (); use Cpanel::JSON (); use Cpanel::SafeRun::Simple (); @@ -29,6 +30,7 @@ sub check ($self) { $ok = 0 unless $self->_blocker_acknowledge_postgresql_datadir; $ok = 0 unless $self->_blocker_old_mysql; $ok = 0 unless $self->_blocker_mysql_upgrade_in_progress; + $ok = 0 unless $self->_blocker_mysql_governor; $self->_warning_mysql_not_enabled(); return $ok; } @@ -185,6 +187,25 @@ sub _blocker_mysql_upgrade_in_progress ($self) { return 0; } +sub _blocker_mysql_governor ($self) { + + if ( Cpanel::Pkgr::is_installed('governor-mysql') ) { + return $self->has_blocker( <<~'EOS' ); +You have MySQL Governor installed. Upgrades with this software in place are not supported. +For more information regarding MySQL Governor, please review the documentation: + + https://docs.cloudlinux.com/shared/cloudlinux_os_components/#mysql-governor + +To remove MySQL Governor, execute the following command: + + /usr/share/lve/dbgovernor/mysqlgovernor.py --delete + +EOS + } + + return 0; +} + sub _warning_mysql_not_enabled ($self) { require Cpanel::Services::Enabled; my $enabled = Cpanel::Services::Enabled::is_enabled('mysql'); diff --git a/lib/Elevate/Blockers/Distros.pm b/lib/Elevate/Blockers/Distros.pm index 867b263a..91b2407a 100644 --- a/lib/Elevate/Blockers/Distros.pm +++ b/lib/Elevate/Blockers/Distros.pm @@ -18,12 +18,14 @@ use constant MINIMUM_CENTOS_7_SUPPORTED => 9; use parent qw{Elevate::Blockers::Base}; +use Elevate::OS (); + use Log::Log4perl qw(:easy); sub check ($self) { my @checks = qw{ - _blocker_is_non_centos7 + _blocker_os_is_not_supported _blocker_is_old_centos7 _blocker_is_experimental_os }; @@ -36,16 +38,17 @@ sub check ($self) { return 0; } -sub _blocker_is_non_centos7 ($self) { - unless ( Cpanel::OS::major() == 7 && Cpanel::OS::distro() eq 'centos' ) { - my $pretty_distro_name = $self->upgrade_to_pretty_name(); - return $self->has_blocker(qq[This script is only designed to upgrade CentOS 7 to $pretty_distro_name.]); +sub _blocker_os_is_not_supported ($self) { + unless ( Elevate::OS::is_supported() ) { + my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); + return $self->has_blocker(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); } return 0; } sub _blocker_is_old_centos7 ($self) { + if ( Cpanel::OS::minor() < MINIMUM_CENTOS_7_SUPPORTED ) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); return $self->has_blocker( @@ -70,8 +73,9 @@ sub _blocker_is_experimental_os ($self) { # We are OK if can_be_elevated or if sub bail_out_on_inappropriate_distro () { - if ( !( eval { Cpanel::OS::can_be_elevated() } // ( Cpanel::OS::distro() eq 'centos' && Cpanel::OS::major() == 7 ) ) ) { - FATAL(qq[This script is designed to only run on CentOS 7 servers.\n]); + unless ( Elevate::OS::is_supported() ) { + my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); + FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); exit 1; } diff --git a/lib/Elevate/Blockers/EA4.pm b/lib/Elevate/Blockers/EA4.pm index 2e365718..adb2dbc1 100644 --- a/lib/Elevate/Blockers/EA4.pm +++ b/lib/Elevate/Blockers/EA4.pm @@ -35,7 +35,6 @@ sub _blocker_ea4_profile ($self) { # perform an early backup so we can check the list of dropped packages my $pretty_distro_name = $self->upgrade_to_pretty_name(); - INFO("Checking EasyApache profile compatibility with $pretty_distro_name."); $self->cpev->component('EA4')->backup; # _backup_ea4_profile(); diff --git a/lib/Elevate/Blockers/Python.pm b/lib/Elevate/Blockers/Python.pm index fb68f51d..48a6cd59 100644 --- a/lib/Elevate/Blockers/Python.pm +++ b/lib/Elevate/Blockers/Python.pm @@ -14,9 +14,13 @@ use cPstrict; use parent qw{Elevate::Blockers::Base}; +use Elevate::OS (); + use Cpanel::Pkgr (); sub check ($self) { + return if Elevate::OS::leapp_can_handle_python36(); + my $pkg = Cpanel::Pkgr::what_provides('python36'); return unless $pkg && Cpanel::Pkgr::is_installed($pkg); return $self->has_blocker( <<~"END" ); diff --git a/lib/Elevate/Blockers/Repositories.pm b/lib/Elevate/Blockers/Repositories.pm index 4117e965..fe4890e5 100644 --- a/lib/Elevate/Blockers/Repositories.pm +++ b/lib/Elevate/Blockers/Repositories.pm @@ -16,6 +16,7 @@ use Cpanel::OS (); use Cpanel::JSON (); use Elevate::Constants (); +use Elevate::OS (); use parent qw{Elevate::Blockers::Base}; @@ -69,6 +70,22 @@ use constant VETTED_MYSQL_YUM_REPO_IDS => qw{ MariaDB106 }; +use constant VETTED_CLOUDLINUX_YUM_REPO => qw{ + cloudlinux + cloudlinux-base + cloudlinux-updates + cloudlinux-extras + cloudlinux-compat + cloudlinux-imunify360 + cl-ea4 + cloudlinux-ea4 + cloudlinux-ea4-rollout + cl-mysql + cl-mysql-meta + cloudlinux-elevate + cloudlinux-rollout +}; + use constant VETTED_YUM_REPO => qw{ base c7-media @@ -217,7 +234,10 @@ sub _check_yum_repos ($self) { $self->{_yum_repos_to_disable} = []; $self->{_yum_repos_unsupported_with_packages} = []; - my %vetted = map { $_ => 1 } VETTED_YUM_REPO; + my @vetted_repos = (VETTED_YUM_REPO); + push( @vetted_repos, VETTED_CLOUDLINUX_YUM_REPO ) if Elevate::OS::name() eq 'CloudLinux7'; + + my %vetted = map { $_ => 1 } @vetted_repos; my $repo_dir = Elevate::Constants::YUM_REPOS_D; @@ -244,8 +264,18 @@ sub _check_yum_repos ($self) { return unless length $current_repo_name; return unless $current_repo_enabled; + my $temp_current_repo_name = $current_repo_name; + + # ignore the number on rollout mirrors + # cloudlinux-rollout-1 becomes cloudlinux-rollout + # cloudlinux-ea4-1 becomes cloudlinux-ea4 + # cloudlinux-ea4-rollout-1 becomes cloudlinux-ea4-rollout + $current_repo_name = $1 if $current_repo_name =~ m/^(cloudlinux-(?:rollout|ea4)(?:-rollout)?)-[0-9]+$/; + my $is_vetted = $vetted{$current_repo_name} || $vetted{ lc $current_repo_name }; + $current_repo_name = $temp_current_repo_name; + if ( !$is_vetted ) { $status{'UNVETTED'} = 1; my @installed_packages = cpev::get_installed_rpms_in_repo($current_repo_name); diff --git a/lib/Elevate/Components/Base.pm b/lib/Elevate/Components/Base.pm index f1a996fd..8089327f 100644 --- a/lib/Elevate/Components/Base.pm +++ b/lib/Elevate/Components/Base.pm @@ -19,6 +19,8 @@ use Carp (); use Simple::Accessor qw( cpev rpm + yum + dnf ); use Log::Log4perl qw(:easy); @@ -52,6 +54,14 @@ sub _build_rpm ($self) { return Elevate::RPM->new( cpev => $self ); } +sub _build_yum ($self) { + return Elevate::YUM->new( cpev => $self ); +} + +sub _build_dnf ($self) { + return Elevate::DNF->new( cpev => $self ); +} + sub run_once ( $self, $subname ) { my $cpev = $self->cpev; diff --git a/lib/Elevate/Components/EA4.pm b/lib/Elevate/Components/EA4.pm index 8acf1234..3e377a80 100644 --- a/lib/Elevate/Components/EA4.pm +++ b/lib/Elevate/Components/EA4.pm @@ -13,7 +13,9 @@ Perform am EA4 backup pre-elevate then restore it after the elevation process. use cPstrict; use Elevate::Constants (); +use Elevate::OS (); use Elevate::RPM (); +use Elevate::YUM (); use Cwd (); use Log::Log4perl qw(:easy); @@ -73,7 +75,7 @@ sub post_leapp ($self) { sub _cleanup_rpm_db ($self) { # remove all ea- packages - $self->ssystem(q{/usr/bin/yum -y erase ea-*}); + $self->yum->remove('ea-*'); return; } @@ -134,8 +136,7 @@ sub _backup_ea4_profile ($self) { ## _backup_ea4_profile sub _get_ea4_profile ($self) { - # obs_project_aliases from /etc/cpanel/ea4/ea4-metainfo.json - my $ea_alias = $self->upgrade_to_rocky() ? 'CentOS_8' : 'AlmaLinux_8'; + my $ea_alias = Elevate::OS::ea_alias(); my @cmd = ( '/usr/local/bin/ea_current_to_profile', "--target-os=$ea_alias" ); diff --git a/lib/Elevate/Components/Grub2.pm b/lib/Elevate/Components/Grub2.pm index 524d6e85..6b4aabf4 100644 --- a/lib/Elevate/Components/Grub2.pm +++ b/lib/Elevate/Components/Grub2.pm @@ -28,10 +28,6 @@ use Elevate::Blockers (); use constant GRUB_EDITENV => '/usr/bin/grub2-editenv'; use constant GRUB_ENV_FILE => '/boot/grub2/grubenv'; -## -## Call early so we can use a blocker based on existing ea4 profile -## - sub pre_leapp ($self) { $self->run_once('_update_grub2_workaround_if_needed'); # required part diff --git a/lib/Elevate/Components/Imunify.pm b/lib/Elevate/Components/Imunify.pm index 2fefa95e..b4348e4d 100644 --- a/lib/Elevate/Components/Imunify.pm +++ b/lib/Elevate/Components/Imunify.pm @@ -15,6 +15,7 @@ use cPstrict; use Elevate::Constants (); use Elevate::Fetch (); use Elevate::Notify (); +use Elevate::OS (); use Cwd (); use Log::Log4perl qw(:easy); @@ -33,6 +34,8 @@ use constant IMUNIFY_LICENSE_BACKUP => Elevate::Constants::ELEVATE_BACKUP_DIR . sub pre_leapp ($self) { + return if Elevate::OS::leapp_can_handle_imunify(); + return unless $self->is_installed; $self->run_once("_capture_imunify_features"); @@ -44,6 +47,8 @@ sub pre_leapp ($self) { sub post_leapp ($self) { + return if Elevate::OS::leapp_can_handle_imunify(); + # order matters $self->run_once('_reinstall_imunify_360'); $self->run_once('_restore_imunify_features'); diff --git a/lib/Elevate/Components/KernelCare.pm b/lib/Elevate/Components/KernelCare.pm index 1103ad08..de8af141 100644 --- a/lib/Elevate/Components/KernelCare.pm +++ b/lib/Elevate/Components/KernelCare.pm @@ -13,6 +13,7 @@ Capture and reinstall KernelCare. use cPstrict; use Elevate::Constants (); +use Elevate::OS (); use Cwd (); use File::Copy (); @@ -23,6 +24,8 @@ use parent qw{Elevate::Components::Base}; sub pre_leapp ($self) { + return if Elevate::OS::leapp_can_handle_kernelcare(); + $self->run_once("_remove_kernelcare_if_needed"); return; @@ -30,6 +33,8 @@ sub pre_leapp ($self) { sub post_leapp ($self) { + return if Elevate::OS::leapp_can_handle_kernelcare(); + $self->run_once('_restore_kernelcare'); return; diff --git a/lib/Elevate/Components/Repositories.pm b/lib/Elevate/Components/Repositories.pm index 82bae165..8f6bd5ad 100644 --- a/lib/Elevate/Components/Repositories.pm +++ b/lib/Elevate/Components/Repositories.pm @@ -14,6 +14,8 @@ use cPstrict; use Elevate::Constants (); use Elevate::Blockers::Repositories (); +use Elevate::OS (); +use Elevate::RPM (); use Cpanel::SafeRun::Simple (); use Cwd (); @@ -24,6 +26,8 @@ use parent qw{Elevate::Components::Base}; sub pre_leapp ($self) { + $self->run_once("_disable_epel"); + $self->run_once("_disable_yum_plugin_fastestmirror"); $self->run_once("_disable_known_yum_repositories"); return; @@ -50,4 +54,25 @@ sub _disable_known_yum_repositories { return; } +sub _disable_yum_plugin_fastestmirror ($self) { + my $pkg = 'yum-plugin-fastestmirror'; + $self->_erase_package($pkg); + return; +} + +sub _disable_epel ($self) { + + return if Elevate::OS::leapp_can_handle_epel(); + + my $pkg = 'epel-release'; + $self->_erase_package($pkg); + return; +} + +sub _erase_package ( $self, $pkg ) { + return unless Cpanel::Pkgr::is_installed($pkg); + $self->rpm->remove_no_dependencies($pkg); + return; +} + 1; diff --git a/lib/Elevate/Components/RpmDB.pm b/lib/Elevate/Components/RpmDB.pm index 9fc4a7d4..35c4f725 100644 --- a/lib/Elevate/Components/RpmDB.pm +++ b/lib/Elevate/Components/RpmDB.pm @@ -13,12 +13,14 @@ Perform some maintenance on the RPM database. use cPstrict; use Elevate::Constants (); +use Elevate::DNF (); use Cwd (); use File::Copy (); use Log::Log4perl qw(:easy); -use Cpanel::Pkgr (); +use Cpanel::Pkgr (); +use Cpanel::Yum::Vars (); use parent qw{Elevate::Components::Base}; @@ -31,19 +33,40 @@ sub pre_leapp ($self) { 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 ); - } + # potential to remove other things, but the goal here to remove cpanel packages provided by rpm.versions + $self->rpm->remove_cpanel_arch_rpms(); return; } sub post_leapp ($self) { + + $self->run_once("_sysup"); + + return; +} + +sub _sysup ($self) { + Cpanel::Yum::Vars::install(); + $self->dnf->clean_all(); + + my $epel_url = 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm'; + + # no failures once already installed: no need to check for the epel-release version + $self->dnf->install_rpm_via_url($epel_url); + + $self->dnf->config_manager_enable('powertools'); + $self->dnf->config_manager_enable('epel'); + + # Break cpanel-perl (NOTE: This only works on perl 5.36) + $self->ssystem(qw{/usr/bin/rm -f /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/X/Tiny.pm}); + { + local $ENV{'CPANEL_BASE_INSTALL'} = 1; # Don't fix more than perl itself. + $self->ssystem(qw{/usr/local/cpanel/scripts/fix-cpanel-perl}); + } + $self->dnf->update_allow_raising( '--disablerepo', 'cpanel-plugins' ); + $self->ssystem_and_die(qw{/usr/local/cpanel/scripts/sysup}); + return; } diff --git a/lib/Elevate/DNF.pm b/lib/Elevate/DNF.pm new file mode 100644 index 00000000..e27c823d --- /dev/null +++ b/lib/Elevate/DNF.pm @@ -0,0 +1,41 @@ +package Elevate::DNF; + +=encoding utf-8 + +=head1 NAME + +Elevate::DNF + +Logic wrapping the 'dnf' system binary + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use parent qw{Elevate::YUM}; + +sub _build_pkgmgr { + return '/usr/bin/dnf'; +} + +sub config_manager_enable ( $self, $repo ) { + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem( $pkgmgr, 'config-manager', '--enable', $repo ); + + return; +} + +sub update_allow_raising ( $self, @args ) { + my $pkgmgr = $self->pkgmgr; + + my @additional_args = scalar @args ? @args : ''; + + $self->cpev->ssystem( $pkgmgr, '-y', '--allowerasing', @additional_args, 'update' ); + + return; +} + +1; diff --git a/lib/Elevate/Leapp.pm b/lib/Elevate/Leapp.pm new file mode 100644 index 00000000..ed3f5fc1 --- /dev/null +++ b/lib/Elevate/Leapp.pm @@ -0,0 +1,174 @@ +package Elevate::Leapp; + +=encoding utf-8 + +=head1 NAME + +Elevate::Leapp + +Object to install and execute the leapp script + +=cut + +use cPstrict; + +use Cpanel::JSON (); +use Cpanel::Pkgr (); + +use Elevate::OS (); +use Elevate::YUM (); + +use Config::Tiny (); + +use Log::Log4perl qw(:easy); + +use constant LEAPP_REPORT_JSON => q[/var/log/leapp/leapp-report.json]; +use constant LEAPP_REPORT_TXT => q[/var/log/leapp/leapp-report.txt]; + +use Simple::Accessor qw{ + cpev + yum +}; + +sub _build_cpev { + die q[Missing cpev]; +} + +sub _build_yum ($self) { + return Elevate::YUM->new( cpev => $self->cpev() ); +} + +sub install ($self) { + + unless ( Cpanel::Pkgr::is_installed('elevate-release') ) { + my $elevate_rpm_url = Elevate::OS::elevate_rpm_url(); + $self->yum->install_rpm_via_url($elevate_rpm_url); + } + + my $leapp_data_pkg = Elevate::OS::leapp_data_pkg(); + + unless ( Cpanel::Pkgr::is_installed('leapp-upgrade') && Cpanel::Pkgr::is_installed($leapp_data_pkg) ) { + $self->yum->install( 'leapp-upgrade', $leapp_data_pkg ); + } + + if ( Cpanel::Pkgr::is_installed('kernel-devel') ) { + $self->yum->remove('kernel-devel'); + } + + return; +} + +sub upgrade ($self) { + + return unless $self->cpev->should_run_leapp(); + + $self->cpev->run_once( + setup_answer_file => sub { + $self->setup_answer_file(); + }, + ); + + my $leapp_flag = Elevate::OS::leapp_flag(); + my $leapp_bin = '/usr/bin/leapp'; + my @leapp_args = ('upgrade'); + push( @leapp_args, $leapp_flag ) if $leapp_flag; + + INFO("Running leapp upgrade"); + + my $ok = eval { + local $ENV{LEAPP_OVL_SIZE} = cpev::read_stage_file('env')->{'LEAPP_OVL_SIZE'} || 3000; + $self->cpev->ssystem_and_die( { keep_env => 1 }, $leapp_bin, @leapp_args ); + 1; + }; + + return 1 if $ok; + + $self->_report_leapp_failure_and_die(); + return; +} + +sub _report_leapp_failure_and_die ($self) { + + my $msg = <<'EOS'; +The 'leapp upgrade' process failed. + +Please investigate, resolve then re-run the following command to continue the update: + + /scripts/elevate-cpanel --continue + +EOS + + my $leapp_json_report = LEAPP_REPORT_JSON; + if ( -e $leapp_json_report ) { + my $report = eval { Cpanel::JSON::LoadFile($leapp_json_report) } // {}; + + my $entries = $report->{entries}; + if ( ref $entries eq 'ARRAY' ) { + foreach my $e (@$entries) { + next unless ref $e && $e->{title} =~ qr{Missing.*answer}i; + + $msg .= $e->{summary} if $e->{summary}; + + if ( ref $e->{detail} ) { + my $d = $e->{detail}; + + if ( ref $d->{remediations} ) { + foreach my $remed ( $d->{remediations}->@* ) { + next unless $remed->{type} && $remed->{type} eq 'command'; + next unless ref $remed->{context}; + my @hint = $remed->{context}->@*; + next unless scalar @hint; + $hint[0] = q[/usr/bin/leapp] if $hint[0] && $hint[0] eq 'leapp'; + my $cmd = join( ' ', @hint ); + + $msg .= "\n\n"; + $msg .= <<"EOS"; +Consider running this command: + + $cmd +EOS + } + } + + } + + } + } + } + + if ( -e LEAPP_REPORT_TXT ) { + $msg .= qq[\nYou can read the full leapp report at: ] . LEAPP_REPORT_TXT; + } + + die qq[$msg\n]; + return; +} + +sub setup_answer_file ($self) { + my $leapp_dir = '/var/log/leapp'; + mkdir $leapp_dir unless -d $leapp_dir; + + my $answerfile_path = $leapp_dir . '/answerfile'; + system touch => $answerfile_path unless -e $answerfile_path; + + my $do_write; # no point in overwriting the file if nothing needs to change + + my $ini_obj = Config::Tiny->read( $answerfile_path, 'utf8' ); + LOGDIE( 'Failed to read leapp answerfile: ' . Config::Tiny->errstr ) unless $ini_obj; + + my $SECTION = 'remove_pam_pkcs11_module_check'; + + if ( not defined $ini_obj->{$SECTION}->{'confirm'} or $ini_obj->{$SECTION}->{'confirm'} ne 'True' ) { + $do_write = 1; + $ini_obj->{$SECTION}->{'confirm'} = 'True'; + } + + if ($do_write) { + $ini_obj->write( $answerfile_path, 'utf8' ) # + or LOGDIE( 'Failed to write leapp answerfile: ' . $ini_obj->errstr ); + } + + return; +} + +1; diff --git a/lib/Elevate/OS.pm b/lib/Elevate/OS.pm new file mode 100644 index 00000000..f790e758 --- /dev/null +++ b/lib/Elevate/OS.pm @@ -0,0 +1,155 @@ +package Elevate::OS; + +=encoding utf-8 + +=head1 NAME + +Elevate::OS + +Abstract interface to the OS to obviate the need for if-this-os-do-this-elsif-elsif-else tech debt + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use Elevate::OS::CentOS7; +use Elevate::OS::CloudLinux7; + +use constant SUPPORTED_DISTROS => qw{ + CentOS7 + CloudLinux7 +}; + +use constant PRETTY_SUPPORTED_DISTROS => ( + 'CentOS 7', + 'CloudLinux 7', +); + +use constant AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7 => qw{ + alma + almalinux + rocky + rockylinux +}; + +use constant AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7 => qw{ + cloud + cloudlinux +}; + +our $OS; + +sub factory { + my $distro_with_version = cpev::read_stage_file( 'upgrade_from', '' ); + + my $distro; + my $major; + if ( !$distro_with_version ) { + $distro = Cpanel::OS::distro(); + $distro = 'CentOS' if $distro eq 'centos'; + $distro = 'CloudLinux' if $distro eq 'cloudlinux'; + $major = Cpanel::OS::major(); + $distro_with_version = $distro . $major; + } + + FATAL("Attempted to get factory for unsupported OS: $distro $major") unless grep { $_ eq $distro_with_version } SUPPORTED_DISTROS; + + my $pkg = "Elevate::OS::" . $distro_with_version; + return $pkg->new; +} + +sub instance { + $OS //= factory(); + + return $OS; +} + +sub is_supported () { + return eval { instance(); 1; } ? 1 : 0; +} + +sub get_supported_distros () { + return PRETTY_SUPPORTED_DISTROS; +} + +sub check_for_old_centos7 () { + return instance()->check_for_old_centos7(); +} + +sub default_upgrade_to () { + return instance()->default_upgrade_to(); +} + +sub get_available_upgrade_paths { + my $name = instance()->name(); + + if ( $name eq 'CentOS7' ) { + return AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; + } + elsif ( $name eq 'CloudLinux7' ) { + return AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; + } + + return; +} + +sub name () { + return instance()->name(); +} + +sub pretty_name () { + return instance()->pretty_name(); +} + +sub can_upgrade_to ($flavor) { + my $name = instance()->name(); + + if ( $name eq 'CentOS7' ) { + return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; + } + elsif ( $name eq 'CloudLinux7' ) { + return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; + } + + return 0; +} + +sub leapp_can_handle_epel () { + return instance()->leapp_can_handle_epel(); +} + +sub leapp_can_handle_imunify () { + return instance()->leapp_can_handle_imunify(); +} + +sub leapp_can_handle_kernelcare () { + return instance()->leapp_can_handle_kernelcare(); +} + +sub ea_alias () { + return instance()->ea_alias(); +} + +sub elevate_rpm_url () { + return instance()->elevate_rpm_url(); +} + +sub leapp_data_pkg () { + return instance()->leapp_data_pkg(); +} + +sub upgrade_to () { + return instance()->upgrade_to(); +} + +sub leapp_flag () { + return instance()->leapp_flag(); +} + +sub leapp_can_handle_python36 () { + return instance()->leapp_can_handle_python36(); +} + +1; diff --git a/lib/Elevate/OS/Base.pm b/lib/Elevate/OS/Base.pm new file mode 100644 index 00000000..4b326da9 --- /dev/null +++ b/lib/Elevate/OS/Base.pm @@ -0,0 +1,79 @@ +package Elevate::OS::Base; + +=encoding utf-8 + +=head1 NAME + +Elevate::OS::Base + +This is a base class currently used by Elevate::OS::* + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use Simple::Accessor qw{ + ea_alias + elevate_rpm_url + default_upgrade_to + leapp_can_handle_epel + leapp_can_handle_imunify + leapp_can_handle_kernelcare + leapp_can_handle_python36 + leapp_data_pkg + leapp_flag + name + pretty_name + upgrade_to +}; + +# NOTE: AlmaLinux_8 is just an alias for CentOS_8 so it really doesn't matter +# which of the two is used +sub _build_ea_alias ($self) { + return 'CentOS_8'; +} + +sub _build_elevate_rpm_url ($self) { + die "subclass must implement elevate_rpm_url\n"; +} + +sub _build_default_upgrade_to ($self) { + die "subclass must implement default_upgrade_to\n"; +} + +sub _build_leapp_can_handle_epel ($self) { + return 0; +} + +sub _build_leapp_can_handle_imunify ($self) { + return 0; +} + +sub _build_leapp_can_handle_kernelcare ($self) { + return 0; +} + +sub _build_leapp_can_handle_python36 ($self) { + return 0; +} + +sub _build_leapp_data_pkg ($self) { + die "subclass must implement leapp_data_pkg\n"; +} + +sub _build_name ($self) { + die "subclass must implement name\n"; +} + +sub _build_pretty_name ($self) { + die "subclass must implment pretty_name\n"; +} + +sub _build_upgrade_to ($self) { + my $default = $self->default_upgrade_to(); + return cpev::read_stage_file( 'upgrade_to', $default ); +} + +1; diff --git a/lib/Elevate/OS/CentOS7.pm b/lib/Elevate/OS/CentOS7.pm new file mode 100644 index 00000000..f5aedfec --- /dev/null +++ b/lib/Elevate/OS/CentOS7.pm @@ -0,0 +1,38 @@ +package Elevate::OS::CentOS7; + +=encoding utf-8 + +=head1 NAME + +Elevate::OS::CentOS7 - CentOS7 custom values + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use parent 'Elevate::OS::Base'; + +sub _build_elevate_rpm_url ($self) { + return 'https://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm'; +} + +sub _build_default_upgrade_to ($self) { + return 'almalinux'; +} + +sub _build_leapp_data_pkg ($self) { + my $upgrade_to = $self->upgrade_to(); + return $upgrade_to =~ m/^rocky/ai ? 'leapp-data-rocky' : 'leapp-data-almalinux'; +} + +sub _build_name ($self) { + return 'CentOS7'; +} + +sub _build_pretty_name ($self) { + return 'CentOS 7'; +} + +1; diff --git a/lib/Elevate/OS/CloudLinux7.pm b/lib/Elevate/OS/CloudLinux7.pm new file mode 100644 index 00000000..278989ce --- /dev/null +++ b/lib/Elevate/OS/CloudLinux7.pm @@ -0,0 +1,61 @@ +package Elevate::OS::CloudLinux7; + +=encoding utf-8 + +=head1 NAME + +Elevate::OS::CloudLinux7 - CloudLinux7 custom values + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use parent 'Elevate::OS::Base'; + +sub _build_ea_alias ($self) { + return 'CloudLinux_8'; +} + +sub _build_elevate_rpm_url ($self) { + return 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; +} + +sub _build_default_upgrade_to ($self) { + return 'CloudLinux'; +} + +sub _build_leapp_can_handle_epel ($self) { + return 1; +} + +sub _build_leapp_can_handle_imunify ($self) { + return 1; +} + +sub _build_leapp_can_handle_kernelcare ($self) { + return 1; +} + +sub _build_leapp_can_handle_python36 ($self) { + return 1; +} + +sub _build_leapp_data_pkg ($self) { + return 'leapp-data-cloudlinux'; +} + +sub _build_leapp_flag ($self) { + return '--nowarn'; +} + +sub _build_name ($self) { + return 'CloudLinux7'; +} + +sub _build_pretty_name ($self) { + return 'CloudLinux 7'; +} + +1; diff --git a/lib/Elevate/RPM.pm b/lib/Elevate/RPM.pm index 2105c1fb..e8eae60a 100644 --- a/lib/Elevate/RPM.pm +++ b/lib/Elevate/RPM.pm @@ -18,6 +18,8 @@ use Simple::Accessor qw{ cpev }; +our $rpm = '/usr/bin/rpm'; + sub _build_cpev { die q[Missing cpev]; } @@ -35,7 +37,7 @@ sub _get_config_files ( $self, $pkgs ) { my %config_files; foreach my $pkg (@$pkgs) { - my $out = $self->cpev->ssystem_capture_output( '/usr/bin/rpm', '-qc', $pkg ) || {}; + my $out = $self->cpev->ssystem_capture_output( $rpm, '-qc', $pkg ) || {}; if ( $out->{status} != 0 ) { @@ -80,4 +82,35 @@ sub restore_config_files ( $self, @files ) { return; } +sub remove_no_dependencies ( $self, $pkg ) { + $self->cpev->ssystem( $rpm, '-e', '--nodeps', $pkg ); + return; +} + +sub remove_no_dependencies_and_justdb ( $self, $pkg ) { + $self->cpev->ssystem( $rpm, '-e', '--nodeps', '--justdb', $pkg ); + return; +} + +sub get_installed_rpms ($self) { + my $out = $self->cpev->ssystem_capture_output( $rpm, '-qa' ); + return @{ $out->{stdout} }; +} + +sub get_cpanel_arch_rpms ($self) { + my @installed_rpms = $self->get_installed_rpms(); + my @cpanel_arch_rpms = grep { $_ =~ m/^cpanel-.*\.x86_64$/ } @installed_rpms; + return @cpanel_arch_rpms; +} + +sub remove_cpanel_arch_rpms ($self) { + my @rpms_to_remove = $self->get_cpanel_arch_rpms(); + + foreach my $rpm (@rpms_to_remove) { + $self->remove_no_dependencies_and_justdb($rpm); + } + + return; +} + 1; diff --git a/lib/Elevate/YUM.pm b/lib/Elevate/YUM.pm new file mode 100644 index 00000000..ddd5b26c --- /dev/null +++ b/lib/Elevate/YUM.pm @@ -0,0 +1,66 @@ +package Elevate::YUM; + +=encoding utf-8 + +=head1 NAME + +Elevate::YUM + +Logic wrapping the 'yum' system binary + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use Simple::Accessor qw{ + cpev + pkgmgr +}; + +sub _build_cpev { + die q[Missing cpev]; +} + +sub _build_pkgmgr { + return '/usr/bin/yum'; +} + +sub remove ( $self, @pkgs ) { + return unless scalar @pkgs; + + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem_and_die( $pkgmgr, '-y', 'remove', @pkgs ); + + return; +} + +sub clean_all ($self) { + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem( $pkgmgr, 'clean', 'all' ); + + return; +} + +sub install_rpm_via_url ( $self, $rpm_url ) { + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem_and_die( $pkgmgr, '-y', 'install', $rpm_url ); + + return; +} + +sub install ( $self, @pkgs ) { + return unless scalar @pkgs; + + my $pkgmgr = $self->pkgmgr; + + $self->cpev->ssystem_and_die( $pkgmgr, '-y', 'install', @pkgs ); + + return; +} + +1; diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index f9ed2f0a..97a406ae 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -35,38 +35,50 @@ package cpev; =head1 DESCRIPTION -Helps to upgrade CentOS 7 cPanel servers to AlmaLinux 8 or Rocky Linux 8. +Wrapper around the ELevate project which is designed to enable migrations +between major version of RHELĀ® derivatives. + +Currently supported upgrade paths: + +CentOS 7 => AlmaLinux 8 +CentOS 7 => Rocky Linux 8 +CloudLinux 7 => CloudLinux 8 =head1 SYNOPSIS /scripts/elevate-cpanel [OPTIONS] Optional: - --start Start the conversion process - --continue Continue the conversion: retry the last step - --check[=BLOCKER_FILE] Check if your system has any known blockers to upgrade. - --log Show the current elevation log - --status Check the current elevation status - --clean Cleanup scripts and files created by elevate-cpanel - --upgrade-to=[rocky|almalinux] Update to AlmaLinux 8 or Rocky Linux 8 - [default to 'almalinux'] - --non-interactive Skip the yes/no prompt before proceeding with the upgrade. + --start Start the conversion process + --continue Continue the conversion: retry the last step + --check[=BLOCKER_FILE] Check if your system has any known blockers to upgrade. + --log Show the current elevation log + --status Check the current elevation status + --clean Cleanup scripts and files created by elevate-cpanel + --upgrade-to=[rocky|almalinux|cloudlinux] Update to AlmaLinux 8 or Rocky Linux 8 + [Servers running CentOS 7 will default to 'almalinux'] + [Servers running CloudLinux 7 will default to 'cloudlinux'] + + NOTE: servers running CentOS 7 can only upgrade to almalinux or rocky + servers running CloudLinux 7 can only upgrade to cloudlinux + + --non-interactive Skip the yes/no prompt before proceeding with the upgrade. - --update Instruct the script to replace itself on disk with a downloaded copy of the latest version. - --version Print the version number and exit. + --update Instruct the script to replace itself on disk with a downloaded copy of the latest version. + --version Print the version number and exit. - --skip-elevate-version-check Skip the check for whether this script is up to date. - --skip-cpanel-version-check Skip the check for whether cPanel is up to date. - This option is intended only for testing! + --skip-elevate-version-check Skip the check for whether this script is up to date. + --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 + --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 - --manual-reboots The script will stop and require the user to reboot manually rather than - automatically rebooting when reboots are needed + --manual-reboots The script will stop and require the user to reboot manually rather than + automatically rebooting when reboots are needed - --help Display this documentation. + --help Display this documentation. =head1 COMMON USAGE @@ -76,13 +88,17 @@ Helps to upgrade CentOS 7 cPanel servers to AlmaLinux 8 or Rocky Linux 8. You can start an elevation update by running: - # AlmaLinux 8 update + # AlmaLinux 8 update from CentOS 7 /scripts/elevate-cpanel --start /scripts/elevate-cpanel --start --upgrade-to=almalinux - # Rocky Linux 8 update + # Rocky Linux 8 update from CentOS 7 /scripts/elevate-cpanel --start --upgrade-to=rocky + # CloudLinux 8 update from CloudLinux 7 + /scripts/elevate-cpanel --start + /scripts/elevate-cpanel --start --upgrade-to=cloudlinux + =item Start an installation and skip the confirmation prompt By default, you will be asked if you wish to proceed with the upgrade. @@ -96,13 +112,17 @@ If you wish to skip this prompt (by assuming yes): You can check if your server is compatible with the upgrade process without starting an upgrade process. - # Check AlmaLinux 8 update + # Check AlmaLinux 8 update from CentOS 7 /scripts/elevate-cpanel --check /scripts/elevate-cpanel --check --upgrade-to=almalinux - # Check Rocky Linux 8 update + # Check Rocky Linux 8 update from CentOS 7 /scripts/elevate-cpanel --check --upgrade-to=rocky + # Check CloudLinux 8 update from CloudLinux 7 + /scripts/elevate-cpanel --check + /scripts/elevate-cpanel --check --upgrade-to=cloudlinux + This will also save a JSON representation of the blockers to a file, C by default, but passing an optional argument will use the file given instead: @@ -142,7 +162,7 @@ the update process by running: =head3 Using an alternative tool to upgrade your distro -By default, the elevate script runs the [leapp process](https://almalinux.org/elevate/) +By default, the elevate script runs the L 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. @@ -174,8 +194,7 @@ NOTE: `--no-leapp` is not required for helper commands like `--continue` or `--s =head1 WARNINGS -The elevation process from CentOS 7 to AlmaLinux 8 or Rocky Linux 8 distribution -is not a risk free update. +The elevation process to perform a major OS upgrade is not a risk free update. Depending on the state of your current distribution multiple errors can occur. We recommend updating your system to the last upstream state before starting. @@ -208,7 +227,6 @@ BEGIN { use Log::Log4perl qw(:easy); use Config; -use Config::Tiny (); use Carp (); use Errno (); use File::Basename (); @@ -284,7 +302,14 @@ use Elevate::Components::RmMod (); use Elevate::Components::WPToolkit (); use Elevate::Components::SSH (); +# - fatpack OS +use Elevate::OS (); +use Elevate::OS::Base (); +use Elevate::OS::CentOS7 (); +use Elevate::OS::CloudLinux7 (); + use Elevate::Fetch (); +use Elevate::Leapp (); use Elevate::Logger (); use Elevate::Motd (); use Elevate::Notify (); @@ -294,6 +319,8 @@ use Elevate::Script (); use Elevate::Service (); use Elevate::SystemctlService (); use Elevate::Usage (); +use Elevate::DNF (); +use Elevate::YUM (); #< 1; @@ -307,9 +334,6 @@ use constant VALID_STAGES => 5; use constant IGNORE_OUTDATED_SERVICES_FILE => q[/etc/cpanel/local/ignore_outdated_services]; -use constant LEAPP_REPORT_JSON => q[/var/log/leapp/leapp-report.json]; -use constant LEAPP_REPORT_TXT => q[/var/log/leapp/leapp-report.txt]; - use constant NOC_RECOMMENDATIONS_TOUCH_FILE => q[/var/cpanel/elevate-noc-recommendations]; # XXX TODO verify that imunify reponames are in fact correct. @@ -319,8 +343,9 @@ 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 UPGRADE_TO_ALMALINUX => q[AlmaLinux]; +use constant UPGRADE_TO_ROCKY => q[Rocky]; +use constant UPGRADE_TO_CLOUDLINUX => q[CloudLinux]; use constant PAUSE_ELEVATE_TOUCHFILE => q[/waiting_for_distro_upgrade]; @@ -328,6 +353,7 @@ use Simple::Accessor qw{ service script blockers + leapp }; # after Simple::Accessor @@ -350,6 +376,12 @@ sub _build_blockers ($self) { return Elevate::Blockers->new( cpev => $self ); } +sub _build_leapp ($self) { + + # FIXME weaken + return Elevate::Leapp->new( cpev => $self ); +} + sub _build_script ($self) { return Elevate::Script->new; } @@ -379,8 +411,6 @@ sub run ( $pkg, @args ) { return $self->do_update(); } - $self->_parse_opt_upgrade_to(); - if ( $self->getopt('start') ) { die qq[Unsupported option with --start\n] if $self->getopt('continue') || $self->getopt('service'); return 1 if $self->start(); @@ -440,17 +470,37 @@ sub get_blocker ( $self, $name ) { # helper for tests sub _parse_opt_upgrade_to ($self) { - return unless my $flavor = $self->getopt('upgrade-to'); + my $flavor = $self->getopt('upgrade-to'); if ( !defined $self->getopt('start') && !defined $self->getopt('check') ) { die qq[--upgrade-to option is only supported with --start or --check\n]; } + + Elevate::Blockers::Distros::bail_out_on_inappropriate_distro(); + + $flavor ||= Elevate::OS::default_upgrade_to(); + $flavor = lc $flavor; - if ( $flavor !~ m{^(?:almalinux|alma|rocky)$} ) { - die qq[Invalid --upgrade_to value '$flavor'. Only 'almalinux' or 'rocky' are supported.\n]; + if ( !Elevate::OS::can_upgrade_to($flavor) ) { + my @available_flavors = Elevate::OS::get_available_upgrade_paths(); + my $af = join( "\n", @available_flavors ); + die qq[The current OS can only upgrade to the following flavors:\n\n$af\n]; } - $self->{upgrade_to} = $flavor eq 'rocky' ? UPGRADE_TO_ROCKY : UPGRADE_TO_ALMALINUX; + $self->_set_upgrade_to($flavor); + + return; +} + +sub _set_upgrade_to ( $self, $flavor ) { + my $upgrade_to = UPGRADE_TO_ROCKY if $flavor =~ m/^rocky/a; + + $upgrade_to = UPGRADE_TO_ALMALINUX if $flavor =~ m/^alma/a; + $upgrade_to = UPGRADE_TO_CLOUDLINUX if $flavor =~ m/^cloud/a; + + die qq['$flavor' is not a valid path to upgrade to\n] unless $upgrade_to; + + $self->{upgrade_to} = $upgrade_to; return; } @@ -486,16 +536,20 @@ sub do_update ($self) { } sub upgrade_to ($self) { # main helper to know the upgrade_to distro - return $self->{upgrade_to} if $self->{upgrade_to}; - return read_stage_file( 'upgrade_to', UPGRADE_TO_ALMALINUX ); # default to AlmaLinux + return $self->{upgrade_to} ? $self->{upgrade_to} : Elevate::OS::upgrade_to(); } sub upgrade_to_rocky ($self) { return $self->upgrade_to() eq UPGRADE_TO_ROCKY; } +sub upgrade_to_cloudlinux ($self) { + return $self->upgrade_to() eq UPGRADE_TO_CLOUDLINUX; +} + sub upgrade_to_pretty_name ($self) { # used by output messages return q[Rocky Linux 8] if $self->upgrade_to_rocky; + return q[CloudLinux 8] if $self->upgrade_to_cloudlinux; return q[AlmaLinux 8]; } @@ -523,7 +577,7 @@ sub monitor_upgrade ($self) { } sub start ($self) { - Elevate::Blockers::Distros::bail_out_on_inappropriate_distro(); + $self->_parse_opt_upgrade_to(); my $stage = get_stage(); if ( $stage != 0 ) { my $header; @@ -790,10 +844,11 @@ sub check_status ($self) { sub _notify_success ($self) { + my $upgrade_from_name = Elevate::OS::pretty_name(); my $pretty_distro_name = $self->upgrade_to_pretty_name(); my $msg = <<"EOS"; -The cPanel & WHM server has completed the elevation process from CentOS 7 to $pretty_distro_name. +The cPanel & WHM server has completed the elevation process from $upgrade_from_name to $pretty_distro_name. EOS if ( my $warnings = read_stage_file( 'final_notifications', [] ) ) { @@ -954,6 +1009,11 @@ sub run_stage_1 ($self) { # store 'upgrade_to' early so later stages can access it update_stage_file( { upgrade_to => $self->upgrade_to } ); + # store 'upgrade_from' early so that Elevate::OS can access it + # Elevate::OS is based on the OS we are upgrading from since the information + # that it provides is mostly based on what leapp can do when upgrading from an OS + update_stage_file( { upgrade_from => Elevate::OS::name() } ); + return $self->service->install(); } @@ -992,15 +1052,16 @@ sub run_stage_2 ($self) { =head2 run_stage_3 -Setup the AlmaLinux elevate-release-latest-el7 repo and install leapp packages. -Prepare the cPanel packages for the update. +Setup the elevate-release-latest-el7 repo from the appropriate fork and install +leapp Packages. Prepare the cPnael packages for the update. Remove some known conflicting packages. (Reinstall later). Provide answers to a few leapp questions. Attempt to perform the leapp upgrade itself. -In case of failure you probably want to reply to a few extra questions or remove some conflicting packages. +In case of failure you probably want to reply to a few extra questions or remove +some conflicting packages. =cut @@ -1012,8 +1073,13 @@ sub run_stage_3 ($self) { return $self->_request_to_upgrade_distro_manually(); } - $self->run_once('_install_leapp'); - $self->_do_leapp_upgrade(); + $self->run_once( + install_leapp => sub { + $self->leapp->install(); + }, + ); + + $self->leapp->upgrade(); WARN(<<~'EOS'); Rebooting for distro upgrade. This will take over 10 minutes to run. @@ -1025,27 +1091,6 @@ sub run_stage_3 ($self) { # 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; @@ -1067,7 +1112,7 @@ EOS =head2 run_stage_4 -At this stage we should now run Alamalinux 8. +At this stage, we should now be run the upgraded OS (i.e. AlmaLinux 8). Update cPanel product for the new distro. Restore removed packages during the previous stage. @@ -1106,29 +1151,7 @@ sub run_stage_4 ($self) { $stash->{stage4} //= {}; # run once each blocks - $self->run_once( - sysup => sub { - Cpanel::Yum::Vars::install(); - $self->ssystem_and_die(qw{/usr/bin/dnf clean all}); - - # no failures once already installed: no need to check for the epel-release version - $self->ssystem_and_die(qw{/usr/bin/dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm}); - - $self->ssystem(qw{/usr/bin/dnf config-manager --enable powertools}); - $self->ssystem(qw{/usr/bin/dnf config-manager --enable epel}); - - # Break cpanel-perl (NOTE: This only works on perl 5.36) - $self->ssystem(qw{/usr/bin/rm -f /usr/local/cpanel/3rdparty/perl/536/cpanel-lib/X/Tiny.pm}); - { - local $ENV{'CPANEL_BASE_INSTALL'} = 1; # Don't fix more than perl itself. - $self->ssystem(qw{/usr/local/cpanel/scripts/fix-cpanel-perl}); - } - $self->ssystem(qw{/usr/bin/dnf -y --allowerasing --disablerepo cpanel-plugins update}); - $self->ssystem_and_die(qw{/usr/local/cpanel/scripts/sysup}); - - return; - } - ); + $self->run_component_once( 'RpmDB', => 'post_leapp' ); $self->run_once( restore_cpanel_services => sub { @@ -1162,7 +1185,7 @@ sub run_stage_4 ($self) { $self->post_leapp_update_restore(); my @known_modules_that_dont_convert = qw{libtermkey msgpack btrfs-progs elevate-release - leapp leapp-data-almalinux leapp-data-rocky leapp-upgrade-el7toel8 + leapp leapp-data-almalinux leapp-data-rocky leapp-data-cloudlinux leapp-upgrade-el7toel8 python2-leapp alt-pcre802 alt-pcre802-devel}; my @to_remove = grep { Cpanel::Pkgr::is_installed($_) } @known_modules_that_dont_convert; @@ -1187,7 +1210,7 @@ The elevate-cpanel service is now removed. =cut sub run_stage_5 ($self) { - return 1 if $self->post_upgrade_check(); + return 0 if $self->post_upgrade_check(); # we cannot stop the service ( ourself ) $self->service->disable; @@ -1251,14 +1274,6 @@ sub elevation_success_marker ($self) { return; } -=pod - -Example: - - $self->run_component_once( Imunify => 'backup' ); - -=cut - sub run_component_once ( $self, $name, $function ) { my $component = $self->component($name); @@ -1440,76 +1455,6 @@ sub disable_all_cpanel_services ($self) { return; } -sub _do_leapp_upgrade ($self) { - - return unless $self->should_run_leapp(); - - $self->run_once('setup_answer_file'); - - INFO("Running leapp upgrade"); - - my $ok = eval { - local $ENV{LEAPP_OVL_SIZE} = read_stage_file('env')->{'LEAPP_OVL_SIZE'} || 3000; - $self->ssystem_and_die( { keep_env => 1 }, qw{/usr/bin/leapp upgrade} ); - 1; - }; - - return 1 if $ok; - - my $msg = <<'EOS'; -The 'leapp upgrade' process failed. - -Please investigate, resolve then re-run the following command to continue the update: - - /scripts/elevate-cpanel --continue - -EOS - - my $leapp_json_report = LEAPP_REPORT_JSON; - if ( -e $leapp_json_report ) { - my $report = eval { Cpanel::JSON::LoadFile($leapp_json_report) } // {}; - - my $entries = $report->{entries}; - if ( ref $entries eq 'ARRAY' ) { - foreach my $e (@$entries) { - next unless ref $e && $e->{title} =~ qr{Missing.*answer}i; - - $msg .= $e->{summary} if $e->{summary}; - - if ( ref $e->{detail} ) { - my $d = $e->{detail}; - - if ( ref $d->{remediations} ) { - foreach my $remed ( $d->{remediations}->@* ) { - next unless $remed->{type} && $remed->{type} eq 'command'; - next unless ref $remed->{context}; - my @hint = $remed->{context}->@*; - next unless scalar @hint; - $hint[0] = q[/usr/bin/leapp] if $hint[0] && $hint[0] eq 'leapp'; - my $cmd = join( ' ', @hint ); - - $msg .= "\n\n"; - $msg .= <<"EOS"; -Consider running this command: - - $cmd -EOS - } - } - - } - - } - } - } - - if ( -e LEAPP_REPORT_TXT ) { - $msg .= qq[\nYou can read the full leapp report at: ] . LEAPP_REPORT_TXT; - } - - die qq[$msg\n]; -} - # remove and store sub run_final_components_pre_leapp ($self) { @@ -1664,12 +1609,12 @@ sub remove_rpms_from_repos ( $self, @repo_list ) { sub post_upgrade_check ($self) { - my $expect_distro = $self->upgrade_to_rocky() ? 'rocky' : 'almalinux'; + my $expect_distro = Elevate::OS::upgrade_to(); + $expect_distro = lc $expect_distro; unless ( Cpanel::OS::major() == 8 && Cpanel::OS::distro() eq $expect_distro ) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); - FATAL("Your distro does not looks like $pretty_distro_name."); - return 1; + die "Your distro does not look like $pretty_distro_name.\n"; } # call a cpanel binary @@ -1678,40 +1623,6 @@ 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; - - my $answerfile_path = $leapp_dir . '/answerfile'; - system touch => $answerfile_path unless -e $answerfile_path; - - my $do_write; # no point in overwriting the file if nothing needs to change - - my $ini_obj = Config::Tiny->read( $answerfile_path, 'utf8' ); - LOGDIE( 'Failed to read leapp answerfile: ' . Config::Tiny->errstr ) unless $ini_obj; - - my $SECTION = 'remove_pam_pkcs11_module_check'; - - if ( not defined $ini_obj->{$SECTION}->{'confirm'} or $ini_obj->{$SECTION}->{'confirm'} ne 'True' ) { - $do_write = 1; - $ini_obj->{$SECTION}->{'confirm'} = 'True'; - } - - if ($do_write) { - $ini_obj->write( $answerfile_path, 'utf8' ) # - or LOGDIE( 'Failed to write leapp answerfile: ' . $ini_obj->errstr ); - } - - return; -} - # 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) { diff --git a/t/blocker-Databases.t b/t/blocker-Databases.t index 07fcf36b..34f27bec 100644 --- a/t/blocker-Databases.t +++ b/t/blocker-Databases.t @@ -42,76 +42,82 @@ my $mock_elevate = Test::MockFile->file('/var/cpanel/elevate'); } { - is( - $db->_blocker_old_mysql('5.7'), - { - id => q[Elevate::Blockers::Databases::_blocker_old_mysql], - msg => <<~'EOS', + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $expected_target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + + is( + $db->_blocker_old_mysql('5.7'), + { + id => q[Elevate::Blockers::Databases::_blocker_old_mysql], + msg => <<~"EOS", You are using MySQL 5.7 server. - This version is not available for AlmaLinux 8. + This version is not available for $expected_target_os. You first need to update your MySQL server to 8.0 or later. You can update to version 8.0 using the following command: /usr/local/cpanel/bin/whmapi1 start_background_mysql_upgrade version=8.0 - Once the MySQL upgrade is finished, you can then retry to elevate to AlmaLinux 8. + Once the MySQL upgrade is finished, you can then retry to elevate to $expected_target_os. EOS - }, - 'MySQL 5.7 is a blocker.' - ); - - local $Cpanel::Version::Tiny::major_version = 108; - is( - $db->_blocker_old_mysql('10.1'), - { - id => q[Elevate::Blockers::Databases::_blocker_old_mysql], - msg => <<~'EOS', - You are using MariaDB server 10.1, this version is not available for AlmaLinux 8. + }, + 'MySQL 5.7 is a blocker.' + ); + + local $Cpanel::Version::Tiny::major_version = 108; + is( + $db->_blocker_old_mysql('10.1'), + { + id => q[Elevate::Blockers::Databases::_blocker_old_mysql], + msg => <<~"EOS", + You are using MariaDB server 10.1, this version is not available for $expected_target_os. You first need to update MariaDB server to 10.3 or later. You can update to version 10.3 using the following command: /usr/local/cpanel/bin/whmapi1 start_background_mysql_upgrade version=10.3 - Once the MariaDB upgrade is finished, you can then retry to elevate to AlmaLinux 8. + Once the MariaDB upgrade is finished, you can then retry to elevate to $expected_target_os. EOS - }, - 'Maria 10.1 on 108 is a blocker.' - ); - - $Cpanel::Version::Tiny::major_version = 110; - is( - $db->_blocker_old_mysql('10.2'), - { - id => q[Elevate::Blockers::Databases::_blocker_old_mysql], - msg => <<~'EOS', - You are using MariaDB server 10.2, this version is not available for AlmaLinux 8. + }, + 'Maria 10.1 on 108 is a blocker.' + ); + + $Cpanel::Version::Tiny::major_version = 110; + is( + $db->_blocker_old_mysql('10.2'), + { + id => q[Elevate::Blockers::Databases::_blocker_old_mysql], + msg => <<~"EOS", + You are using MariaDB server 10.2, this version is not available for $expected_target_os. You first need to update MariaDB server to 10.5 or later. You can update to version 10.5 using the following command: /usr/local/cpanel/bin/whmapi1 start_background_mysql_upgrade version=10.5 - Once the MariaDB upgrade is finished, you can then retry to elevate to AlmaLinux 8. + Once the MariaDB upgrade is finished, you can then retry to elevate to $expected_target_os. EOS - }, - 'Maria 10.2 on 110 is a blocker.' - ); - - is( - $db->_blocker_old_mysql('4.2'), - { - id => q[Elevate::Blockers::Databases::_blocker_old_mysql], - msg => <<~'EOS', - We do not know how to upgrade to AlmaLinux 8 with MySQL version 4.2. + }, + 'Maria 10.2 on 110 is a blocker.' + ); + + is( + $db->_blocker_old_mysql('4.2'), + { + id => q[Elevate::Blockers::Databases::_blocker_old_mysql], + msg => <<~"EOS", + We do not know how to upgrade to $expected_target_os with MySQL version 4.2. Please upgrade your MySQL server to one of the supported versions before running elevate. Supported MySQL server versions are: 8.0, 10.3, 10.4, 10.5, 10.6 EOS - }, - 'Maria 10.2 on 110 is a blocker.' - ); + }, + 'Maria 10.2 on 110 is a blocker.' + ); + } my $stash = undef; $cpev_mock->redefine( @@ -135,25 +141,31 @@ my $mock_elevate = Test::MockFile->file('/var/cpanel/elevate'); clear_messages_seen(); - my $pkgr_mock = Test::MockModule->new('Cpanel::Pkgr'); - my %installed = ( 'cpanel-ccs-calendarserver' => 9.2, 'postgresql-server' => 9.2 ); - $pkgr_mock->redefine( 'is_installed' => sub ($rpm) { return defined $installed{$rpm} ? 1 : 0 } ); - $pkgr_mock->redefine( 'get_package_version' => sub ($rpm) { return $installed{$rpm} } ); + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $expected_target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + + my $pkgr_mock = Test::MockModule->new('Cpanel::Pkgr'); + my %installed = ( 'cpanel-ccs-calendarserver' => 9.2, 'postgresql-server' => 9.2 ); + $pkgr_mock->redefine( 'is_installed' => sub ($rpm) { return defined $installed{$rpm} ? 1 : 0 } ); + $pkgr_mock->redefine( 'get_package_version' => sub ($rpm) { return $installed{$rpm} } ); - is( $db->_warning_if_postgresql_installed, 2, "pg 9 is installed" ); - message_seen( 'WARN', "You have postgresql-server version 9.2 installed. This will be upgraded irreversibly to version 10.0 when you switch to AlmaLinux 8" ); + is( $db->_warning_if_postgresql_installed, 2, "pg 9 is installed" ); + message_seen( 'WARN', "You have postgresql-server version 9.2 installed. This will be upgraded irreversibly to version 10.0 when you switch to $expected_target_os" ); - $installed{'postgresql-server'} = '10.2'; - is( $db->_warning_if_postgresql_installed, 1, "pg 10 is installed so no warning" ); - no_messages_seen(); + $installed{'postgresql-server'} = '10.2'; + is( $db->_warning_if_postgresql_installed, 1, "pg 10 is installed so no warning" ); + no_messages_seen(); - $installed{'postgresql-server'} = 'an_unexpected_version'; - is( $db->_warning_if_postgresql_installed, 1, "unknown pg version is installed so no warning" ); - no_messages_seen(); + $installed{'postgresql-server'} = 'an_unexpected_version'; + is( $db->_warning_if_postgresql_installed, 1, "unknown pg version is installed so no warning" ); + no_messages_seen(); - delete $installed{'postgresql-server'}; - is( $db->_warning_if_postgresql_installed, 0, "pg is not installed so no warning" ); - no_messages_seen(); + delete $installed{'postgresql-server'}; + is( $db->_warning_if_postgresql_installed, 0, "pg is not installed so no warning" ); + no_messages_seen(); + } } diff --git a/t/blocker-DiskSpace.t b/t/blocker-DiskSpace.t index 34f38c51..16c07ac1 100644 --- a/t/blocker-DiskSpace.t +++ b/t/blocker-DiskSpace.t @@ -11,10 +11,9 @@ use Test2::Tools::Exception; use Test::MockModule qw/strict/; -BEGIN { - use FindBin; - require $FindBin::Bin . '/../elevate-cpanel'; -} +use FindBin; +use lib $FindBin::Bin . "/lib"; +use Test::Elevate; use Elevate::Blockers::DiskSpace (); diff --git a/t/blocker-Distros.t b/t/blocker-Distros.t index 6def708a..653b0f38 100644 --- a/t/blocker-Distros.t +++ b/t/blocker-Distros.t @@ -26,47 +26,44 @@ my $distros = $cpev->get_blocker('Distros'); { note "Distro supported checks."; Cpanel::OS::clear_cache_after_cloudlinux_update(); + unmock_os(); my $f = Test::MockFile->symlink( 'linux|centos|6|9|2009', '/var/cpanel/caches/Cpanel-OS' ); my $osr = Test::MockFile->file( '/etc/os-release', '', { mtime => time - 100000 } ); my $rhr = Test::MockFile->file( '/etc/redhat-release', '', { mtime => time - 100000 } ); my $m_custom = Test::MockFile->file(q[/var/cpanel/caches/Cpanel-OS.custom]); - is( + like( $distros->check(), { - id => q[Elevate::Blockers::Distros::_blocker_is_non_centos7], - msg => 'This script is only designed to upgrade CentOS 7 to AlmaLinux 8.', + id => q[Elevate::Blockers::Distros::_blocker_os_is_not_supported], + msg => qr/This script is only designed to upgrade the following OSs/, }, 'C6 is not supported.' ); undef $f; Cpanel::OS::clear_cache_after_cloudlinux_update(); + unmock_os(); $f = Test::MockFile->symlink( 'linux|centos|8|9|2009', '/var/cpanel/caches/Cpanel-OS' ); - is( + like( $distros->check(), { - id => q[Elevate::Blockers::Distros::_blocker_is_non_centos7], - msg => 'This script is only designed to upgrade CentOS 7 to AlmaLinux 8.', + id => q[Elevate::Blockers::Distros::_blocker_os_is_not_supported], + msg => qr/This script is only designed to upgrade the following OSs/, }, 'C8 is not supported.' ); undef $f; Cpanel::OS::clear_cache_after_cloudlinux_update(); + unmock_os(); $f = Test::MockFile->symlink( 'linux|cloudlinux|7|9|2009', '/var/cpanel/caches/Cpanel-OS' ); - is( - $distros->check(), - { - id => q[Elevate::Blockers::Distros::_blocker_is_non_centos7], - msg => 'This script is only designed to upgrade CentOS 7 to AlmaLinux 8.', - }, - 'CL7 is not supported.' - ); + is( $distros->check(), 0, 'CL7 is supported.' ); undef $f; Cpanel::OS::clear_cache_after_cloudlinux_update(); + unmock_os(); $f = Test::MockFile->symlink( 'linux|centos|7|4|2009', '/var/cpanel/caches/Cpanel-OS' ); like( $distros->check(), @@ -79,6 +76,7 @@ my $distros = $cpev->get_blocker('Distros'); undef $f; Cpanel::OS::clear_cache_after_cloudlinux_update(); + unmock_os(); $f = Test::MockFile->symlink( 'linux|centos|7|9|2009', '/var/cpanel/caches/Cpanel-OS' ); $m_custom->contents(''); is( @@ -90,9 +88,9 @@ my $distros = $cpev->get_blocker('Distros'); 'Custom OS is not supported.' ); $m_custom->unlink; - is( $distros->_blocker_is_experimental_os(), 0, "if not experimental, we're ok" ); - is( $distros->_blocker_is_non_centos7(), 0, "now on a valid C7" ); - is( $distros->_blocker_is_old_centos7(), 0, "now on a up to date C7" ); + is( $distros->_blocker_is_experimental_os(), 0, "if not experimental, we're ok" ); + is( $distros->_blocker_os_is_not_supported(), 0, "now on a valid C7" ); + is( $distros->_blocker_is_old_centos7(), 0, "now on a up to date C7" ); #no_messages_seen(); } diff --git a/t/blocker-JetBackup.t b/t/blocker-JetBackup.t index a155ea2a..5e4a26f5 100644 --- a/t/blocker-JetBackup.t +++ b/t/blocker-JetBackup.t @@ -53,18 +53,24 @@ my $jb = $cpev->get_blocker('JetBackup'); my $jb_mock = Test::MockModule->new('Elevate::Blockers::JetBackup'); - $jb_mock->redefine( '_use_jetbackup4_or_earlier' => 1 ); - is( - $jb->_blocker_old_jetbackup(), - { - id => q[Elevate::Blockers::JetBackup::_blocker_old_jetbackup], - msg => "AlmaLinux 8 does not support JetBackup prior to version 5.\nPlease upgrade JetBackup before elevate.\n", - }, - q{Block if jetbackup 4 is installed.} - ); - - $jb_mock->redefine( '_use_jetbackup4_or_earlier' => 0 ); - is( $jb->_blocker_old_jetbackup(), 0, 'ok when jetbackup 4 or earlier is not installed.' ); + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $expected_target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + + $jb_mock->redefine( '_use_jetbackup4_or_earlier' => 1 ); + is( + $jb->_blocker_old_jetbackup(), + { + id => q[Elevate::Blockers::JetBackup::_blocker_old_jetbackup], + msg => "$expected_target_os does not support JetBackup prior to version 5.\nPlease upgrade JetBackup before elevate.\n", + }, + q{Block if jetbackup 4 is installed.} + ); + + $jb_mock->redefine( '_use_jetbackup4_or_earlier' => 0 ); + is( $jb->_blocker_old_jetbackup(), 0, 'ok when jetbackup 4 or earlier is not installed.' ); + } } diff --git a/t/blocker-Python.t b/t/blocker-Python.t index f85c184e..867af173 100644 --- a/t/blocker-Python.t +++ b/t/blocker-Python.t @@ -12,6 +12,7 @@ use Test2::Plugin::NoWarnings; use Test::MockModule qw{strict}; use Elevate::Blockers::Python (); +use Elevate::OS (); my %mocks = map { $_ => Test::MockModule->new($_); } qw{ Cpanel::Pkgr @@ -40,3 +41,11 @@ my $expected = { is( $obj->check, $expected, "Got expected blocker returned when found" ); done_testing(); + +# ------------------------------ # + +package cpev; + +sub read_stage_file { + return 'CentOS7'; +} diff --git a/t/blocker-dns.t b/t/blocker-dns.t index 74179701..cd4fabad 100644 --- a/t/blocker-dns.t +++ b/t/blocker-dns.t @@ -24,33 +24,37 @@ my $cpev = cpev->new; my $dns = $cpev->get_blocker('DNS'); { - is( - $dns->_blocker_non_bind_powerdns('nsd'), - { - id => q[Elevate::Blockers::DNS::_blocker_non_bind_powerdns], - msg => <<~'EOS', - AlmaLinux 8 only supports bind or powerdns. We suggest you switch to powerdns. + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + my $expected_target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + is( + $dns->_blocker_non_bind_powerdns('nsd'), + { + id => q[Elevate::Blockers::DNS::_blocker_non_bind_powerdns], + msg => <<~"EOS", + $expected_target_os only supports bind or powerdns. We suggest you switch to powerdns. Before upgrading, we suggest you run: /scripts/setupnameserver powerdns. EOS - }, - 'nsd nameserver is a blocker.' - ); - - is( - $dns->_blocker_non_bind_powerdns('mydns'), - { - id => q[Elevate::Blockers::DNS::_blocker_non_bind_powerdns], - msg => <<~'EOS', - AlmaLinux 8 only supports bind or powerdns. We suggest you switch to powerdns. + }, + 'nsd nameserver is a blocker.' + ); + + is( + $dns->_blocker_non_bind_powerdns('mydns'), + { + id => q[Elevate::Blockers::DNS::_blocker_non_bind_powerdns], + msg => <<~"EOS", + $expected_target_os only supports bind or powerdns. We suggest you switch to powerdns. Before upgrading, we suggest you run: /scripts/setupnameserver powerdns. EOS - }, - 'mydns nameserver is a blocker.' - ); - - is( $dns->_blocker_non_bind_powerdns('bind'), 0, "if they use bind, we're ok" ); - is( $dns->_blocker_non_bind_powerdns('powerdns'), 0, "if they use powerdns, we're ok" ); - is( $dns->_blocker_non_bind_powerdns('disabled'), 0, "if they use no dns, we're ok" ); + }, + 'mydns nameserver is a blocker.' + ); + + is( $dns->_blocker_non_bind_powerdns('bind'), 0, "if they use bind, we're ok" ); + is( $dns->_blocker_non_bind_powerdns('powerdns'), 0, "if they use powerdns, we're ok" ); + is( $dns->_blocker_non_bind_powerdns('disabled'), 0, "if they use no dns, we're ok" ); + } } done_testing(); diff --git a/t/blocker-ea4.t b/t/blocker-ea4.t index 4c20fb14..32e0b989 100644 --- a/t/blocker-ea4.t +++ b/t/blocker-ea4.t @@ -47,19 +47,37 @@ my $mock_cpev = Test::MockModule->new('cpev'); # only testing the blocking case - like( - $ea4->_blocker_ea4_profile(), - { - id => q[Elevate::Blockers::EA4::_blocker_ea4_profile], - msg => <<~'EOS', - One or more EasyApache 4 package(s) are not compatible with AlmaLinux 8. + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $expected_target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + like( + $ea4->_blocker_ea4_profile(), + { + id => q[Elevate::Blockers::EA4::_blocker_ea4_profile], + msg => <<~"EOS", + One or more EasyApache 4 package(s) are not compatible with $expected_target_os. Please remove these packages before continuing the update. - ea4-bad-pkg EOS - }, - 'blocks when EA4 has an incompatible package' - ); + }, + 'blocks when EA4 has an incompatible package' + ); + + my $target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + ea_info_check($target_os); + message_seen( WARN => <<"EOS"); +*** Elevation Blocker detected: *** +One or more EasyApache 4 package(s) are not compatible with $target_os. +Please remove these packages before continuing the update. +- ea4-bad-pkg + +EOS + + } + + no_messages_seen(); $mock_cpev->unmock_all; } @@ -67,63 +85,72 @@ my $mock_cpev = Test::MockModule->new('cpev'); { $mock_compoment_ea4->redefine( backup => sub { return; } ); - my $ea_info_check = sub { - message_seen( 'INFO' => "Checking EasyApache profile compatibility with AlmaLinux 8." ); - }; + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); - ok !$ea4->_blocker_ea4_profile(), "no ea4 blockers without an ea4 profile to backup"; - $ea_info_check->(); + my $target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; - my $stage_file = Test::MockFile->file( cpev::ELEVATE_STAGE_FILE() ); + ok !$ea4->_blocker_ea4_profile(), "no ea4 blockers without an ea4 profile to backup"; + ea_info_check($target_os); - my $stage_ea4 = { - profile => '/some/file.not.used.there', - }; + my $stage_file = Test::MockFile->file( cpev::ELEVATE_STAGE_FILE() ); - $mock_cpev->redefine( - read_stage_file => sub { - return { ea4 => $stage_ea4 }; - } - ); + my $stage_ea4 = { + profile => '/some/file.not.used.there', + }; - clear_messages_seen(); + $mock_cpev->redefine( + read_stage_file => sub { + return { ea4 => $stage_ea4 }; + } + ); - ok( !$ea4->_blocker_ea4_profile(), "no ea4 blockers: profile without any dropped_pkgs" ); + ok( !$ea4->_blocker_ea4_profile(), "no ea4 blockers: profile without any dropped_pkgs" ); - $ea_info_check->(); + ea_info_check($target_os); - $stage_ea4->{'dropped_pkgs'} = { - "ea-bar" => "exp", - "ea-baz" => "exp", - }; - ok( !$ea4->_blocker_ea4_profile(), "no ea4 blockers: profile with dropped_pkgs: exp only" ); - $ea_info_check->(); + $stage_ea4->{'dropped_pkgs'} = { + "ea-bar" => "exp", + "ea-baz" => "exp", + }; + ok( !$ea4->_blocker_ea4_profile(), "no ea4 blockers: profile with dropped_pkgs: exp only" ); + ea_info_check($target_os); - $stage_ea4->{'dropped_pkgs'} = { - "pkg1" => "reg", - "ea-baz" => "exp", - "pkg3" => "reg", - "pkg4" => "whatever", - }; + $stage_ea4->{'dropped_pkgs'} = { + "pkg1" => "reg", + "ea-baz" => "exp", + "pkg3" => "reg", + "pkg4" => "whatever", + }; - ok my $blocker = $ea4->_blocker_ea4_profile(), "_blocker_ea4_profile "; - $ea_info_check->(); + ok my $blocker = $ea4->_blocker_ea4_profile(), "_blocker_ea4_profile "; + ea_info_check($target_os); - message_seen( 'WARN' => qr[Elevation Blocker detected] ); + message_seen( 'WARN' => qr[Elevation Blocker detected] ); - like $blocker, object { - prop blessed => 'cpev::Blocker'; + like $blocker, object { + prop blessed => 'cpev::Blocker'; - field id => q[Elevate::Blockers::EA4::_blocker_ea4_profile]; - field msg => 'One or more EasyApache 4 package(s) are not compatible with AlmaLinux 8. + field id => q[Elevate::Blockers::EA4::_blocker_ea4_profile]; + field msg => qq[One or more EasyApache 4 package(s) are not compatible with $target_os. Please remove these packages before continuing the update. - pkg1 - pkg3 - pkg4 -'; +]; + + end(); + }, "blocker with expected error" or diag explain $blocker; + + $stage_ea4 = {}; + $mock_cpev->unmock_all; + } + + no_messages_seen(); +} - end(); - }, "blocker with expected error" or diag explain $blocker; +sub ea_info_check ($os) { + message_seen( 'INFO' => "Checking EasyApache profile compatibility with $os." ); } done_testing(); diff --git a/t/blocker-whm.t b/t/blocker-whm.t index 14590059..a8172e7b 100644 --- a/t/blocker-whm.t +++ b/t/blocker-whm.t @@ -82,23 +82,30 @@ my $whm = $cpev->get_blocker('WHM'); { note "cPanel & WHM minimum LTS."; - local $Cpanel::Version::Tiny::major_version = 100; - local $Cpanel::Version::Tiny::VERSION_BUILD = '11.109.0.9999'; - - like( - $whm->_blocker_is_newer_than_lts(), - { - id => q[Elevate::Blockers::WHM::_blocker_is_newer_than_lts], - msg => qr{ - \QThis version 11.109.0.9999 does not support upgrades to AlmaLinux 8.\E \s+ + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + my $cpev = cpev->new; + my $whm = $cpev->get_blocker('WHM'); + + local $Cpanel::Version::Tiny::major_version = 100; + local $Cpanel::Version::Tiny::VERSION_BUILD = '11.109.0.9999'; + + my $expected_target_os = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; + like( + $whm->_blocker_is_newer_than_lts(), + { + id => q[Elevate::Blockers::WHM::_blocker_is_newer_than_lts], + msg => qr{ + \QThis version 11.109.0.9999 does not support upgrades to $expected_target_os.\E \s+ \QPlease ensure the cPanel version is 110.\E }xms, - }, - q{cPanel version must be above the known LTS.} - ); + }, + q{cPanel version must be above the known LTS.} + ); - $Cpanel::Version::Tiny::major_version = Elevate::Constants::MINIMUM_LTS_SUPPORTED; - is( $whm->_blocker_is_newer_than_lts(), 0, 'Recent LTS version passes this test.' ); + $Cpanel::Version::Tiny::major_version = Elevate::Constants::MINIMUM_LTS_SUPPORTED; + is( $whm->_blocker_is_newer_than_lts(), 0, 'Recent LTS version passes this test.' ); + } } diff --git a/t/components-ea4.t b/t/components-ea4.t index 5a2b7c2a..ab3b0baa 100644 --- a/t/components-ea4.t +++ b/t/components-ea4.t @@ -102,29 +102,35 @@ sub test_backup_and_restore_not_using_ea4 : Test(7) ($self) { return; } -sub test_missing_ea4_profile : Test(3) ($self) { +sub test_missing_ea4_profile : Test(6) ($self) { - $self->{mock_saferun}->redefine( - saferunnoerror => sub { - note "saferunnoerror: no output"; - return; - }, - ); + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); - my $ea4 = cpev->new->component('EA4'); - like( - dies { $ea4->_backup_ea4_profile() }, - qr/Unable to backup EA4 profile/, - "Unable to backup EA4 profile - no profile file" - ); + $self->{mock_saferun}->redefine( + saferunnoerror => sub { + note "saferunnoerror: no output"; + return; + }, + ); + + my $ea4 = cpev->new->component('EA4'); + like( + dies { $ea4->_backup_ea4_profile() }, + qr/Unable to backup EA4 profile/, + "Unable to backup EA4 profile - no profile file" + ); - _message_run_ea_current_to_profile(); + _message_run_ea_current_to_profile($os); + } return; } sub test_get_ea4_profile : Test(10) ($self) { + set_os_to('cent'); + my $profile = PROFILE_FILE; my $output = qq[$profile\n]; @@ -140,7 +146,7 @@ sub test_get_ea4_profile : Test(10) ($self) { my $ea4 = cpev->new->component('EA4'); is( $ea4->_get_ea4_profile(), PROFILE_FILE, "_get_ea4_profile" ); - _message_run_ea_current_to_profile(1); + _message_run_ea_current_to_profile( 'cent', 1 ); $output = <<'EOS'; The following packages are not available on AlmaLinux_8 and have been removed from the profile @@ -176,41 +182,46 @@ EOS is( $ea4->_get_ea4_profile(), $f, "_get_ea4_profile with noise..." ); - _message_run_ea_current_to_profile($f); + _message_run_ea_current_to_profile( 'cent', $f ); return; } -sub test_get_ea4_profile_check_mode : Test(7) ($self) { +sub test_get_ea4_profile_check_mode : Test(14) ($self) { - my $output = qq[void\n]; + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); - my $cpev = cpev->new( _is_check_mode => 1 ); - ok -d $cpev->tmp_dir, "tmp_dir works"; + my $output = qq[void\n]; - my $mock_b = Test::MockModule->new('Elevate::Blockers') # - ->redefine( is_check_mode => 1 ); + my $cpev = cpev->new( _is_check_mode => 1 ); + ok -d $cpev->tmp_dir, "tmp_dir works"; - ok( Elevate::Blockers->is_check_mode(), 'Elevate::Blockers->is_check_mode()' ); + my $mock_b = Test::MockModule->new('Elevate::Blockers') # + ->redefine( is_check_mode => 1 ); - my $expected_profile = $cpev->tmp_dir() . '/ea_profile.json'; - { - open( my $fh, '>', $expected_profile ) or die; - print {$fh} "...\n"; - } + ok( Elevate::Blockers->is_check_mode(), 'Elevate::Blockers->is_check_mode()' ); - $self->{mock_saferun}->redefine( - saferunnoerror => sub { - note "saferunnoerror: ", $output; - return $output; - }, - ); + my $expected_profile = $cpev->tmp_dir() . '/ea_profile.json'; + { + open( my $fh, '>', $expected_profile ) or die; + print {$fh} "...\n"; + } - my $ea4 = $cpev->component('EA4'); - is( $ea4->_get_ea4_profile(), $expected_profile, "_get_ea4_profile uses a temporary file for the profile" ); + $self->{mock_saferun}->redefine( + saferunnoerror => sub { + note "saferunnoerror: ", $output; + return $output; + }, + ); + + my $ea4 = $cpev->component('EA4'); + is( $ea4->_get_ea4_profile(), $expected_profile, "_get_ea4_profile uses a temporary file for the profile" ); - message_seen( 'INFO' => "Running: /usr/local/bin/ea_current_to_profile --target-os=AlmaLinux_8 --output=$expected_profile" ); - message_seen( 'INFO' => "Backed up EA4 profile to $expected_profile" ); + my $expected_target = $os eq 'cent' ? 'CentOS_8' : 'CloudLinux_8'; + message_seen( 'INFO' => "Running: /usr/local/bin/ea_current_to_profile --target-os=$expected_target --output=$expected_profile" ); + message_seen( 'INFO' => "Backed up EA4 profile to $expected_profile" ); + } return; } @@ -229,27 +240,31 @@ sub test_tmp_dir : Test(3) ($self) { return; } -sub backup_non_existing_profile : Test(10) ($self) { +sub backup_non_existing_profile : Test(16) ($self) { my $ea4 = cpev->new->component('EA4'); - like( - dies { $ea4->_backup_ea4_profile() }, - qr/Unable to backup EA4 profile/, - "Unable to backup EA4 profile - non existing profile file" - ); + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); - _message_run_ea_current_to_profile(); + like( + dies { $ea4->_backup_ea4_profile() }, + qr/Unable to backup EA4 profile/, + "Unable to backup EA4 profile - non existing profile file" + ); - $self->{mock_profile}->contents(''); + _message_run_ea_current_to_profile($os); - like( - dies { $ea4->_backup_ea4_profile() }, - qr/Unable to backup EA4 profile/, - "Unable to backup EA4 profile - empty profile file" - ); + $self->{mock_profile}->contents(''); + + like( + dies { $ea4->_backup_ea4_profile() }, + qr/Unable to backup EA4 profile/, + "Unable to backup EA4 profile - empty profile file" + ); - _message_run_ea_current_to_profile(); + _message_run_ea_current_to_profile($os); + } is cpev::read_stage_file(), { ea4 => { enable => 1 } }, "stage file - ea4 is enabled but we failed"; is $ea4->_restore_ea4_profile(), undef, "restore_ea4_profile: nothing to restore"; @@ -259,7 +274,7 @@ sub backup_non_existing_profile : Test(10) ($self) { return; } -sub test_backup_and_restore_ea4_profile : Test(8) ($self) { +sub test_backup_and_restore_ea4_profile : Test(13) ($self) { my $ea4 = cpev->new->component('EA4'); @@ -267,8 +282,12 @@ sub test_backup_and_restore_ea4_profile : Test(8) ($self) { $self->_update_profile_file($profile); - is( $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4" ); - _message_run_ea_current_to_profile(1); + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + is( $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4" ); + _message_run_ea_current_to_profile( $os, 1 ); + } is cpev::read_stage_file(), { ea4 => { enable => 1, profile => PROFILE_FILE } }, "stage file - ea4 is enabled / profile is backup"; @@ -279,102 +298,113 @@ sub test_backup_and_restore_ea4_profile : Test(8) ($self) { return; } -sub test_backup_and_restore_ea4_profile_dropped_packages : Test(14) ($self) { +sub test_backup_and_restore_ea4_profile_dropped_packages : Test(28) ($self) { my $ea4 = cpev->new->component('EA4'); - my $profile = { - "os_upgrade" => { - "source_os" => "", - "target_os" => "", - "target_obs_project" => "", - "dropped_pkgs" => { - "ea-bar" => "reg", - "ea-baz" => "exp" + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $profile = { + "os_upgrade" => { + "source_os" => "", + "target_os" => "", + "target_obs_project" => "", + "dropped_pkgs" => { + "ea-bar" => "reg", + "ea-baz" => "exp" + } } - } - }; - $self->_update_profile_file($profile); + }; + $self->_update_profile_file($profile); - is $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4"; - _message_run_ea_current_to_profile(1); + is $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4"; + _message_run_ea_current_to_profile( $os, 1 ); - is cpev::read_stage_file(), { - ea4 => { - enable => 1, # - profile => PROFILE_FILE, # - dropped_pkgs => $profile->{os_upgrade}->{dropped_pkgs} # - } - }, - "stage file - ea4 is enabled / profile is backup with dropped_pkgs"; + is cpev::read_stage_file(), { + ea4 => { + enable => 1, # + profile => PROFILE_FILE, # + dropped_pkgs => $profile->{os_upgrade}->{dropped_pkgs} # + } + }, + "stage file - ea4 is enabled / profile is backup with dropped_pkgs"; - is $ea4->_restore_ea4_profile(), 1, "restore_ea4_profile: profile restored"; - is $self->{last_ssystem_call}, [qw{ /usr/local/bin/ea_install_profile --install /var/my.profile}], "call ea_install_profile to restore it" - or diag explain $self->{last_ssystem_call}; + is $ea4->_restore_ea4_profile(), 1, "restore_ea4_profile: profile restored"; + is $self->{last_ssystem_call}, [qw{ /usr/local/bin/ea_install_profile --install /var/my.profile}], "call ea_install_profile to restore it" + or diag explain $self->{last_ssystem_call}; - my $expect = <<'EOS'; + my $expect = <<'EOS'; One or more EasyApache 4 package(s) cannot be restored from your previous profile: - 'ea-bar' - 'ea-baz' ( package was Experimental in CentOS 7 ) EOS - chomp $expect; - foreach my $l ( split( "\n", $expect ) ) { - message_seen( 'WARN' => $l ); + chomp $expect; + foreach my $l ( split( "\n", $expect ) ) { + message_seen( 'WARN' => $l ); + } + + $stage_file->unlink; } return; } -sub test_backup_and_restore_ea4_profile_cleanup_dropped_packages : Test(14) ($self) { +sub test_backup_and_restore_ea4_profile_cleanup_dropped_packages : Test(28) ($self) { my $ea4 = cpev->new->component('EA4'); - my $profile = { - "os_upgrade" => { - "source_os" => "", - "target_os" => "", - "target_obs_project" => "", - "dropped_pkgs" => { - "ea-bar" => "reg", - "ea-baz" => "exp" + for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $profile = { + "os_upgrade" => { + "source_os" => "", + "target_os" => "", + "target_obs_project" => "", + "dropped_pkgs" => { + "ea-bar" => "reg", + "ea-baz" => "exp" + } } - } - }; - $self->_update_profile_file($profile); + }; + $self->_update_profile_file($profile); - is $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4"; - _message_run_ea_current_to_profile(1); + is $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4"; + _message_run_ea_current_to_profile( $os, 1 ); - is cpev::read_stage_file(), { - ea4 => { - enable => 1, # - profile => PROFILE_FILE, # - dropped_pkgs => $profile->{os_upgrade}->{dropped_pkgs} # - } - }, - "stage file - ea4 is enabled / profile is backup with dropped_pkgs"; - - $profile = { - "os_upgrade" => { - "source_os" => "", - "target_os" => "", - "target_obs_project" => "", - } - }; - $self->_update_profile_file($profile); + is cpev::read_stage_file(), { + ea4 => { + enable => 1, # + profile => PROFILE_FILE, # + dropped_pkgs => $profile->{os_upgrade}->{dropped_pkgs} # + } + }, + "stage file - ea4 is enabled / profile is backup with dropped_pkgs"; + + $profile = { + "os_upgrade" => { + "source_os" => "", + "target_os" => "", + "target_obs_project" => "", + } + }; + $self->_update_profile_file($profile); - is $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4"; - _message_run_ea_current_to_profile(1); + is $ea4->_backup_ea4_profile(), 1, "backup_ea4_profile - using ea4"; + _message_run_ea_current_to_profile( $os, 1 ); - my $stage = cpev::read_stage_file(); - is $stage, { - ea4 => { - enable => 1, # - profile => PROFILE_FILE, # - } - }, - "stage file - ea4 is enabled / profile: clear the dropped_pkgs hash" - or diag explain $stage; + my $stage = cpev::read_stage_file(); + is $stage, { + ea4 => { + enable => 1, # + profile => PROFILE_FILE, # + } + }, + "stage file - ea4 is enabled / profile: clear the dropped_pkgs hash" + or diag explain $stage; + + } return; @@ -512,9 +542,11 @@ Please remove these packages before continuing the update. ## helpers -sub _message_run_ea_current_to_profile ( $success = 0 ) { +sub _message_run_ea_current_to_profile ( $os = 'cent', $success = 0 ) { + + my $target = $os eq 'cent' ? 'CentOS_8' : 'CloudLinux_8'; - message_seen( 'INFO' => q[Running: /usr/local/bin/ea_current_to_profile --target-os=AlmaLinux_8] ); + message_seen( 'INFO' => qq[Running: /usr/local/bin/ea_current_to_profile --target-os=$target] ); return unless $success; my $f = $success eq 1 ? PROFILE_FILE : $success; diff --git a/t/leapp_upgrade.t b/t/leapp_upgrade.t index b2f9aaaa..a025d4d3 100644 --- a/t/leapp_upgrade.t +++ b/t/leapp_upgrade.t @@ -22,23 +22,37 @@ use cPstrict; $INC{'scripts/ElevateCpanel.pm'} = '__TEST__'; +my $ssystem_cmd; my $mock_elevate = Test::MockModule->new('cpev'); $mock_elevate->redefine( ssystem_and_die => sub ( $, @args ) { - note "run: ", join( ' ', @args ); + shift @args; + $ssystem_cmd = join( ' ', @args ); + note "run: $ssystem_cmd"; return; }, + getopt => sub { return; }, +); + +my $mock_elevate_leapp = Test::MockModule->new('Elevate::Leapp'); +$mock_elevate_leapp->redefine( setup_answer_file => sub { # cannot use Test::MockFile with system touch... note "mocked setup_answer_file"; return; }, - getopt => sub { return; }, ); my $mock_elevate_file = Test::MockFile->file('/var/cpanel/elevate'); -ok( cpev->_do_leapp_upgrade(), '_do_leapp_upgrade succeeds' ); +for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $expect_cmd = '/usr/bin/leapp upgrade'; + $expect_cmd .= ' --nowarn' if $os eq 'cloud'; + ok( cpev->leapp->upgrade(), 'leapp upgrade succeeds' ); + is( $ssystem_cmd, $expect_cmd ); +} $mock_elevate->redefine( ssystem_and_die => sub { @@ -46,14 +60,14 @@ $mock_elevate->redefine( } ); -ok cpev::LEAPP_REPORT_JSON(), 'LEAPP_REPORT_JSON defined'; -ok cpev::LEAPP_REPORT_TXT(), 'LEAPP_REPORT_TXT defined'; +ok Elevate::Leapp::LEAPP_REPORT_JSON(), 'LEAPP_REPORT_JSON defined'; +ok Elevate::Leapp::LEAPP_REPORT_TXT(), 'LEAPP_REPORT_TXT defined'; -my $mock_leap_report_json = Test::MockFile->file( cpev::LEAPP_REPORT_JSON() ); -my $mock_leap_report_txt = Test::MockFile->file( cpev::LEAPP_REPORT_TXT() ); +my $mock_leap_report_json = Test::MockFile->file( Elevate::Leapp::LEAPP_REPORT_JSON() ); +my $mock_leap_report_txt = Test::MockFile->file( Elevate::Leapp::LEAPP_REPORT_TXT() ); like( - dies { cpev->_do_leapp_upgrade() }, + dies { cpev->leapp->upgrade() }, qr{The 'leapp upgrade' process failed}, '_do_leapp_upgrade failed' ); @@ -131,7 +145,7 @@ $mock_leap_report_json->contents( <<'EOS' ); } EOS -my $error = dies { cpev->_do_leapp_upgrade() }; +my $error = dies { cpev->leapp->upgrade() }; note $error; @@ -162,7 +176,7 @@ unlike( ); $mock_leap_report_txt->contents('full report'); -$error = dies { cpev->_do_leapp_upgrade() }; +$error = dies { cpev->leapp->upgrade() }; note $error; diff --git a/t/lib/Test/Elevate.pm b/t/lib/Test/Elevate.pm index 226e8f5d..3a0eddb7 100644 --- a/t/lib/Test/Elevate.pm +++ b/t/lib/Test/Elevate.pm @@ -7,7 +7,7 @@ use Test::More; use Test::Deep; our @ISA = qw(Exporter); -our @EXPORT = qw(message_seen message_seen_lines clear_messages_seen no_messages_seen no_message_seen ); +our @EXPORT = qw(message_seen message_seen_lines clear_messages_seen no_messages_seen no_message_seen set_os_to_centos_7 set_os_to_cloudlinux_7 set_os_to unmock_os); our @EXPORT_OK = @EXPORT; use Log::Log4perl; @@ -67,6 +67,10 @@ sub init { mockLoggerFor($cat); } + # Default to CentOS 7 + note 'Mock Elevate::OS singleton to think this server is CentOS 7'; + $Elevate::OS::OS = Elevate::OS::CentOS7->new(); + return; } @@ -125,4 +129,28 @@ sub no_messages_seen { # convenience sub no_message_seen { goto &no_messages_seen; } +sub set_os_to_centos_7 { + note 'Mock Elevate::OS singleton to think this server is CentOS 7'; + $Elevate::OS::OS = Elevate::OS::CentOS7->new(); + return; +} + +sub set_os_to_cloudlinux_7 { + note 'Mock Elevate::OS singleton to think this server is CloudLinux 7'; + $Elevate::OS::OS = Elevate::OS::CloudLinux7->new(); + return; +} + +sub set_os_to ($os) { + return set_os_to_centos_7() if $os =~ m/^cent/i; + return set_os_to_cloudlinux_7 if $os =~ m/^cloud/i; + + die "Unknown os: $os\n"; +} + +sub unmock_os { + note 'Elevate::OS is no longer mocked'; + $Elevate::OS::OS = undef; +} + 1; diff --git a/t/notify.t b/t/notify.t index 16982630..20b9e1c3 100644 --- a/t/notify.t +++ b/t/notify.t @@ -33,55 +33,72 @@ $mock_notify->redefine( } ); -my $stage_file = Test::MockFile->file( cpev::ELEVATE_STAGE_FILE() ); - my $cpev = bless {}, 'cpev'; -$cpev->_notify_success(); +for my $os ( 'cent', 'cloud' ) { + set_os_to($os); + + my $stage_file = Test::MockFile->file( cpev::ELEVATE_STAGE_FILE() ); + + my $expect_title = $os eq 'cent' ? 'Successfully updated to AlmaLinux 8' : 'Successfully updated to CloudLinux 8'; + my $expect_body = + $os eq 'cent' + ? qq[The cPanel & WHM server has completed the elevation process from CentOS 7 to AlmaLinux 8.\n] + : qq[The cPanel & WHM server has completed the elevation process from CloudLinux 7 to CloudLinux 8.\n]; + + $cpev->_notify_success(); -is $notification, { - title => 'Successfully updated to AlmaLinux 8', - body => qq[The cPanel & WHM server has completed the elevation process from CentOS 7 to AlmaLinux 8.\n], - opts => { is_success => 1 }, - }, - " _notify_success" - or diag explain $notification; + is $notification, { + title => $expect_title, + body => $expect_body, + opts => { is_success => 1 }, + }, + " _notify_success" + or diag explain $notification; -$notification = {}; + $notification = {}; -ok Elevate::Notify::add_final_notification("My First Notification"), 'add_final_notification'; + ok Elevate::Notify::add_final_notification("My First Notification"), 'add_final_notification'; -is cpev::read_stage_file(), { final_notifications => ['My First Notification'] }, "stage file - notifications"; + is cpev::read_stage_file(), { final_notifications => ['My First Notification'] }, "stage file - notifications"; -ok !Elevate::Notify::add_final_notification(undef), q[cannot add_final_notification(undef)]; -ok !Elevate::Notify::add_final_notification(''), q[cannot add_final_notification('')]; + ok !Elevate::Notify::add_final_notification(undef), q[cannot add_final_notification(undef)]; + ok !Elevate::Notify::add_final_notification(''), q[cannot add_final_notification('')]; -is cpev::read_stage_file(), { final_notifications => ['My First Notification'] }, "stage file - notifications"; + is cpev::read_stage_file(), { final_notifications => ['My First Notification'] }, "stage file - notifications"; -Elevate::Notify::add_final_notification("My Second Notification\nwith two lines."); + Elevate::Notify::add_final_notification("My Second Notification\nwith two lines."); -is cpev::read_stage_file(), { - final_notifications => [ - "My Second Notification\nwith two lines.", - 'My First Notification', - ] - }, - "stage file - notifications" - or diag explain cpev::read_stage_file(); + is cpev::read_stage_file(), { + final_notifications => [ + "My Second Notification\nwith two lines.", + 'My First Notification', + ] + }, + "stage file - notifications" + or diag explain cpev::read_stage_file(); -$cpev->_notify_success(); + $cpev->_notify_success(); -is $notification->{title}, 'Successfully updated to AlmaLinux 8', '_notify_success: title'; -is $notification->{body}, <{body}; -The cPanel & WHM server has completed the elevation process from CentOS 7 to AlmaLinux 8. + my $expect_upgrade_from = $os eq 'cent' ? 'CentOS 7' : 'CloudLinux 7'; + my $expect_upgrade_to = $os eq 'cent' ? 'AlmaLinux 8' : 'CloudLinux 8'; -The update to AlmaLinux 8 was successful but please note that one ore more notifications require your attention: + is $notification->{title}, "Successfully updated to $expect_upgrade_to", '_notify_success: title'; + is $notification->{body}, <{body}; +The cPanel & WHM server has completed the elevation process from $expect_upgrade_from to $expect_upgrade_to. + +The update to $expect_upgrade_to was successful but please note that one ore more notifications require your attention: * My First Notification * My Second Notification with two lines. EOS -no_messages_seen(); + no_messages_seen(); + + $notification = {}; + undef $stage_file; + +} done_testing(); diff --git a/t/usage.t b/t/usage.t index ef947259..2d8589ef 100644 --- a/t/usage.t +++ b/t/usage.t @@ -247,35 +247,76 @@ foreach my $test_hr (@TEST_DATA) { # Test out setting --upgrade-to to different values # -my $mock_cpev = Test::MockModule->new('cpev'); -$mock_cpev->redefine( - _read_stage_file => sub { - return {}; - } -); +{ + note 'Test as CentOS 7 server'; -my $cpev = cpev->new->_init( '--check', '--upgrade-to=OogaBoogaLinux' ); + set_os_to_centos_7(); -like( - dies { $cpev->_parse_opt_upgrade_to() }, - qr/Invalid --upgrade_to value/, - 'Exception thrown for invalid linux distro' -); + my $cpev = cpev->new->_init( '--check', '--upgrade-to=OogaBoogaLinux' ); + + like( + dies { $cpev->_parse_opt_upgrade_to() }, + qr/The current OS can only upgrade to the following flavors/, + 'Exception thrown for invalid linux distro' + ); + + $cpev = cpev->new->_init('--check'); + + ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to not supplied'; + is $cpev->upgrade_to(), 'AlmaLinux', 'CentOS 7 defaults to AlmaLinux when upgrade-to not specified'; + + $cpev = cpev->new->_init( '--check', '--upgrade-to=almalinux' ); + + ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to set to AlmaLinux'; + is $cpev->upgrade_to(), 'AlmaLinux', 'Set to use AlmaLinux when upgrade-to set to AlmaLinux'; + + $cpev = cpev->new->_init( '--check', '--upgrade-to=rocky' ); + + ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to set to Rocky'; + is $cpev->upgrade_to(), 'Rocky', 'Set to use Rocky when upgrade-to set to Rocky'; -$cpev = cpev->new->_init('--check'); + $cpev = cpev->new->_init( '--check', '--upgrade-to=cloudlinux' ); -ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to not supplied'; -is $cpev->upgrade_to(), 'AlmaLinux', 'Defaults to AlmaLinux when upgrade-to not specified'; + like( + dies { $cpev->_parse_opt_upgrade_to() }, + qr/The current OS can only upgrade to the following flavors/, + 'Exception thrown for CloudLinux when the OS is CentOS 7', + ); -$cpev = cpev->new->_init( '--check', '--upgrade-to=almalinux' ); +} + +{ + note 'Test as CloudLinux 7 server'; + + set_os_to_cloudlinux_7(); + + my $cpev = cpev->new->_init('--check'); + + ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to not supplied'; + is $cpev->upgrade_to(), 'CloudLinux', 'CloudLinux 7 defaults to CloudLinux when upgrade-to not specified'; -ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to set to AlmaLinux'; -is $cpev->upgrade_to(), 'AlmaLinux', 'Set to use AlmaLinux when upgrade-to set to AlmaLinux'; + $cpev = cpev->new->_init( '--check', '--upgrade-to=almalinux' ); -$cpev = cpev->new->_init( '--check', '--upgrade-to=rocky' ); + like( + dies { $cpev->_parse_opt_upgrade_to() }, + qr/The current OS can only upgrade to the following flavors/, + 'Exception thrown for AlmaLinux when the OS is CloudLinux 7', + ); -ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to set to Rocky'; -is $cpev->upgrade_to(), 'Rocky', 'Set to use Rocky when upgrade-to set to Rocky'; + $cpev = cpev->new->_init( '--check', '--upgrade-to=rocky' ); + + like( + dies { $cpev->_parse_opt_upgrade_to() }, + qr/The current OS can only upgrade to the following flavors/, + 'Exception thrown for Rocky Linux when the OS is CloudLinux 7', + ); + + $cpev = cpev->new->_init( '--check', '--upgrade-to=cloudlinux' ); + + ok lives { $cpev->_parse_opt_upgrade_to() }, 'No exception when upgrade-to set to cloudlinux'; + is $cpev->upgrade_to(), 'CloudLinux', 'Set to use CloudLinux when upgrade-to set to CloudLinux'; + +} # # Test out the --non-interactive parameter @@ -291,7 +332,7 @@ $mock_io_prompt->redefine( } ); -$cpev = cpev->new->_init('--start'); +my $cpev = cpev->new->_init('--start'); $cpev->give_last_chance(); is $user_has_been_prompted, 1, 'IP::Prompt invoked without the non-interactive option'; From 1daf3d98667afe99a5e6c625c1e8e87715ef805b Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Tue, 13 Feb 2024 09:49:32 -0600 Subject: [PATCH 02/12] Update blocker message for MySQL Governor Case RE-18: This is a requested change from the review. Do not advise to remove MySQL Governor. Instead, just provide more information and let it be. Changelog: --- elevate-cpanel | 4 ---- lib/Elevate/Blockers/Databases.pm | 4 ---- 2 files changed, 8 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 0341f703..61a60239 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -658,10 +658,6 @@ For more information regarding MySQL Governor, please review the documentation: https://docs.cloudlinux.com/shared/cloudlinux_os_components/#mysql-governor -To remove MySQL Governor, execute the following command: - - /usr/share/lve/dbgovernor/mysqlgovernor.py --delete - EOS } diff --git a/lib/Elevate/Blockers/Databases.pm b/lib/Elevate/Blockers/Databases.pm index a2e51a70..4c1f6062 100644 --- a/lib/Elevate/Blockers/Databases.pm +++ b/lib/Elevate/Blockers/Databases.pm @@ -196,10 +196,6 @@ For more information regarding MySQL Governor, please review the documentation: https://docs.cloudlinux.com/shared/cloudlinux_os_components/#mysql-governor -To remove MySQL Governor, execute the following command: - - /usr/share/lve/dbgovernor/mysqlgovernor.py --delete - EOS } From 78ab352362e5927d22330904f0ed8260b3d13fa6 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Tue, 13 Feb 2024 09:53:02 -0600 Subject: [PATCH 03/12] Remove accidental change to the EA4 blocker Case RE-18: This is a request from the review. An additional blank line was accidentally removed from this file. This was an accidental change that likely occurred due to testing/debugging. This commit reverses that mistake. Changelog: --- elevate-cpanel | 1 + lib/Elevate/Blockers/EA4.pm | 1 + 2 files changed, 2 insertions(+) diff --git a/elevate-cpanel b/elevate-cpanel index 61a60239..e161e495 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -918,6 +918,7 @@ EOS sub _blocker_ea4_profile ($self) { my $pretty_distro_name = $self->upgrade_to_pretty_name(); + INFO("Checking EasyApache profile compatibility with $pretty_distro_name."); $self->cpev->component('EA4')->backup; # _backup_ea4_profile(); diff --git a/lib/Elevate/Blockers/EA4.pm b/lib/Elevate/Blockers/EA4.pm index adb2dbc1..2e365718 100644 --- a/lib/Elevate/Blockers/EA4.pm +++ b/lib/Elevate/Blockers/EA4.pm @@ -35,6 +35,7 @@ sub _blocker_ea4_profile ($self) { # perform an early backup so we can check the list of dropped packages my $pretty_distro_name = $self->upgrade_to_pretty_name(); + INFO("Checking EasyApache profile compatibility with $pretty_distro_name."); $self->cpev->component('EA4')->backup; # _backup_ea4_profile(); From fc342fe29647a95ad4fade5e6775b1de60fa4eb1 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Tue, 13 Feb 2024 14:26:00 -0600 Subject: [PATCH 04/12] Add support for regex within the vetted repo constants Case RE-18: This is a request from the review. This updates the code so that regex can be placed directly within the repo constants which allows for fewer repos to be added to the array and helps to future proof for new rollout repos being added. Changelog: --- elevate-cpanel | 140 ++++++++----------------- lib/Elevate/Blockers/Repositories.pm | 148 ++++++++------------------- 2 files changed, 89 insertions(+), 199 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index e161e495..db828068 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -1589,95 +1589,51 @@ EOS mysql-community.repo }; - use constant VETTED_MYSQL_YUM_REPO_IDS => qw{ - mysql-cluster-7.5-community - mysql-cluster-7.5-community-source - mysql-cluster-7.5-community-source - mysql-cluster-7.6-community - mysql-cluster-7.6-community-source - mysql-cluster-7.6-community-source - mysql-cluster-8.0-community - mysql-cluster-8.0-community-debuginfo - mysql-cluster-8.0-community-source - mysql-connectors-community - mysql-connectors-community-debuginfo - mysql-connectors-community-source - mysql-connectors-community-source - mysql-tools-community - mysql-tools-community-debuginfo - mysql-tools-community-source - mysql-tools-preview - mysql-tools-preview-source - mysql55-community - mysql55-community-source - mysql56-community - mysql56-community-source - mysql57-community - mysql57-community-source - mysql80-community - mysql80-community-debuginfo - mysql80-community-source - MariaDB102 - MariaDB103 - MariaDB105 - MariaDB106 - }; + use constant VETTED_MYSQL_YUM_REPO_IDS => ( + qr/^mysql-cluster-[0-9.]{3}-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-connectors-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-preview(?:-source)?$/, + qr/^mysql[0-9]{2}-community(?:-(?:source|debuginfo))?$/, + qr/^MariaDB[0-9]{3}$/, + ); - use constant VETTED_CLOUDLINUX_YUM_REPO => qw{ - cloudlinux - cloudlinux-base - cloudlinux-updates - cloudlinux-extras - cloudlinux-compat - cloudlinux-imunify360 - cl-ea4 - cloudlinux-ea4 - cloudlinux-ea4-rollout - cl-mysql - cl-mysql-meta - cloudlinux-elevate - cloudlinux-rollout - }; + use constant VETTED_CLOUDLINUX_YUM_REPO => ( + qr/^cloudlinux(?:-(?:base|updates|extras|compat|imunify360|elevate))?$/, + qr/^cloudlinux-rollout(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4-rollout(?:-[0-9]+)?$/, + 'cl-ea4', + qr/^cl-mysql(?:-meta)?/, + ); - use constant VETTED_YUM_REPO => qw{ - base - c7-media - centos-kernel - centos-kernel-experimental - centosplus - cp-dev-tools - cpanel-addons-production-feed - cpanel-plugins - cr - ct-preset - digitalocean-agent - droplet-agent - EA4 - EA4-c$releasever - elasticsearch - elasticsearch-7.x - elevate - elevate-source - epel - epel-testing - extras - fasttrack - imunify360 - imunify360-ea-php-hardened - imunify360-rollout-1 - imunify360-rollout-2 - imunify360-rollout-3 - imunify360-rollout-4 - imunify360-rollout-5 - imunify360-rollout-6 - imunify360-rollout-7 - imunify360-rollout-8 - influxdb - kernelcare - updates - wp-toolkit-cpanel - wp-toolkit-thirdparties - }, VETTED_MYSQL_YUM_REPO_IDS; + use constant VETTED_YUM_REPO => ( + 'base', + 'c7-media', + qr/^centos-kernel(?:-experimental)?$/, + 'centosplus', + 'cp-dev-tools', + 'cpanel-addons-production-feed', + 'cpanel-plugins', + 'cr', + 'ct-preset', + 'digitalocean-agent', + 'droplet-agent', + qr/^EA4(?:-c\$releasever)?$/, + qr/^elasticsearch(?:7\.x)?$/, + qr/^elevate(?:-source)?$/, + qr/^epel(?:-testing)?$/, + 'extras', + 'fasttrack', + 'imunify360', + 'imunify360-ea-php-hardened', + qr/^imunify360-rollout-[0-9]+$/, + 'influxdb', + 'kernelcare', + 'updates', + qr/^wp-toolkit-(?:cpanel|thirdparties)$/, + ), + VETTED_MYSQL_YUM_REPO_IDS; sub check ($self) { my $ok = 1; @@ -1780,8 +1736,6 @@ EOS my @vetted_repos = (VETTED_YUM_REPO); push( @vetted_repos, VETTED_CLOUDLINUX_YUM_REPO ) if Elevate::OS::name() eq 'CloudLinux7'; - my %vetted = map { $_ => 1 } @vetted_repos; - my $repo_dir = Elevate::Constants::YUM_REPOS_D; my %status; @@ -1807,13 +1761,7 @@ EOS return unless length $current_repo_name; return unless $current_repo_enabled; - my $temp_current_repo_name = $current_repo_name; - - $current_repo_name = $1 if $current_repo_name =~ m/^(cloudlinux-(?:rollout|ea4)(?:-rollout)?)-[0-9]+$/; - - my $is_vetted = $vetted{$current_repo_name} || $vetted{ lc $current_repo_name }; - - $current_repo_name = $temp_current_repo_name; + my $is_vetted = grep { $current_repo_name =~ m/$_/ } @vetted_repos; if ( !$is_vetted ) { $status{'UNVETTED'} = 1; diff --git a/lib/Elevate/Blockers/Repositories.pm b/lib/Elevate/Blockers/Repositories.pm index fe4890e5..ac6df5d3 100644 --- a/lib/Elevate/Blockers/Repositories.pm +++ b/lib/Elevate/Blockers/Repositories.pm @@ -35,96 +35,50 @@ use constant DISABLE_MYSQL_YUM_REPOS => qw{ mysql-community.repo }; -# FIXME use some RegExp... -use constant VETTED_MYSQL_YUM_REPO_IDS => qw{ - mysql-cluster-7.5-community - mysql-cluster-7.5-community-source - mysql-cluster-7.5-community-source - mysql-cluster-7.6-community - mysql-cluster-7.6-community-source - mysql-cluster-7.6-community-source - mysql-cluster-8.0-community - mysql-cluster-8.0-community-debuginfo - mysql-cluster-8.0-community-source - mysql-connectors-community - mysql-connectors-community-debuginfo - mysql-connectors-community-source - mysql-connectors-community-source - mysql-tools-community - mysql-tools-community-debuginfo - mysql-tools-community-source - mysql-tools-preview - mysql-tools-preview-source - mysql55-community - mysql55-community-source - mysql56-community - mysql56-community-source - mysql57-community - mysql57-community-source - mysql80-community - mysql80-community-debuginfo - mysql80-community-source - MariaDB102 - MariaDB103 - MariaDB105 - MariaDB106 -}; - -use constant VETTED_CLOUDLINUX_YUM_REPO => qw{ - cloudlinux - cloudlinux-base - cloudlinux-updates - cloudlinux-extras - cloudlinux-compat - cloudlinux-imunify360 - cl-ea4 - cloudlinux-ea4 - cloudlinux-ea4-rollout - cl-mysql - cl-mysql-meta - cloudlinux-elevate - cloudlinux-rollout -}; - -use constant VETTED_YUM_REPO => qw{ - base - c7-media - centos-kernel - centos-kernel-experimental - centosplus - cp-dev-tools - cpanel-addons-production-feed - cpanel-plugins - cr - ct-preset - digitalocean-agent - droplet-agent - EA4 - EA4-c$releasever - elasticsearch - elasticsearch-7.x - elevate - elevate-source - epel - epel-testing - extras - fasttrack - imunify360 - imunify360-ea-php-hardened - imunify360-rollout-1 - imunify360-rollout-2 - imunify360-rollout-3 - imunify360-rollout-4 - imunify360-rollout-5 - imunify360-rollout-6 - imunify360-rollout-7 - imunify360-rollout-8 - influxdb - kernelcare - updates - wp-toolkit-cpanel - wp-toolkit-thirdparties -}, VETTED_MYSQL_YUM_REPO_IDS; +use constant VETTED_MYSQL_YUM_REPO_IDS => ( + qr/^mysql-cluster-[0-9.]{3}-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-connectors-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-preview(?:-source)?$/, + qr/^mysql[0-9]{2}-community(?:-(?:source|debuginfo))?$/, + qr/^MariaDB[0-9]{3}$/, +); + +use constant VETTED_CLOUDLINUX_YUM_REPO => ( + qr/^cloudlinux(?:-(?:base|updates|extras|compat|imunify360|elevate))?$/, + qr/^cloudlinux-rollout(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4-rollout(?:-[0-9]+)?$/, + 'cl-ea4', + qr/^cl-mysql(?:-meta)?/, +); + +use constant VETTED_YUM_REPO => ( + 'base', + 'c7-media', + qr/^centos-kernel(?:-experimental)?$/, + 'centosplus', + 'cp-dev-tools', + 'cpanel-addons-production-feed', + 'cpanel-plugins', + 'cr', + 'ct-preset', + 'digitalocean-agent', + 'droplet-agent', + qr/^EA4(?:-c\$releasever)?$/, + qr/^elasticsearch(?:7\.x)?$/, + qr/^elevate(?:-source)?$/, + qr/^epel(?:-testing)?$/, + 'extras', + 'fasttrack', + 'imunify360', + 'imunify360-ea-php-hardened', + qr/^imunify360-rollout-[0-9]+$/, + 'influxdb', + 'kernelcare', + 'updates', + qr/^wp-toolkit-(?:cpanel|thirdparties)$/, +), VETTED_MYSQL_YUM_REPO_IDS; sub check ($self) { my $ok = 1; @@ -237,8 +191,6 @@ sub _check_yum_repos ($self) { my @vetted_repos = (VETTED_YUM_REPO); push( @vetted_repos, VETTED_CLOUDLINUX_YUM_REPO ) if Elevate::OS::name() eq 'CloudLinux7'; - my %vetted = map { $_ => 1 } @vetted_repos; - my $repo_dir = Elevate::Constants::YUM_REPOS_D; my %status; @@ -264,17 +216,7 @@ sub _check_yum_repos ($self) { return unless length $current_repo_name; return unless $current_repo_enabled; - my $temp_current_repo_name = $current_repo_name; - - # ignore the number on rollout mirrors - # cloudlinux-rollout-1 becomes cloudlinux-rollout - # cloudlinux-ea4-1 becomes cloudlinux-ea4 - # cloudlinux-ea4-rollout-1 becomes cloudlinux-ea4-rollout - $current_repo_name = $1 if $current_repo_name =~ m/^(cloudlinux-(?:rollout|ea4)(?:-rollout)?)-[0-9]+$/; - - my $is_vetted = $vetted{$current_repo_name} || $vetted{ lc $current_repo_name }; - - $current_repo_name = $temp_current_repo_name; + my $is_vetted = grep { $current_repo_name =~ m/$_/ } @vetted_repos; if ( !$is_vetted ) { $status{'UNVETTED'} = 1; From b2412761d615a7f07c8e47a8a26797311296127d Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Tue, 13 Feb 2024 14:39:52 -0600 Subject: [PATCH 05/12] Only install epel-release post leapp if it is not already installed Case RE-18: This is a request from the review. Check to see if epel-release is installed before attempting to install it post leapp. Changelog: --- elevate-cpanel | 4 +++- lib/Elevate/Components/RpmDB.pm | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index db828068..455984c3 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -4030,7 +4030,9 @@ EOS my $epel_url = 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm'; - $self->dnf->install_rpm_via_url($epel_url); + unless ( Cpanel::Pkgr::is_installed('epel-release') ) { + $self->dnf->install_rpm_via_url($epel_url); + } $self->dnf->config_manager_enable('powertools'); $self->dnf->config_manager_enable('epel'); diff --git a/lib/Elevate/Components/RpmDB.pm b/lib/Elevate/Components/RpmDB.pm index 35c4f725..6e869cb7 100644 --- a/lib/Elevate/Components/RpmDB.pm +++ b/lib/Elevate/Components/RpmDB.pm @@ -53,7 +53,9 @@ sub _sysup ($self) { my $epel_url = 'https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm'; # no failures once already installed: no need to check for the epel-release version - $self->dnf->install_rpm_via_url($epel_url); + unless ( Cpanel::Pkgr::is_installed('epel-release') ) { + $self->dnf->install_rpm_via_url($epel_url); + } $self->dnf->config_manager_enable('powertools'); $self->dnf->config_manager_enable('epel'); From e353f0c5648ac2585c99fab4828c288bb6d040a2 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Tue, 13 Feb 2024 14:54:51 -0600 Subject: [PATCH 06/12] Update the name of sub to match the name of the flag it is named after Case RE-18: This is a request from the review. The sub `update_allow_raising` was intended to be named after the dnf flag `--allowerasing`. The name of the sub has now been changed to `update_allow_erasing` to reflect the name of the flag. Changelog: --- elevate-cpanel | 4 ++-- lib/Elevate/Components/RpmDB.pm | 2 +- lib/Elevate/DNF.pm | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 455984c3..b5fc8202 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -4042,7 +4042,7 @@ EOS local $ENV{'CPANEL_BASE_INSTALL'} = 1; # Don't fix more than perl itself. $self->ssystem(qw{/usr/local/cpanel/scripts/fix-cpanel-perl}); } - $self->dnf->update_allow_raising( '--disablerepo', 'cpanel-plugins' ); + $self->dnf->update_allow_erasing( '--disablerepo', 'cpanel-plugins' ); $self->ssystem_and_die(qw{/usr/local/cpanel/scripts/sysup}); return; @@ -5617,7 +5617,7 @@ EOS return; } - sub update_allow_raising ( $self, @args ) { + sub update_allow_erasing ( $self, @args ) { my $pkgmgr = $self->pkgmgr; my @additional_args = scalar @args ? @args : ''; diff --git a/lib/Elevate/Components/RpmDB.pm b/lib/Elevate/Components/RpmDB.pm index 6e869cb7..49416aa1 100644 --- a/lib/Elevate/Components/RpmDB.pm +++ b/lib/Elevate/Components/RpmDB.pm @@ -66,7 +66,7 @@ sub _sysup ($self) { local $ENV{'CPANEL_BASE_INSTALL'} = 1; # Don't fix more than perl itself. $self->ssystem(qw{/usr/local/cpanel/scripts/fix-cpanel-perl}); } - $self->dnf->update_allow_raising( '--disablerepo', 'cpanel-plugins' ); + $self->dnf->update_allow_erasing( '--disablerepo', 'cpanel-plugins' ); $self->ssystem_and_die(qw{/usr/local/cpanel/scripts/sysup}); return; diff --git a/lib/Elevate/DNF.pm b/lib/Elevate/DNF.pm index e27c823d..77bce640 100644 --- a/lib/Elevate/DNF.pm +++ b/lib/Elevate/DNF.pm @@ -28,7 +28,7 @@ sub config_manager_enable ( $self, $repo ) { return; } -sub update_allow_raising ( $self, @args ) { +sub update_allow_erasing ( $self, @args ) { my $pkgmgr = $self->pkgmgr; my @additional_args = scalar @args ? @args : ''; From 8c40aaa635724673655b1185c1069f60e34a9018 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Tue, 13 Feb 2024 15:02:26 -0600 Subject: [PATCH 07/12] Remove documentation of manual-reboots flag Case RE-18: This is a request from the review. I documented this flag while I was doing an audit of the POD for the necessary CloudLinux updates. However, since this is not relevant to CloudLinux, I am going to move this change to a separate PR via RE-186. Changelog: --- elevate-cpanel | 3 --- script/elevate-cpanel.PL | 3 --- 2 files changed, 6 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index b5fc8202..85090bef 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -5770,9 +5770,6 @@ CloudLinux 7 => CloudLinux 8 Once leapp has been run you should remove the file /waiting_for_distro_upgrade - --manual-reboots The script will stop and require the user to reboot manually rather than - automatically rebooting when reboots are needed - --help Display this documentation. =head1 COMMON USAGE diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index 97a406ae..2b21d4fe 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -75,9 +75,6 @@ CloudLinux 7 => CloudLinux 8 Once leapp has been run you should remove the file /waiting_for_distro_upgrade - --manual-reboots The script will stop and require the user to reboot manually rather than - automatically rebooting when reboots are needed - --help Display this documentation. =head1 COMMON USAGE From f033cf418088ef72b87ddbf090a788d8d071d0e8 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Wed, 14 Feb 2024 09:45:06 -0600 Subject: [PATCH 08/12] Teach Elevate::OS:instance() to emit a user friendly error Case RE-18: This is a request from the review. Instead of relying on Elevate::OS::is_supported() to be the first call into Elevate::OS, this change makes it so that Elevate::OS::instance() will always emit a user friendly error when it dies due to the OS not being supported. Changelog: --- elevate-cpanel | 28 ++++++++++++---------------- lib/Elevate/Blockers/Distros.pm | 14 ++------------ lib/Elevate/OS.pm | 14 ++++++++++---- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 85090bef..d11ab14d 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -806,11 +806,7 @@ EOS } sub _blocker_os_is_not_supported ($self) { - unless ( Elevate::OS::is_supported() ) { - my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); - return $self->has_blocker(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); - } - + Elevate::OS::is_supported(); # dies return 0; } @@ -838,13 +834,7 @@ EOS } sub bail_out_on_inappropriate_distro () { - - unless ( Elevate::OS::is_supported() ) { - my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); - FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); - exit 1; - } - + Elevate::OS::is_supported(); # dies return; } @@ -4258,20 +4248,26 @@ EOS $distro_with_version = $distro . $major; } - FATAL("Attempted to get factory for unsupported OS: $distro $major") unless grep { $_ eq $distro_with_version } SUPPORTED_DISTROS; - my $pkg = "Elevate::OS::" . $distro_with_version; return $pkg->new; } sub instance { - $OS //= factory(); + return $OS if $OS; + + $OS = eval { factory(); }; + + if ( !$OS ) { + my $supported_distros = join( "\n", get_supported_distros() ); + FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); + exit 1; + } return $OS; } sub is_supported () { - return eval { instance(); 1; } ? 1 : 0; + return instance(); # dies } sub get_supported_distros () { diff --git a/lib/Elevate/Blockers/Distros.pm b/lib/Elevate/Blockers/Distros.pm index 91b2407a..701a5bda 100644 --- a/lib/Elevate/Blockers/Distros.pm +++ b/lib/Elevate/Blockers/Distros.pm @@ -39,11 +39,7 @@ sub check ($self) { } sub _blocker_os_is_not_supported ($self) { - unless ( Elevate::OS::is_supported() ) { - my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); - return $self->has_blocker(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); - } - + Elevate::OS::is_supported(); # dies return 0; } @@ -72,13 +68,7 @@ sub _blocker_is_experimental_os ($self) { # We are OK if can_be_elevated or if sub bail_out_on_inappropriate_distro () { - - unless ( Elevate::OS::is_supported() ) { - my $supported_distros = join( "\n", Elevate::OS::get_supported_distros() ); - FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); - exit 1; - } - + Elevate::OS::is_supported(); # dies return; } diff --git a/lib/Elevate/OS.pm b/lib/Elevate/OS.pm index f790e758..6a31b35e 100644 --- a/lib/Elevate/OS.pm +++ b/lib/Elevate/OS.pm @@ -54,20 +54,26 @@ sub factory { $distro_with_version = $distro . $major; } - FATAL("Attempted to get factory for unsupported OS: $distro $major") unless grep { $_ eq $distro_with_version } SUPPORTED_DISTROS; - my $pkg = "Elevate::OS::" . $distro_with_version; return $pkg->new; } sub instance { - $OS //= factory(); + return $OS if $OS; + + $OS = eval { factory(); }; + + if ( !$OS ) { + my $supported_distros = join( "\n", get_supported_distros() ); + FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); + exit 1; + } return $OS; } sub is_supported () { - return eval { instance(); 1; } ? 1 : 0; + return instance(); # dies } sub get_supported_distros () { From 1decebf91d7051b8ad5f4620861707041aa42523 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Thu, 15 Feb 2024 09:22:20 -0600 Subject: [PATCH 09/12] Convert Elevate::OS to use constants rather than accessors Case RE-18: This is a request from the review. Since most of the data provided by Elevate::OS is constant, we should use constants rather than accessors to provide this data. There is less code involved this way and it makes the code cleaner/easier to read over time. Changelog: --- elevate-cpanel | 454 +++++++++---------------- lib/Elevate/Blockers/Repositories.pm | 61 +--- lib/Elevate/Components/Repositories.pm | 10 +- lib/Elevate/OS.pm | 147 ++++---- lib/Elevate/OS/Base.pm | 79 ----- lib/Elevate/OS/CentOS7.pm | 37 +- lib/Elevate/OS/CloudLinux7.pm | 76 ++--- lib/Elevate/OS/RHEL.pm | 80 +++++ script/elevate-cpanel.PL | 4 +- 9 files changed, 363 insertions(+), 585 deletions(-) delete mode 100644 lib/Elevate/OS/Base.pm create mode 100644 lib/Elevate/OS/RHEL.pm diff --git a/elevate-cpanel b/elevate-cpanel index d11ab14d..a2de99b9 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -52,9 +52,9 @@ BEGIN { # Suppress load of all of these at earliest point. $INC{'Elevate/Components/WPToolkit.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Components/SSH.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/OS.pm'} = 'script/elevate-cpanel.PL.static'; - $INC{'Elevate/OS/Base.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/OS/CentOS7.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/OS/CloudLinux7.pm'} = 'script/elevate-cpanel.PL.static'; + $INC{'Elevate/OS/RHEL.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Fetch.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Leapp.pm'} = 'script/elevate-cpanel.PL.static'; $INC{'Elevate/Logger.pm'} = 'script/elevate-cpanel.PL.static'; @@ -1567,64 +1567,6 @@ EOS # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - use constant DISABLE_MYSQL_YUM_REPOS => qw{ - Mysql57.repo - Mysql80.repo - - MariaDB102.repo - MariaDB103.repo - MariaDB105.repo - MariaDB106.repo - - mysql-community.repo - }; - - use constant VETTED_MYSQL_YUM_REPO_IDS => ( - qr/^mysql-cluster-[0-9.]{3}-community(?:-(?:source|debuginfo))?$/, - qr/^mysql-connectors-community(?:-(?:source|debuginfo))?$/, - qr/^mysql-tools-community(?:-(?:source|debuginfo))?$/, - qr/^mysql-tools-preview(?:-source)?$/, - qr/^mysql[0-9]{2}-community(?:-(?:source|debuginfo))?$/, - qr/^MariaDB[0-9]{3}$/, - ); - - use constant VETTED_CLOUDLINUX_YUM_REPO => ( - qr/^cloudlinux(?:-(?:base|updates|extras|compat|imunify360|elevate))?$/, - qr/^cloudlinux-rollout(?:-[0-9]+)?$/, - qr/^cloudlinux-ea4(?:-[0-9]+)?$/, - qr/^cloudlinux-ea4-rollout(?:-[0-9]+)?$/, - 'cl-ea4', - qr/^cl-mysql(?:-meta)?/, - ); - - use constant VETTED_YUM_REPO => ( - 'base', - 'c7-media', - qr/^centos-kernel(?:-experimental)?$/, - 'centosplus', - 'cp-dev-tools', - 'cpanel-addons-production-feed', - 'cpanel-plugins', - 'cr', - 'ct-preset', - 'digitalocean-agent', - 'droplet-agent', - qr/^EA4(?:-c\$releasever)?$/, - qr/^elasticsearch(?:7\.x)?$/, - qr/^elevate(?:-source)?$/, - qr/^epel(?:-testing)?$/, - 'extras', - 'fasttrack', - 'imunify360', - 'imunify360-ea-php-hardened', - qr/^imunify360-rollout-[0-9]+$/, - 'influxdb', - 'kernelcare', - 'updates', - qr/^wp-toolkit-(?:cpanel|thirdparties)$/, - ), - VETTED_MYSQL_YUM_REPO_IDS; - sub check ($self) { my $ok = 1; $ok = 0 unless $self->_blocker_system_update; @@ -1723,8 +1665,7 @@ EOS $self->{_yum_repos_to_disable} = []; $self->{_yum_repos_unsupported_with_packages} = []; - my @vetted_repos = (VETTED_YUM_REPO); - push( @vetted_repos, VETTED_CLOUDLINUX_YUM_REPO ) if Elevate::OS::name() eq 'CloudLinux7'; + my @vetted_repos = Elevate::OS::vetted_yum_repo(); my $repo_dir = Elevate::Constants::YUM_REPOS_D; @@ -3901,10 +3842,9 @@ EOS use cPstrict; - use Elevate::Constants (); - use Elevate::Blockers::Repositories (); - use Elevate::OS (); - use Elevate::RPM (); + use Elevate::Constants (); + use Elevate::OS (); + use Elevate::RPM (); use Cpanel::SafeRun::Simple (); use Cwd (); @@ -3928,8 +3868,7 @@ EOS sub _disable_known_yum_repositories { - my @repo_files = map { Elevate::Constants::YUM_REPOS_D . '/' . $_ } # - Elevate::Blockers::Repositories::DISABLE_MYSQL_YUM_REPOS; + my @repo_files = map { Elevate::Constants::YUM_REPOS_D . '/' . $_ } Elevate::OS::disable_mysql_yum_repos(); foreach my $f (@repo_files) { next unless -e $f; @@ -4205,34 +4144,16 @@ EOS use cPstrict; + use Carp (); + # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - use Elevate::OS::CentOS7; - use Elevate::OS::CloudLinux7; - - use constant SUPPORTED_DISTROS => qw{ - CentOS7 - CloudLinux7 - }; - - use constant PRETTY_SUPPORTED_DISTROS => ( + use constant SUPPORTED_DISTROS => ( 'CentOS 7', 'CloudLinux 7', ); - use constant AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7 => qw{ - alma - almalinux - rocky - rockylinux - }; - - use constant AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7 => qw{ - cloud - cloudlinux - }; - our $OS; sub factory { @@ -4248,8 +4169,13 @@ EOS $distro_with_version = $distro . $major; } - my $pkg = "Elevate::OS::" . $distro_with_version; - return $pkg->new; + my $class = "Elevate::OS::" . $distro_with_version; + my $class_path = "Elevate/OS/$distro_with_version.pm"; + + require $class unless $INC{$class_path}; + + my $self = bless {}, $class; + return $self; } sub instance { @@ -4258,7 +4184,7 @@ EOS $OS = eval { factory(); }; if ( !$OS ) { - my $supported_distros = join( "\n", get_supported_distros() ); + my $supported_distros = join( "\n", SUPPORTED_DISTROS() ); FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); exit 1; } @@ -4266,168 +4192,61 @@ EOS return $OS; } - sub is_supported () { - return instance(); # dies - } + my %methods; - sub get_supported_distros () { - return PRETTY_SUPPORTED_DISTROS; - } + BEGIN { - sub check_for_old_centos7 () { - return instance()->check_for_old_centos7(); + %methods = map { $_ => 0 } ( + 'available_upgrade_paths', # This returns a list of possible upgrade paths for the OS + 'default_upgrade_to', # This is the default OS that the current OS should upgrade to (i.e. CL7->CL8, C7->A8) + 'disable_mysql_yum_repos', # This is a list of mysql repo files to disable + 'ea_alias', # This is the value for the --target-os flag used when backing up an EA4 profile + 'elevate_rpm_url', # This is the URL used to install the leapp RPM/repo + 'is_supported', # This is used to determine if the OS is supported or not + 'leapp_can_handle_epel', # This is used to determine if we can skip removing the EPEL repo pre_leapp or not + 'leapp_can_handle_imunify', # This is used to determine if we can skip the Imunify component or not + 'leapp_can_handle_kernelcare', # This is used to determine if we can skip the kernelcare component or not + 'leapp_can_handle_python36', # This is used to determine if we can skip the python36 blocker or not + 'leapp_data_pkg', # This is used to determine which leapp data package to install + 'leapp_flag', # This is used to determine if we need to pass any flags to the leapp script or not + 'name', # This is the name of the OS we are upgrading from (i.e. CentOS7, or CloudLinux7) + 'pretty_name', # This is the pretty name of the OS we are upgrading from (i.e. 'CentOS 7') + 'vetted_mysql_yum_repo_ids', # This is a list of known mysql yum repo ids + 'vetted_yum_repo', # This is a list of known yum repos that we do not block on + ); } - sub default_upgrade_to () { - return instance()->default_upgrade_to(); + sub supported_methods { + return sort keys %methods; } - sub get_available_upgrade_paths { - my $name = instance()->name(); + our $AUTOLOAD; - if ( $name eq 'CentOS7' ) { - return AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; - } - elsif ( $name eq 'CloudLinux7' ) { - return AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; - } + sub AUTOLOAD { + my $sub = $AUTOLOAD; + $sub =~ s/.*:://; - return; - } + exists $methods{$sub} or Carp::Croak("$sub is not a supported data variable for Elevate::OS"); - sub name () { - return instance()->name(); + my $i = instance(); + my $can = $i->can($sub) or Carp::Croak( ref($i) . " does not implement $sub" ); + return $can->( $i, @_ ); } - sub pretty_name () { - return instance()->pretty_name(); - } + sub DESTROY { } # This is a must for autoload modules sub can_upgrade_to ($flavor) { - my $name = instance()->name(); - - if ( $name eq 'CentOS7' ) { - return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; - } - elsif ( $name eq 'CloudLinux7' ) { - return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; - } - - return 0; - } - - sub leapp_can_handle_epel () { - return instance()->leapp_can_handle_epel(); - } - - sub leapp_can_handle_imunify () { - return instance()->leapp_can_handle_imunify(); - } - - sub leapp_can_handle_kernelcare () { - return instance()->leapp_can_handle_kernelcare(); - } - - sub ea_alias () { - return instance()->ea_alias(); - } - - sub elevate_rpm_url () { - return instance()->elevate_rpm_url(); - } - - sub leapp_data_pkg () { - return instance()->leapp_data_pkg(); + return grep { $_ eq $flavor } Elevate::OS::available_upgrade_paths(); } sub upgrade_to () { - return instance()->upgrade_to(); - } - - sub leapp_flag () { - return instance()->leapp_flag(); - } - - sub leapp_can_handle_python36 () { - return instance()->leapp_can_handle_python36(); - } - - 1; - -} # --- END lib/Elevate/OS.pm - -{ # --- BEGIN lib/Elevate/OS/Base.pm - - package Elevate::OS::Base; - - use cPstrict; - - # use Log::Log4perl qw(:easy); - INIT { Log::Log4perl->import(qw{:easy}); } - - use Simple::Accessor qw{ - ea_alias - elevate_rpm_url - default_upgrade_to - leapp_can_handle_epel - leapp_can_handle_imunify - leapp_can_handle_kernelcare - leapp_can_handle_python36 - leapp_data_pkg - leapp_flag - name - pretty_name - upgrade_to - }; - - sub _build_ea_alias ($self) { - return 'CentOS_8'; - } - - sub _build_elevate_rpm_url ($self) { - die "subclass must implement elevate_rpm_url\n"; - } - - sub _build_default_upgrade_to ($self) { - die "subclass must implement default_upgrade_to\n"; - } - - sub _build_leapp_can_handle_epel ($self) { - return 0; - } - - sub _build_leapp_can_handle_imunify ($self) { - return 0; - } - - sub _build_leapp_can_handle_kernelcare ($self) { - return 0; - } - - sub _build_leapp_can_handle_python36 ($self) { - return 0; - } - - sub _build_leapp_data_pkg ($self) { - die "subclass must implement leapp_data_pkg\n"; - } - - sub _build_name ($self) { - die "subclass must implement name\n"; - } - - sub _build_pretty_name ($self) { - die "subclass must implment pretty_name\n"; - } - - sub _build_upgrade_to ($self) { - my $default = $self->default_upgrade_to(); + my $default = Elevate::OS::default_upgrade_to(); return cpev::read_stage_file( 'upgrade_to', $default ); } 1; -} # --- END lib/Elevate/OS/Base.pm +} # --- END lib/Elevate/OS.pm { # --- BEGIN lib/Elevate/OS/CentOS7.pm @@ -4438,31 +4257,28 @@ EOS # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - # use Elevate::OS::Base(); + # use Elevate::OS::RHEL(); our @ISA; - BEGIN { push @ISA, qw(Elevate::OS::Base); } + BEGIN { push @ISA, qw(Elevate::OS::RHEL); } - sub _build_elevate_rpm_url ($self) { - return 'https://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm'; - } + use constant available_upgrade_paths => ( + 'alma', + 'almalinux', + 'rocky', + 'rockylinux', + ); - sub _build_default_upgrade_to ($self) { - return 'almalinux'; - } + use constant default_upgrade_to => 'AlmaLinux'; + use constant ea_alias => 'CentOS_8'; + use constant elevate_rpm_url => 'https://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm'; + use constant name => 'CentOS7'; + use constant pretty_name => 'CentOS 7'; - sub _build_leapp_data_pkg ($self) { - my $upgrade_to = $self->upgrade_to(); + sub leapp_data_pkg () { + my $upgrade_to = Elevate::OS::upgrade_to(); return $upgrade_to =~ m/^rocky/ai ? 'leapp-data-rocky' : 'leapp-data-almalinux'; } - sub _build_name ($self) { - return 'CentOS7'; - } - - sub _build_pretty_name ($self) { - return 'CentOS 7'; - } - 1; } # --- END lib/Elevate/OS/CentOS7.pm @@ -4476,57 +4292,121 @@ EOS # use Log::Log4perl qw(:easy); INIT { Log::Log4perl->import(qw{:easy}); } - # use Elevate::OS::Base(); + # use Elevate::OS::RHEL(); our @ISA; - BEGIN { push @ISA, qw(Elevate::OS::Base); } + BEGIN { push @ISA, qw(Elevate::OS::RHEL); } - sub _build_ea_alias ($self) { - return 'CloudLinux_8'; - } + use constant available_upgrade_paths => ( + 'cloud', + 'cloudlinux', + ); - sub _build_elevate_rpm_url ($self) { - return 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; - } + use constant default_upgrade_to => 'CloudLinux'; + use constant ea_alias => 'CloudLinux_8'; + use constant elevate_rpm_url => 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; + use constant leapp_can_handle_epel => 1; + use constant leapp_can_handle_imunify => 1; + use constant leapp_can_handle_kernelcare => 1; + use constant leapp_can_handle_python36 => 1; + use constant leapp_data_pkg => 'leapp-data-cloudlinux'; + use constant leapp_flag => '--nowarn'; + use constant name => 'CloudLinux7'; + use constant pretty_name => 'CloudLinux 7'; + + sub vetted_yum_repo ($self) { + my @vetted_cloudlinux_yum_repo = ( + qr/^cloudlinux(?:-(?:base|updates|extras|compat|imunify360|elevate))?$/, + qr/^cloudlinux-rollout(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4-rollout(?:-[0-9]+)?$/, + 'cl-ea4', + qr/^cl-mysql(?:-meta)?/, + ); - sub _build_default_upgrade_to ($self) { - return 'CloudLinux'; + my @repos = $self->SUPER::vetted_yum_repo(); + push @repos, @vetted_cloudlinux_yum_repo; + return @repos; } - sub _build_leapp_can_handle_epel ($self) { - return 1; - } + 1; - sub _build_leapp_can_handle_imunify ($self) { - return 1; - } +} # --- END lib/Elevate/OS/CloudLinux7.pm - sub _build_leapp_can_handle_kernelcare ($self) { - return 1; - } +{ # --- BEGIN lib/Elevate/OS/RHEL.pm - sub _build_leapp_can_handle_python36 ($self) { - return 1; - } + package Elevate::OS::RHEL; - sub _build_leapp_data_pkg ($self) { - return 'leapp-data-cloudlinux'; - } + use cPstrict; - sub _build_leapp_flag ($self) { - return '--nowarn'; - } + # use Log::Log4perl qw(:easy); + INIT { Log::Log4perl->import(qw{:easy}); } - sub _build_name ($self) { - return 'CloudLinux7'; - } + use constant disable_mysql_yum_repos => qw{ + Mysql57.repo + Mysql80.repo - sub _build_pretty_name ($self) { - return 'CloudLinux 7'; - } + MariaDB102.repo + MariaDB103.repo + MariaDB105.repo + MariaDB106.repo + + mysql-community.repo + }; + + use constant vetted_mysql_yum_repo_ids => ( + qr/^mysql-cluster-[0-9.]{3}-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-connectors-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-preview(?:-source)?$/, + qr/^mysql[0-9]{2}-community(?:-(?:source|debuginfo))?$/, + qr/^MariaDB[0-9]{3}$/, + ); + + use constant vetted_yum_repo => ( + 'base', + 'c7-media', + qr/^centos-kernel(?:-experimental)?$/, + 'centosplus', + 'cp-dev-tools', + 'cpanel-addons-production-feed', + 'cpanel-plugins', + 'cr', + 'ct-preset', + 'digitalocean-agent', + 'droplet-agent', + qr/^EA4(?:-c\$releasever)?$/, + qr/^elasticsearch(?:7\.x)?$/, + qr/^elevate(?:-source)?$/, + qr/^epel(?:-testing)?$/, + 'extras', + 'fasttrack', + 'imunify360', + 'imunify360-ea-php-hardened', + qr/^imunify360-rollout-[0-9]+$/, + 'influxdb', + 'kernelcare', + 'updates', + qr/^wp-toolkit-(?:cpanel|thirdparties)$/, + ), + vetted_mysql_yum_repo_ids; + + use constant available_upgrade_paths => undef; + use constant default_upgrade_to => undef; + use constant ea_alias => undef; + use constant elevate_rpm_url => undef; + use constant is_supported => 1; + use constant leapp_can_handle_epel => 0; + use constant leapp_can_handle_imunify => 0; + use constant leapp_can_handle_kernelcare => 0; + use constant leapp_can_handle_python36 => 0; + use constant leapp_data_package => undef; + use constant leapp_flag => undef; + use constant name => 'RHEL'; + use constant pretty_name => 'RHEL'; 1; -} # --- END lib/Elevate/OS/CloudLinux7.pm +} # --- END lib/Elevate/OS/RHEL.pm { # --- BEGIN lib/Elevate/Fetch.pm @@ -5992,9 +5872,9 @@ use Elevate::Components::SSH (); # - fatpack OS use Elevate::OS (); -use Elevate::OS::Base (); use Elevate::OS::CentOS7 (); use Elevate::OS::CloudLinux7 (); +use Elevate::OS::RHEL (); use Elevate::Fetch (); use Elevate::Leapp (); @@ -6170,7 +6050,7 @@ sub _parse_opt_upgrade_to ($self) { $flavor = lc $flavor; if ( !Elevate::OS::can_upgrade_to($flavor) ) { - my @available_flavors = Elevate::OS::get_available_upgrade_paths(); + my @available_flavors = Elevate::OS::available_upgrade_paths(); my $af = join( "\n", @available_flavors ); die qq[The current OS can only upgrade to the following flavors:\n\n$af\n]; } diff --git a/lib/Elevate/Blockers/Repositories.pm b/lib/Elevate/Blockers/Repositories.pm index ac6df5d3..a5d04e7f 100644 --- a/lib/Elevate/Blockers/Repositories.pm +++ b/lib/Elevate/Blockers/Repositories.pm @@ -22,64 +22,6 @@ use parent qw{Elevate::Blockers::Base}; use Log::Log4perl qw(:easy); -# still used by disable_known_yum_repositories function -use constant DISABLE_MYSQL_YUM_REPOS => qw{ - Mysql57.repo - Mysql80.repo - - MariaDB102.repo - MariaDB103.repo - MariaDB105.repo - MariaDB106.repo - - mysql-community.repo -}; - -use constant VETTED_MYSQL_YUM_REPO_IDS => ( - qr/^mysql-cluster-[0-9.]{3}-community(?:-(?:source|debuginfo))?$/, - qr/^mysql-connectors-community(?:-(?:source|debuginfo))?$/, - qr/^mysql-tools-community(?:-(?:source|debuginfo))?$/, - qr/^mysql-tools-preview(?:-source)?$/, - qr/^mysql[0-9]{2}-community(?:-(?:source|debuginfo))?$/, - qr/^MariaDB[0-9]{3}$/, -); - -use constant VETTED_CLOUDLINUX_YUM_REPO => ( - qr/^cloudlinux(?:-(?:base|updates|extras|compat|imunify360|elevate))?$/, - qr/^cloudlinux-rollout(?:-[0-9]+)?$/, - qr/^cloudlinux-ea4(?:-[0-9]+)?$/, - qr/^cloudlinux-ea4-rollout(?:-[0-9]+)?$/, - 'cl-ea4', - qr/^cl-mysql(?:-meta)?/, -); - -use constant VETTED_YUM_REPO => ( - 'base', - 'c7-media', - qr/^centos-kernel(?:-experimental)?$/, - 'centosplus', - 'cp-dev-tools', - 'cpanel-addons-production-feed', - 'cpanel-plugins', - 'cr', - 'ct-preset', - 'digitalocean-agent', - 'droplet-agent', - qr/^EA4(?:-c\$releasever)?$/, - qr/^elasticsearch(?:7\.x)?$/, - qr/^elevate(?:-source)?$/, - qr/^epel(?:-testing)?$/, - 'extras', - 'fasttrack', - 'imunify360', - 'imunify360-ea-php-hardened', - qr/^imunify360-rollout-[0-9]+$/, - 'influxdb', - 'kernelcare', - 'updates', - qr/^wp-toolkit-(?:cpanel|thirdparties)$/, -), VETTED_MYSQL_YUM_REPO_IDS; - sub check ($self) { my $ok = 1; $ok = 0 unless $self->_blocker_system_update; @@ -188,8 +130,7 @@ sub _check_yum_repos ($self) { $self->{_yum_repos_to_disable} = []; $self->{_yum_repos_unsupported_with_packages} = []; - my @vetted_repos = (VETTED_YUM_REPO); - push( @vetted_repos, VETTED_CLOUDLINUX_YUM_REPO ) if Elevate::OS::name() eq 'CloudLinux7'; + my @vetted_repos = Elevate::OS::vetted_yum_repo(); my $repo_dir = Elevate::Constants::YUM_REPOS_D; diff --git a/lib/Elevate/Components/Repositories.pm b/lib/Elevate/Components/Repositories.pm index 8f6bd5ad..31716954 100644 --- a/lib/Elevate/Components/Repositories.pm +++ b/lib/Elevate/Components/Repositories.pm @@ -12,10 +12,9 @@ Disable some repostiories. use cPstrict; -use Elevate::Constants (); -use Elevate::Blockers::Repositories (); -use Elevate::OS (); -use Elevate::RPM (); +use Elevate::Constants (); +use Elevate::OS (); +use Elevate::RPM (); use Cpanel::SafeRun::Simple (); use Cwd (); @@ -36,8 +35,7 @@ sub pre_leapp ($self) { sub _disable_known_yum_repositories { # remove all MySQL repos - my @repo_files = map { Elevate::Constants::YUM_REPOS_D . '/' . $_ } # - Elevate::Blockers::Repositories::DISABLE_MYSQL_YUM_REPOS; + my @repo_files = map { Elevate::Constants::YUM_REPOS_D . '/' . $_ } Elevate::OS::disable_mysql_yum_repos(); foreach my $f (@repo_files) { next unless -e $f; diff --git a/lib/Elevate/OS.pm b/lib/Elevate/OS.pm index 6a31b35e..83638b18 100644 --- a/lib/Elevate/OS.pm +++ b/lib/Elevate/OS.pm @@ -12,33 +12,15 @@ Abstract interface to the OS to obviate the need for if-this-os-do-this-elsif-el use cPstrict; -use Log::Log4perl qw(:easy); - -use Elevate::OS::CentOS7; -use Elevate::OS::CloudLinux7; +use Carp (); -use constant SUPPORTED_DISTROS => qw{ - CentOS7 - CloudLinux7 -}; +use Log::Log4perl qw(:easy); -use constant PRETTY_SUPPORTED_DISTROS => ( +use constant SUPPORTED_DISTROS => ( 'CentOS 7', 'CloudLinux 7', ); -use constant AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7 => qw{ - alma - almalinux - rocky - rockylinux -}; - -use constant AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7 => qw{ - cloud - cloudlinux -}; - our $OS; sub factory { @@ -54,8 +36,15 @@ sub factory { $distro_with_version = $distro . $major; } - my $pkg = "Elevate::OS::" . $distro_with_version; - return $pkg->new; + my $class = "Elevate::OS::" . $distro_with_version; + my $class_path = "Elevate/OS/$distro_with_version.pm"; + + # Ok if it dies since instance() should be the only thing calling this + # Since this is a fat packed script, we only want to require the class in tests + require $class unless $INC{$class_path}; + + my $self = bless {}, $class; + return $self; } sub instance { @@ -64,7 +53,7 @@ sub instance { $OS = eval { factory(); }; if ( !$OS ) { - my $supported_distros = join( "\n", get_supported_distros() ); + my $supported_distros = join( "\n", SUPPORTED_DISTROS() ); FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); exit 1; } @@ -72,90 +61,74 @@ sub instance { return $OS; } -sub is_supported () { - return instance(); # dies -} +## NOTE: private methods (beginning with _) are NOT allowed in this list! +my %methods; -sub get_supported_distros () { - return PRETTY_SUPPORTED_DISTROS; -} +BEGIN { -sub check_for_old_centos7 () { - return instance()->check_for_old_centos7(); + # The key specifies what the method that all platforms we support. + # The value specifies how many args the method is designed to take. + %methods = map { $_ => 0 } ( + ### General distro specific methods. + 'available_upgrade_paths', # This returns a list of possible upgrade paths for the OS + 'default_upgrade_to', # This is the default OS that the current OS should upgrade to (i.e. CL7->CL8, C7->A8) + 'disable_mysql_yum_repos', # This is a list of mysql repo files to disable + 'ea_alias', # This is the value for the --target-os flag used when backing up an EA4 profile + 'elevate_rpm_url', # This is the URL used to install the leapp RPM/repo + 'is_supported', # This is used to determine if the OS is supported or not + 'leapp_can_handle_epel', # This is used to determine if we can skip removing the EPEL repo pre_leapp or not + 'leapp_can_handle_imunify', # This is used to determine if we can skip the Imunify component or not + 'leapp_can_handle_kernelcare', # This is used to determine if we can skip the kernelcare component or not + 'leapp_can_handle_python36', # This is used to determine if we can skip the python36 blocker or not + 'leapp_data_pkg', # This is used to determine which leapp data package to install + 'leapp_flag', # This is used to determine if we need to pass any flags to the leapp script or not + 'name', # This is the name of the OS we are upgrading from (i.e. CentOS7, or CloudLinux7) + 'pretty_name', # This is the pretty name of the OS we are upgrading from (i.e. 'CentOS 7') + 'vetted_mysql_yum_repo_ids', # This is a list of known mysql yum repo ids + 'vetted_yum_repo', # This is a list of known yum repos that we do not block on + ); } -sub default_upgrade_to () { - return instance()->default_upgrade_to(); +sub supported_methods { + return sort keys %methods; } -sub get_available_upgrade_paths { - my $name = instance()->name(); +our $AUTOLOAD; - if ( $name eq 'CentOS7' ) { - return AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; - } - elsif ( $name eq 'CloudLinux7' ) { - return AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; - } +sub AUTOLOAD { + my $sub = $AUTOLOAD; + $sub =~ s/.*:://; - return; -} + exists $methods{$sub} or Carp::Croak("$sub is not a supported data variable for Elevate::OS"); -sub name () { - return instance()->name(); + my $i = instance(); + my $can = $i->can($sub) or Carp::Croak( ref($i) . " does not implement $sub" ); + return $can->( $i, @_ ); } -sub pretty_name () { - return instance()->pretty_name(); -} +sub DESTROY { } # This is a must for autoload modules -sub can_upgrade_to ($flavor) { - my $name = instance()->name(); +=head1 can_upgrade_to - if ( $name eq 'CentOS7' ) { - return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CENTOS_7; - } - elsif ( $name eq 'CloudLinux7' ) { - return grep { $_ eq $flavor } AVAILABLE_UPGRADE_PATHS_FOR_CLOUDLINUX_7; - } +This returns true or false depending on whether the current OS +is able to upgrade to the requested OS or not. - return 0; -} - -sub leapp_can_handle_epel () { - return instance()->leapp_can_handle_epel(); -} +=cut -sub leapp_can_handle_imunify () { - return instance()->leapp_can_handle_imunify(); +sub can_upgrade_to ($flavor) { + return grep { $_ eq $flavor } Elevate::OS::available_upgrade_paths(); } -sub leapp_can_handle_kernelcare () { - return instance()->leapp_can_handle_kernelcare(); -} +=head1 upgrade_to -sub ea_alias () { - return instance()->ea_alias(); -} +This is the name of the OS we are upgrading to. Data is stored +within the stages file. -sub elevate_rpm_url () { - return instance()->elevate_rpm_url(); -} - -sub leapp_data_pkg () { - return instance()->leapp_data_pkg(); -} +=cut sub upgrade_to () { - return instance()->upgrade_to(); -} - -sub leapp_flag () { - return instance()->leapp_flag(); -} - -sub leapp_can_handle_python36 () { - return instance()->leapp_can_handle_python36(); + my $default = Elevate::OS::default_upgrade_to(); + return cpev::read_stage_file( 'upgrade_to', $default ); } 1; diff --git a/lib/Elevate/OS/Base.pm b/lib/Elevate/OS/Base.pm deleted file mode 100644 index 4b326da9..00000000 --- a/lib/Elevate/OS/Base.pm +++ /dev/null @@ -1,79 +0,0 @@ -package Elevate::OS::Base; - -=encoding utf-8 - -=head1 NAME - -Elevate::OS::Base - -This is a base class currently used by Elevate::OS::* - -=cut - -use cPstrict; - -use Log::Log4perl qw(:easy); - -use Simple::Accessor qw{ - ea_alias - elevate_rpm_url - default_upgrade_to - leapp_can_handle_epel - leapp_can_handle_imunify - leapp_can_handle_kernelcare - leapp_can_handle_python36 - leapp_data_pkg - leapp_flag - name - pretty_name - upgrade_to -}; - -# NOTE: AlmaLinux_8 is just an alias for CentOS_8 so it really doesn't matter -# which of the two is used -sub _build_ea_alias ($self) { - return 'CentOS_8'; -} - -sub _build_elevate_rpm_url ($self) { - die "subclass must implement elevate_rpm_url\n"; -} - -sub _build_default_upgrade_to ($self) { - die "subclass must implement default_upgrade_to\n"; -} - -sub _build_leapp_can_handle_epel ($self) { - return 0; -} - -sub _build_leapp_can_handle_imunify ($self) { - return 0; -} - -sub _build_leapp_can_handle_kernelcare ($self) { - return 0; -} - -sub _build_leapp_can_handle_python36 ($self) { - return 0; -} - -sub _build_leapp_data_pkg ($self) { - die "subclass must implement leapp_data_pkg\n"; -} - -sub _build_name ($self) { - die "subclass must implement name\n"; -} - -sub _build_pretty_name ($self) { - die "subclass must implment pretty_name\n"; -} - -sub _build_upgrade_to ($self) { - my $default = $self->default_upgrade_to(); - return cpev::read_stage_file( 'upgrade_to', $default ); -} - -1; diff --git a/lib/Elevate/OS/CentOS7.pm b/lib/Elevate/OS/CentOS7.pm index f5aedfec..46445af7 100644 --- a/lib/Elevate/OS/CentOS7.pm +++ b/lib/Elevate/OS/CentOS7.pm @@ -12,27 +12,24 @@ use cPstrict; use Log::Log4perl qw(:easy); -use parent 'Elevate::OS::Base'; - -sub _build_elevate_rpm_url ($self) { - return 'https://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm'; -} - -sub _build_default_upgrade_to ($self) { - return 'almalinux'; -} - -sub _build_leapp_data_pkg ($self) { - my $upgrade_to = $self->upgrade_to(); +use parent 'Elevate::OS::RHEL'; + +use constant available_upgrade_paths => ( + 'alma', + 'almalinux', + 'rocky', + 'rockylinux', +); + +use constant default_upgrade_to => 'AlmaLinux'; +use constant ea_alias => 'CentOS_8'; +use constant elevate_rpm_url => 'https://repo.almalinux.org/elevate/elevate-release-latest-el7.noarch.rpm'; +use constant name => 'CentOS7'; +use constant pretty_name => 'CentOS 7'; + +sub leapp_data_pkg () { + my $upgrade_to = Elevate::OS::upgrade_to(); return $upgrade_to =~ m/^rocky/ai ? 'leapp-data-rocky' : 'leapp-data-almalinux'; } -sub _build_name ($self) { - return 'CentOS7'; -} - -sub _build_pretty_name ($self) { - return 'CentOS 7'; -} - 1; diff --git a/lib/Elevate/OS/CloudLinux7.pm b/lib/Elevate/OS/CloudLinux7.pm index 278989ce..428388e6 100644 --- a/lib/Elevate/OS/CloudLinux7.pm +++ b/lib/Elevate/OS/CloudLinux7.pm @@ -12,50 +12,38 @@ use cPstrict; use Log::Log4perl qw(:easy); -use parent 'Elevate::OS::Base'; - -sub _build_ea_alias ($self) { - return 'CloudLinux_8'; -} - -sub _build_elevate_rpm_url ($self) { - return 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; -} - -sub _build_default_upgrade_to ($self) { - return 'CloudLinux'; -} - -sub _build_leapp_can_handle_epel ($self) { - return 1; -} - -sub _build_leapp_can_handle_imunify ($self) { - return 1; -} - -sub _build_leapp_can_handle_kernelcare ($self) { - return 1; -} - -sub _build_leapp_can_handle_python36 ($self) { - return 1; -} - -sub _build_leapp_data_pkg ($self) { - return 'leapp-data-cloudlinux'; -} - -sub _build_leapp_flag ($self) { - return '--nowarn'; -} - -sub _build_name ($self) { - return 'CloudLinux7'; -} - -sub _build_pretty_name ($self) { - return 'CloudLinux 7'; +use parent 'Elevate::OS::RHEL'; + +use constant available_upgrade_paths => ( + 'cloud', + 'cloudlinux', +); + +use constant default_upgrade_to => 'CloudLinux'; +use constant ea_alias => 'CloudLinux_8'; +use constant elevate_rpm_url => 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; +use constant leapp_can_handle_epel => 1; +use constant leapp_can_handle_imunify => 1; +use constant leapp_can_handle_kernelcare => 1; +use constant leapp_can_handle_python36 => 1; +use constant leapp_data_pkg => 'leapp-data-cloudlinux'; +use constant leapp_flag => '--nowarn'; +use constant name => 'CloudLinux7'; +use constant pretty_name => 'CloudLinux 7'; + +sub vetted_yum_repo ($self) { + my @vetted_cloudlinux_yum_repo = ( + qr/^cloudlinux(?:-(?:base|updates|extras|compat|imunify360|elevate))?$/, + qr/^cloudlinux-rollout(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4(?:-[0-9]+)?$/, + qr/^cloudlinux-ea4-rollout(?:-[0-9]+)?$/, + 'cl-ea4', + qr/^cl-mysql(?:-meta)?/, + ); + + my @repos = $self->SUPER::vetted_yum_repo(); + push @repos, @vetted_cloudlinux_yum_repo; + return @repos; } 1; diff --git a/lib/Elevate/OS/RHEL.pm b/lib/Elevate/OS/RHEL.pm new file mode 100644 index 00000000..31fbea12 --- /dev/null +++ b/lib/Elevate/OS/RHEL.pm @@ -0,0 +1,80 @@ +package Elevate::OS::RHEL; + +=encoding utf-8 + +=head1 NAME + +Elevate::OS::RHEL + +Rhel base class + +=cut + +use cPstrict; + +use Log::Log4perl qw(:easy); + +use constant disable_mysql_yum_repos => qw{ + Mysql57.repo + Mysql80.repo + + MariaDB102.repo + MariaDB103.repo + MariaDB105.repo + MariaDB106.repo + + mysql-community.repo +}; + +use constant vetted_mysql_yum_repo_ids => ( + qr/^mysql-cluster-[0-9.]{3}-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-connectors-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-community(?:-(?:source|debuginfo))?$/, + qr/^mysql-tools-preview(?:-source)?$/, + qr/^mysql[0-9]{2}-community(?:-(?:source|debuginfo))?$/, + qr/^MariaDB[0-9]{3}$/, +); + +use constant vetted_yum_repo => ( + 'base', + 'c7-media', + qr/^centos-kernel(?:-experimental)?$/, + 'centosplus', + 'cp-dev-tools', + 'cpanel-addons-production-feed', + 'cpanel-plugins', + 'cr', + 'ct-preset', + 'digitalocean-agent', + 'droplet-agent', + qr/^EA4(?:-c\$releasever)?$/, + qr/^elasticsearch(?:7\.x)?$/, + qr/^elevate(?:-source)?$/, + qr/^epel(?:-testing)?$/, + 'extras', + 'fasttrack', + 'imunify360', + 'imunify360-ea-php-hardened', + qr/^imunify360-rollout-[0-9]+$/, + 'influxdb', + 'kernelcare', + 'updates', + qr/^wp-toolkit-(?:cpanel|thirdparties)$/, + ), + vetted_mysql_yum_repo_ids; + +use constant available_upgrade_paths => undef; +use constant default_upgrade_to => undef; +use constant ea_alias => undef; +use constant elevate_rpm_url => undef; +use constant is_supported => 1; +use constant leapp_can_handle_epel => 0; +use constant leapp_can_handle_imunify => 0; +use constant leapp_can_handle_kernelcare => 0; +use constant leapp_can_handle_python36 => 0; +use constant leapp_data_package => undef; +use constant leapp_flag => undef; +use constant name => 'RHEL'; +use constant pretty_name => 'RHEL'; + +1; diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index 2b21d4fe..c5e75e39 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -301,9 +301,9 @@ use Elevate::Components::SSH (); # - fatpack OS use Elevate::OS (); -use Elevate::OS::Base (); use Elevate::OS::CentOS7 (); use Elevate::OS::CloudLinux7 (); +use Elevate::OS::RHEL (); use Elevate::Fetch (); use Elevate::Leapp (); @@ -479,7 +479,7 @@ sub _parse_opt_upgrade_to ($self) { $flavor = lc $flavor; if ( !Elevate::OS::can_upgrade_to($flavor) ) { - my @available_flavors = Elevate::OS::get_available_upgrade_paths(); + my @available_flavors = Elevate::OS::available_upgrade_paths(); my $af = join( "\n", @available_flavors ); die qq[The current OS can only upgrade to the following flavors:\n\n$af\n]; } From 64857540d2336596ce9e700f2b59403df03f26aa Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Thu, 15 Feb 2024 12:53:28 -0600 Subject: [PATCH 10/12] Fix wording on DB governor blocker Case RE-18: This is a request from the review. This adds the word currently to the message to imply that it may be supported in a future update. Changelog: --- elevate-cpanel | 2 +- lib/Elevate/Blockers/Databases.pm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index a2de99b9..91bdbf96 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -653,7 +653,7 @@ BEGIN { # Suppress load of all of these at earliest point. if ( Cpanel::Pkgr::is_installed('governor-mysql') ) { return $self->has_blocker( <<~'EOS' ); -You have MySQL Governor installed. Upgrades with this software in place are not supported. +You have MySQL Governor installed. Upgrades with this software in place are not currently supported. For more information regarding MySQL Governor, please review the documentation: https://docs.cloudlinux.com/shared/cloudlinux_os_components/#mysql-governor diff --git a/lib/Elevate/Blockers/Databases.pm b/lib/Elevate/Blockers/Databases.pm index 4c1f6062..1c2dd8b0 100644 --- a/lib/Elevate/Blockers/Databases.pm +++ b/lib/Elevate/Blockers/Databases.pm @@ -191,7 +191,7 @@ sub _blocker_mysql_governor ($self) { if ( Cpanel::Pkgr::is_installed('governor-mysql') ) { return $self->has_blocker( <<~'EOS' ); -You have MySQL Governor installed. Upgrades with this software in place are not supported. +You have MySQL Governor installed. Upgrades with this software in place are not currently supported. For more information regarding MySQL Governor, please review the documentation: https://docs.cloudlinux.com/shared/cloudlinux_os_components/#mysql-governor From 2b103bb059c3c2ae46ff65f3d51b48b5f0667aa9 Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Thu, 15 Feb 2024 14:52:14 -0600 Subject: [PATCH 11/12] Update unit tests for review changes Case RE-18: This is a request from the review. The review changes led to a few failures amongst the unit tests. This change ensures all the unit tests now pass again, and fixes a couple minor bugs. Changelog: --- elevate-cpanel | 7 +++---- lib/Elevate/OS.pm | 5 ++--- lib/Elevate/OS/CentOS7.pm | 2 +- t/blocker-Distros.t | 14 ++++---------- t/blocker-Repositories.t | 8 ++++++-- t/blocker-ea4.t | 2 +- t/lib/Test/Elevate.pm | 6 +++--- 7 files changed, 20 insertions(+), 24 deletions(-) diff --git a/elevate-cpanel b/elevate-cpanel index 91bdbf96..1a8513b2 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -4172,7 +4172,7 @@ EOS my $class = "Elevate::OS::" . $distro_with_version; my $class_path = "Elevate/OS/$distro_with_version.pm"; - require $class unless $INC{$class_path}; + require $class_path unless $INC{$class_path}; my $self = bless {}, $class; return $self; @@ -4185,8 +4185,7 @@ EOS if ( !$OS ) { my $supported_distros = join( "\n", SUPPORTED_DISTROS() ); - FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); - exit 1; + die "This script is only designed to upgrade the following OSs:\n\n$supported_distros\n"; } return $OS; @@ -4274,7 +4273,7 @@ EOS use constant name => 'CentOS7'; use constant pretty_name => 'CentOS 7'; - sub leapp_data_pkg () { + sub leapp_data_pkg ($self) { my $upgrade_to = Elevate::OS::upgrade_to(); return $upgrade_to =~ m/^rocky/ai ? 'leapp-data-rocky' : 'leapp-data-almalinux'; } diff --git a/lib/Elevate/OS.pm b/lib/Elevate/OS.pm index 83638b18..8353f4e8 100644 --- a/lib/Elevate/OS.pm +++ b/lib/Elevate/OS.pm @@ -41,7 +41,7 @@ sub factory { # Ok if it dies since instance() should be the only thing calling this # Since this is a fat packed script, we only want to require the class in tests - require $class unless $INC{$class_path}; + require $class_path unless $INC{$class_path}; my $self = bless {}, $class; return $self; @@ -54,8 +54,7 @@ sub instance { if ( !$OS ) { my $supported_distros = join( "\n", SUPPORTED_DISTROS() ); - FATAL(qq[This script is only designed to upgrade the following OSs:\n\n$supported_distros]); - exit 1; + die "This script is only designed to upgrade the following OSs:\n\n$supported_distros\n"; } return $OS; diff --git a/lib/Elevate/OS/CentOS7.pm b/lib/Elevate/OS/CentOS7.pm index 46445af7..6c4f53eb 100644 --- a/lib/Elevate/OS/CentOS7.pm +++ b/lib/Elevate/OS/CentOS7.pm @@ -27,7 +27,7 @@ use constant elevate_rpm_url => 'https://repo.almalinux.org/elevate/elevate-r use constant name => 'CentOS7'; use constant pretty_name => 'CentOS 7'; -sub leapp_data_pkg () { +sub leapp_data_pkg ($self) { my $upgrade_to = Elevate::OS::upgrade_to(); return $upgrade_to =~ m/^rocky/ai ? 'leapp-data-rocky' : 'leapp-data-almalinux'; } diff --git a/t/blocker-Distros.t b/t/blocker-Distros.t index 653b0f38..89dd6c87 100644 --- a/t/blocker-Distros.t +++ b/t/blocker-Distros.t @@ -34,11 +34,8 @@ my $distros = $cpev->get_blocker('Distros'); my $m_custom = Test::MockFile->file(q[/var/cpanel/caches/Cpanel-OS.custom]); like( - $distros->check(), - { - id => q[Elevate::Blockers::Distros::_blocker_os_is_not_supported], - msg => qr/This script is only designed to upgrade the following OSs/, - }, + dies { $distros->check() }, + qr/This script is only designed to upgrade the following OSs/, 'C6 is not supported.' ); @@ -47,11 +44,8 @@ my $distros = $cpev->get_blocker('Distros'); unmock_os(); $f = Test::MockFile->symlink( 'linux|centos|8|9|2009', '/var/cpanel/caches/Cpanel-OS' ); like( - $distros->check(), - { - id => q[Elevate::Blockers::Distros::_blocker_os_is_not_supported], - msg => qr/This script is only designed to upgrade the following OSs/, - }, + dies { $distros->check() }, + qr/This script is only designed to upgrade the following OSs/, 'C8 is not supported.' ); diff --git a/t/blocker-Repositories.t b/t/blocker-Repositories.t index 85efa99b..2b8515e0 100644 --- a/t/blocker-Repositories.t +++ b/t/blocker-Repositories.t @@ -57,9 +57,13 @@ my $mocked_yum_repos_d = Test::MockFile->dir($path_yum_repos_d); #mkdir $path_yum_repos_d; is $yum->_check_yum_repos(), undef, "no blockers when directory is empty"; -ok scalar Elevate::Blockers::Repositories::VETTED_YUM_REPO(), "VETTED_YUM_REPO populated"; +for my $os ( 'cent', 'cloud' ) { + set_os_to($os); -ok( grep( { 'MariaDB103' } Elevate::Blockers::Repositories::VETTED_YUM_REPO() ), 'MariaDB103 is a valid repo' ); + ok scalar Elevate::OS::vetted_yum_repo(), 'vetted_yum_repo populated'; + + ok( grep( { 'MariaDB103' } Elevate::OS::vetted_yum_repo() ), 'MariaDB103 is a valid repo' ); +} my $mock_vetted_repo = Test::MockFile->file( "$path_yum_repos_d/MariaDB103.repo" => q[MariaDB103] ); diff --git a/t/blocker-ea4.t b/t/blocker-ea4.t index 32e0b989..eae9c733 100644 --- a/t/blocker-ea4.t +++ b/t/blocker-ea4.t @@ -100,7 +100,7 @@ EOS }; $mock_cpev->redefine( - read_stage_file => sub { + _read_stage_file => sub { return { ea4 => $stage_ea4 }; } ); diff --git a/t/lib/Test/Elevate.pm b/t/lib/Test/Elevate.pm index 3a0eddb7..dffd4fd8 100644 --- a/t/lib/Test/Elevate.pm +++ b/t/lib/Test/Elevate.pm @@ -69,7 +69,7 @@ sub init { # Default to CentOS 7 note 'Mock Elevate::OS singleton to think this server is CentOS 7'; - $Elevate::OS::OS = Elevate::OS::CentOS7->new(); + $Elevate::OS::OS = bless {}, 'Elevate::OS::CentOS7'; return; } @@ -131,13 +131,13 @@ sub no_message_seen { goto &no_messages_seen; } sub set_os_to_centos_7 { note 'Mock Elevate::OS singleton to think this server is CentOS 7'; - $Elevate::OS::OS = Elevate::OS::CentOS7->new(); + $Elevate::OS::OS = bless {}, 'Elevate::OS::CentOS7'; return; } sub set_os_to_cloudlinux_7 { note 'Mock Elevate::OS singleton to think this server is CloudLinux 7'; - $Elevate::OS::OS = Elevate::OS::CloudLinux7->new(); + $Elevate::OS::OS = bless {}, 'Elevate::OS::CloudLinux7'; return; } From bc0e616df3de3ea326518ce0a5d900051244178d Mon Sep 17 00:00:00 2001 From: Travis Holloway Date: Mon, 19 Feb 2024 15:21:21 -0600 Subject: [PATCH 12/12] Make CloudLinux 7 an experimental OS Case RE-208: This change makes CloudLinux 7 an experimental OS and will give the user a warning before proceeding with the elevation if the server they are upgrading is considered experimental. Changelog: --- elevate-cpanel | 10 ++++++++++ lib/Elevate/OS.pm | 1 + lib/Elevate/OS/CloudLinux7.pm | 1 + lib/Elevate/OS/RHEL.pm | 1 + script/elevate-cpanel.PL | 7 +++++++ 5 files changed, 20 insertions(+) diff --git a/elevate-cpanel b/elevate-cpanel index 1a8513b2..42d33a6f 100755 --- a/elevate-cpanel +++ b/elevate-cpanel @@ -4201,6 +4201,7 @@ EOS 'disable_mysql_yum_repos', # This is a list of mysql repo files to disable 'ea_alias', # This is the value for the --target-os flag used when backing up an EA4 profile 'elevate_rpm_url', # This is the URL used to install the leapp RPM/repo + 'is_experimental', # This is used to determine if the OS is experimental or not 'is_supported', # This is used to determine if the OS is supported or not 'leapp_can_handle_epel', # This is used to determine if we can skip removing the EPEL repo pre_leapp or not 'leapp_can_handle_imunify', # This is used to determine if we can skip the Imunify component or not @@ -4303,6 +4304,7 @@ EOS use constant default_upgrade_to => 'CloudLinux'; use constant ea_alias => 'CloudLinux_8'; use constant elevate_rpm_url => 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; + use constant is_experimental => 1; use constant leapp_can_handle_epel => 1; use constant leapp_can_handle_imunify => 1; use constant leapp_can_handle_kernelcare => 1; @@ -4393,6 +4395,7 @@ EOS use constant default_upgrade_to => undef; use constant ea_alias => undef; use constant elevate_rpm_url => undef; + use constant is_experimental => 0; use constant is_supported => 1; use constant leapp_can_handle_epel => 0; use constant leapp_can_handle_imunify => 0; @@ -6241,6 +6244,13 @@ It is *highly* recommended that you have a full backup or snapshot of your server before proceeding. EOS + if ( Elevate::OS::is_experimental() ) { + say <getopt('non-interactive') ) { if ( !IO::Prompt::prompt( diff --git a/lib/Elevate/OS.pm b/lib/Elevate/OS.pm index 8353f4e8..96a555ac 100644 --- a/lib/Elevate/OS.pm +++ b/lib/Elevate/OS.pm @@ -74,6 +74,7 @@ BEGIN { 'disable_mysql_yum_repos', # This is a list of mysql repo files to disable 'ea_alias', # This is the value for the --target-os flag used when backing up an EA4 profile 'elevate_rpm_url', # This is the URL used to install the leapp RPM/repo + 'is_experimental', # This is used to determine if the OS is experimental or not 'is_supported', # This is used to determine if the OS is supported or not 'leapp_can_handle_epel', # This is used to determine if we can skip removing the EPEL repo pre_leapp or not 'leapp_can_handle_imunify', # This is used to determine if we can skip the Imunify component or not diff --git a/lib/Elevate/OS/CloudLinux7.pm b/lib/Elevate/OS/CloudLinux7.pm index 428388e6..19e41ad7 100644 --- a/lib/Elevate/OS/CloudLinux7.pm +++ b/lib/Elevate/OS/CloudLinux7.pm @@ -22,6 +22,7 @@ use constant available_upgrade_paths => ( use constant default_upgrade_to => 'CloudLinux'; use constant ea_alias => 'CloudLinux_8'; use constant elevate_rpm_url => 'https://repo.cloudlinux.com/elevate/elevate-release-latest-el7.noarch.rpm'; +use constant is_experimental => 1; use constant leapp_can_handle_epel => 1; use constant leapp_can_handle_imunify => 1; use constant leapp_can_handle_kernelcare => 1; diff --git a/lib/Elevate/OS/RHEL.pm b/lib/Elevate/OS/RHEL.pm index 31fbea12..d0d30b80 100644 --- a/lib/Elevate/OS/RHEL.pm +++ b/lib/Elevate/OS/RHEL.pm @@ -67,6 +67,7 @@ use constant available_upgrade_paths => undef; use constant default_upgrade_to => undef; use constant ea_alias => undef; use constant elevate_rpm_url => undef; +use constant is_experimental => 0; use constant is_supported => 1; use constant leapp_can_handle_epel => 0; use constant leapp_can_handle_imunify => 0; diff --git a/script/elevate-cpanel.PL b/script/elevate-cpanel.PL index c5e75e39..adadb1ad 100755 --- a/script/elevate-cpanel.PL +++ b/script/elevate-cpanel.PL @@ -671,6 +671,13 @@ It is *highly* recommended that you have a full backup or snapshot of your server before proceeding. EOS + if ( Elevate::OS::is_experimental() ) { + say <getopt('non-interactive') ) { if ( !IO::Prompt::prompt(