2021-05-11 22:55:56 +00:00
#!/bin/bash
#
# migrate2rocky - Migrate another EL8 distribution to RockyLinux 8.
# By: Peter Ajamian <peter@pajamian.dhs.org>
# Adapted from centos2rocky.sh by label <label@rockylinux.org>
#
2021-05-31 15:13:33 +00:00
# The latest version of this script can be found at:
# https://github.com/rocky-linux/rocky-tools
#
2021-06-01 05:11:37 +00:00
# Copyright (c) 2021 Rocky Enterprise Software Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
2021-05-11 22:55:56 +00:00
## Rocky is RC status. Using this script means you accept all risks of system
## instability.
# Path to logfile
2021-05-29 09:22:01 +00:00
logfile = /var/log/migrate2rocky.log
2021-05-11 22:55:56 +00:00
# Send all output to the logfile as well as stdout.
truncate -s0 " $logfile "
exec > >( tee -a " $logfile " ) 2> >( tee -a " $logfile " >& 2)
2021-05-18 12:05:01 +00:00
# List nocolor last here so that -x doesn't bork the display.
2021-05-29 09:17:10 +00:00
#errcolor=$(tput setaf 1)
#blue=$(tput setaf 4)
#nocolor=$(tput op)
2021-06-03 14:16:43 +00:00
errcolor =
blue =
nocolor =
2021-05-11 22:55:56 +00:00
export LANG = en_US.UTF-8
2021-05-13 14:26:20 +00:00
shopt -s nullglob
2021-05-11 22:55:56 +00:00
SUPPORTED_MAJOR = "8"
SUPPORTED_PLATFORM = " platform:el $SUPPORTED_MAJOR "
ARCH = $( arch)
2021-05-31 16:41:27 +00:00
gpg_key_url = "https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-rockyofficial"
gpg_key_sha512 = "88fe66cf0a68648c2371120d56eb509835266d9efdf7c8b9ac8fc101bdf1f0e0197030d3ea65f4b5be89dc9d1ef08581adb068815c88d7b1dc40aa1c32990f6a"
# all repos must be signed with the same key given in $gpg_key_url
declare -A repo_urls
2021-05-11 22:55:56 +00:00
repo_urls = (
2021-05-31 16:41:27 +00:00
[ rockybaseos] = " https://dl.rockylinux.org/pub/rocky/ ${ SUPPORTED_MAJOR } /BaseOS/ $ARCH /os/ "
[ rockyappstream] = " https://dl.rockylinux.org/pub/rocky/ ${ SUPPORTED_MAJOR } /AppStream/ $ARCH /os/ "
2021-05-11 22:55:56 +00:00
)
unset CDPATH
exit_message( ) {
printf '%s\n' " $1 "
final_message
exit 1
} >& 2
final_message( ) {
printf '%s\n' " ${ errcolor } An error occurred while we were attempting to convert your system to Rocky Linux. Your system may be unstable. Script will now exit to prevent possible damage. $nocolor "
logmessage
}
logmessage( ) {
printf '%s\n' " ${ blue } A log of this installation can be found at $logfile $nocolor "
}
# This just grabs a field from os-release and returns it.
2021-05-11 23:11:36 +00:00
os-release ( ) (
2021-05-11 22:55:56 +00:00
. /etc/os-release
if ! [ [ ${ !1 } ] ] ; then
return 1
fi
printf '%s\n' " ${ !1 } "
2021-05-11 23:11:36 +00:00
)
2021-05-11 22:55:56 +00:00
2021-05-29 02:17:06 +00:00
# Check the version of a package against a supplied version number. Note that
# this uses sort -V to compare the versions which isn't perfect for rpm package
# versions, but to do a proper comparison we would need to use rpmdev-vercmp in
# the rpmdevtools package which we don't want to force-install. sort -V should
# be adequate for our needs here.
pkg_ver( ) (
ver = $( rpm -q --qf '%{VERSION}\n' " $1 " ) || return 2
2021-06-03 14:16:43 +00:00
if [ [ $( sort -V <<< " $ver " $'\n' " $2 " | head -1) != " $2 " ] ] ; then
2021-05-29 02:17:06 +00:00
return 1
fi
return 0
)
2021-06-04 23:51:02 +00:00
pre_check ( ) {
if [ [ -e /etc/rhsm/ca/katello-server-ca.pem ] ] ; then
exit_message "Migration from Katello-modified systems is not supported by migrate2rocky."
fi
}
2021-05-11 22:55:56 +00:00
# All of the binaries used by this script are available in a EL8 minimal install
# and are in /bin, so we should not encounter a system where the script doesn't
# work unless it's severly broken. This is just a simple check that will cause
# the script to bail if any expected system utilities are missing.
bin_check( ) {
# Make sure we're root.
if ( ( EUID != 0 ) ) ; then
exit_message " You must run this script as root. Either use sudo or 'su -c ${ 0 } ' "
fi
# Check the platform.
2021-06-03 14:16:43 +00:00
if [ [ $( os-release PLATFORM_ID) != " $SUPPORTED_PLATFORM " ] ] ; then
2021-05-11 22:55:56 +00:00
exit_message "This script must be run on an EL8 distribution. Migration from other distributions is not supported."
fi
# We need bash version >= 4 for associative arrays. This will also verify
# that we're actually running bash.
if ( ( BASH_VERSINFO < 4 ) ) ; then
exit_message "bash >= 4.0 is required for this script."
fi
2021-05-29 06:33:57 +00:00
local -a missing bins
bins = (
rpm dnf awk column tee tput mkdir
cat arch sort uniq rmdir rm head
2021-05-31 16:41:27 +00:00
curl sha512sum mktemp
2021-05-29 06:33:57 +00:00
)
if [ [ $update_efi ] ] ; then
2021-05-31 15:06:31 +00:00
bins += ( findmnt grub2-mkconfig efibootmgr grep mokutil)
2021-05-29 06:33:57 +00:00
fi
for bin in " ${ bins [@] } " ; do
2021-05-11 22:55:56 +00:00
if ! type " $bin " >/dev/null 2>& 1; then
missing += ( " $bin " )
fi
done
2021-05-29 02:17:06 +00:00
if ! pkg_ver dnf 4.2; then
exit_message 'dnf >= 4.2 is required for this script. Please run "dnf update" first.'
fi
2021-05-11 22:55:56 +00:00
if ( ( ${# missing [@] } ) ) ; then
2021-06-03 14:16:43 +00:00
exit_message " Commands not found: ${ missing [*] } . Possible bad PATH setting or corrupt installation. "
2021-05-11 22:55:56 +00:00
fi
}
# This function will overwrite the repoquery_results associative array with the
# info for the resulting package. Note that we explicitly disable the epel repo
# as a special-case below to avoid having the extras repository map to epel.
repoquery ( ) {
2021-06-03 14:16:43 +00:00
local name val prev result
result = $(
2021-05-11 22:55:56 +00:00
dnf -q --setopt= epel.excludepkgs= epel-release repoquery -i " $1 " ||
exit_message " Failed to fetch info for package $1 . "
)
if ! [ [ $result ] ] ; then
# We didn't match this package, the repo could be disabled.
return 1
fi
declare -gA repoquery_results = ( )
while IFS = " :" read -r name val; do
if [ [ -z $name ] ] ; then
repoquery_results[ $prev ] += " $val "
else
prev = $name
repoquery_results[ $name ] = $val
fi
done <<< " $result "
}
# This function will overwrite the repoinfo_results associative array with the
# info for the resulting repository.
repoinfo ( ) {
local name val result
result = $( dnf -q repoinfo " $1 " ) ||
exit_message " Failed to fetch info for repository $1 . "
if [ [ $result = = 'Total packages: 0' ] ] ; then
# We didn't match this repo.
return 1
fi
declare -gA repoinfo_results = ( )
while IFS = " :" read -r name val; do
if [ [ -z $name ] ] ; then
repoinfo_results[ $prev ] += " $val "
else
prev = $name
repoinfo_results[ $name ] = $val
fi
done <<< " $result "
# dnf repoinfo doesn't return the gpgkey, but we need that so we have to get
# it from the repo file itself.
2021-05-13 14:26:20 +00:00
# "end_of_file" is a hack here. Since it is not a valid dnf setting we know
# it won't appear in a .repo file on a line by itself, so it's safe to
# search for the string to make the awk parser look all the way to the end
# of the file.
2021-05-11 22:55:56 +00:00
repoinfo_results[ Repo-gpgkey] = $(
awk '
2021-05-13 14:26:20 +00:00
$0 = = "['" ${ repoinfo_results [Repo-id] } "']" ,$0 = = "end_of_file" {
if ( l++ < 1) { next}
else if ( /^\[ .*\] $/) { nextfile}
else if ( sub( /^gpgkey\s *= \s *file:\/ \/ /,"" ) ) { print; nextfile}
else { next}
}
' < " ${ repoinfo_results [Repo-filename] } "
2021-05-11 22:55:56 +00:00
)
2021-05-14 03:18:43 +00:00
# Add an indicator of whether this is a subscription-manager managed
# repository.
repoinfo_results[ Repo-managed] = $(
awk '
BEGIN { FS = "[)(]" }
/^# Managed by \( .*\) subscription-manager$/ { print $2 }
' < " ${ repoinfo_results [Repo-filename] } "
)
2021-05-11 22:55:56 +00:00
}
2021-05-13 14:26:20 +00:00
provides_pkg ( ) (
2021-05-14 03:18:43 +00:00
if [ [ ! $1 ] ] ; then
return 0
fi
2021-05-13 14:26:20 +00:00
set -o pipefail
provides = $( dnf -q provides " $1 " | awk '{print $1; nextfile}' ) ||
return 1
set +o pipefail
2021-06-04 10:11:15 +00:00
pkg = $( rpm -q --queryformat '%{NAME}\n' " $provides " ) ||
pkg = $( dnf -q repoquery --queryformat '%{NAME}\n' " $provides " ) ||
2021-05-13 14:26:20 +00:00
exit_message " Can't get package name for $provides . "
printf '%s\n' " $pkg "
)
2021-06-04 10:11:15 +00:00
# If you pass an empty arg as one of the package specs to rpm it will match
# every package on the system. This funtion simply strips out any empty args
# and passes the rest to rpm to avoid this side-effect.
saferpm ( ) (
args = ( )
for a in " $@ " ; do
if [ [ $a ] ] ; then
args += ( " $a " )
fi
done
rpm " ${ args [@] } "
)
# And a similar function for dnf
safednf ( ) (
args = ( )
for a in " $@ " ; do
if [ [ $a ] ] ; then
args += ( " $a " )
fi
done
dnf " ${ args [@] } "
)
2021-05-11 22:55:56 +00:00
collect_system_info ( ) {
2021-05-29 06:33:57 +00:00
# Check the efi mount first, so we can bail before wasting time on all these
# other checks if it's not there.
if [ [ $update_efi ] ] ; then
declare -g efi_mount
efi_mount = $( findmnt --mountpoint /boot/efi --output SOURCE \
--noheadings) ||
exit_message "Can't find EFI mount. No EFI boot detected."
fi
2021-05-31 15:06:31 +00:00
# check if EFI secure boot is enabled
if [ [ $update_efi ] ] ; then
if mokutil --sb-state 2>& 1 | grep -q "SecureBoot enabled" ; then
exit_message "EFI Secure Boot is enabled but Rocky Linux doesn't provide a signed shim yet. Disable EFI Secure Boot and reboot."
fi
fi
2021-05-18 11:43:58 +00:00
# Don't enable these module streams, even if they are enabled in the source
# distro.
declare -g -a module_excludes
module_excludes = (
libselinux-python:2.8
)
2021-05-11 22:55:56 +00:00
# We need to map rockylinux repository names to the equivalent repositories
# in the source distro. To do that we look for known packages in each
# repository and see what repo they came from. We need to use repoquery for
# this which requires downloading the package, so we pick relatively small
# packages for this.
declare -g -A repo_map pkg_repo_map
2021-05-14 03:18:43 +00:00
declare -g -a managed_repos
2021-05-11 22:55:56 +00:00
pkg_repo_map = (
[ baseos] = rootfiles.noarch
[ appstream] = apr-util-ldap.$ARCH
[ ha] = pacemaker-doc.noarch
[ powertools] = libaec-devel.$ARCH
[ extras] = epel-release.noarch
)
2021-05-16 02:05:42 +00:00
# [devel]=quota-devel.$ARCH
2021-05-11 22:55:56 +00:00
PRETTY_NAME = $( os-release PRETTY_NAME)
printf '%s\n' " ${ blue } Preparing to migrate $PRETTY_NAME to Rocky Linux 8. $nocolor "
printf '\n%s' " ${ blue } Determining repository names for $PRETTY_NAME $nocolor "
for r in " ${ !pkg_repo_map[@] } " ; do
printf '.'
p = ${ pkg_repo_map [ $r ] }
repoquery " $p " || continue
repo_map[ $r ] = ${ repoquery_results [Repository] }
done
printf '%s\n' '' '' " Found the following repositories which map from $PRETTY_NAME to Rocky Linux 8: "
2021-06-04 10:11:15 +00:00
column -t -s $'\t' -N " $PRETTY_NAME ,Rocky Linux 8 " < <( for r in " ${ !repo_map[@] } " ; do
printf '%s\t%s\n' " ${ repo_map [ $r ] } " " $r "
2021-05-11 22:55:56 +00:00
done )
printf '\n%s' " ${ blue } Getting system package names for $PRETTY_NAME $nocolor . "
# We don't know what the names of these packages are, we have to discover
# them via various means. The most common means is to look for either a
# distro-agnostic provides or a filename. In a couple of cases we need to
# jump through hoops to get a filename that is provided specifically by the
# source distro.
2021-05-14 03:18:43 +00:00
# Get info for each repository to determine which ones are subscription
# managed.
# system-release here is a bit of a hack, but it ensures that the
# rocky-repos package will get installed.
for r in " ${ !repo_map[@] } " ; do
repoinfo " ${ repo_map [ $r ] } "
if [ [ $r = = "baseos" ] ] ; then
local baseos_filename = system-release
if [ [ ! ${ repoinfo_results [Repo-managed] } ] ] ; then
baseos_filename = " ${ repoinfo_results [Repo-filename] } "
fi
local baseos_gpgkey = " ${ repoinfo_results [Repo-gpgkey] } "
fi
if [ [ ${ repoinfo_results [Repo-managed] } ] ] ; then
managed_repos += ( " ${ repo_map [ $r ] } " )
fi
done
2021-05-11 22:55:56 +00:00
# First get info for the baseos repo
repoinfo " ${ repo_map [baseos] } "
declare -g -A pkg_map provides_pkg_map
2021-05-13 14:26:20 +00:00
declare -g -a addl_provide_removes addl_pkg_removes
2021-05-11 22:55:56 +00:00
provides_pkg_map = (
[ rocky-backgrounds] = system-backgrounds
[ rocky-indexhtml] = redhat-indexhtml
2021-05-14 03:18:43 +00:00
[ rocky-repos] = " $baseos_filename "
2021-05-11 22:55:56 +00:00
[ rocky-logos] = system-logos
2021-05-14 03:18:43 +00:00
[ rocky-gpg-keys] = " $baseos_gpgkey "
2021-05-11 22:55:56 +00:00
[ rocky-release] = system-release
)
2021-05-13 14:26:20 +00:00
addl_provide_removes = (
redhat-release-eula
)
2021-05-11 22:55:56 +00:00
for pkg in " ${ !provides_pkg_map[@] } " ; do
printf '.'
prov = ${ provides_pkg_map [ $pkg ] }
2021-06-03 14:16:43 +00:00
pkg_map[ $pkg ] = $( provides_pkg " $prov " ) ||
2021-05-11 22:55:56 +00:00
exit_message " Can't get package that provides $prov . "
2021-05-13 14:26:20 +00:00
done
for prov in " ${ addl_provide_removes [@] } " ; do
printf '.'
local pkg;
2021-06-03 14:16:43 +00:00
pkg = $( provides_pkg " $prov " ) || continue
2021-05-13 14:26:20 +00:00
addl_pkg_removes += ( " $pkg " )
2021-05-11 22:55:56 +00:00
done
printf '%s\n' '' '' " Found the following system packages which map from $PRETTY_NAME to Rocky Linux 8: "
2021-06-04 10:11:15 +00:00
column -t -s $'\t' -N " $PRETTY_NAME ,Rocky Linux 8 " < <( for p in " ${ !pkg_map[@] } " ; do
printf '%s\t%s\n' " ${ pkg_map [ $p ] } " " $p "
2021-05-11 22:55:56 +00:00
done )
printf '%s\n' '' " ${ blue } Getting list of installed system packages $nocolor . "
2021-06-04 10:11:15 +00:00
readarray -t installed_packages < <( saferpm -qa --queryformat= "%{NAME}\n" " ${ pkg_map [@] } " )
2021-05-11 22:55:56 +00:00
declare -g -A installed_pkg_check installed_pkg_map
for p in " ${ installed_packages [@] } " ; do
installed_pkg_check[ $p ] = 1
done
for p in " ${ !pkg_map[@] } " ; do
2021-06-04 10:11:15 +00:00
if [ [ ${ pkg_map [ $p ] } && ${ installed_pkg_check [ ${ pkg_map [ $p ] } ] } ] ] ; then
2021-05-11 22:55:56 +00:00
installed_pkg_map[ $p ] = ${ pkg_map [ $p ] }
fi
done ;
printf '%s\n' '' " We will replace the following $PRETTY_NAME packages with their Rocky Linux 8 equivalents "
2021-06-04 10:11:15 +00:00
column -t -s $'\t' -N "Packages to be Removed,Packages to be Installed" < <(
2021-05-11 22:55:56 +00:00
for p in " ${ !installed_pkg_map[@] } " ; do
2021-06-04 10:11:15 +00:00
printf '%s\t%s\n' " ${ installed_pkg_map [ $p ] } " " $p "
2021-05-11 22:55:56 +00:00
done
)
2021-05-13 14:26:20 +00:00
if ( ( ${# addl_pkg_removes [@] } ) ) ; then
printf '%s\n' '' "In addition to the above the following system packages will be removed:" \
" ${ addl_pkg_removes [@] } "
fi
2021-05-11 22:55:56 +00:00
# Release packages that are part of SIG's should be listed below when they
# are available.
# UPDATE: We may or may not do something with SIG's here, it could just be
# left as a separate excersize to swap out the sig repos.
#sigs_to_swap=()
printf '%s\n' '' " ${ blue } Getting a list of enabled modules for the system repositories $nocolor . "
# Get a list of system enabled modules.
readarray -t enabled_modules < <(
set -e -o pipefail
2021-06-04 10:11:15 +00:00
safednf -q " ${ repo_map [@]/#/--repo= } " module list --enabled |
2021-05-11 22:55:56 +00:00
awk '
$1 = = "@modulefailsafe" , /^$/ { next}
2021-05-16 02:05:42 +00:00
$1 = = "Name" , /^$/ { if ( $1 != "Name" && !/^$/) print $1 ":" $2 }
' | sort -u
2021-05-11 22:55:56 +00:00
set +e +o pipefail
)
2021-05-18 11:43:58 +00:00
# Remove entries matching any excluded modules.
if ( ( ${# module_excludes [@] } ) ) ; then
printf '%s\n' '' "Excluding modules:" " ${ module_excludes [@] } "
local -A module_check = '()'
local -a tmparr = '()'
for m in " ${ module_excludes [@] } " ; do
module_check[ $m ] = 1
done
for m in " ${ enabled_modules [@] } " ; do
if [ [ ! ${ module_check [ $m ] } ] ] ; then
tmparr += ( " $m " )
fi
done
enabled_modules = ( " ${ tmparr [@] } " )
fi
2021-05-11 22:55:56 +00:00
2021-05-14 03:18:43 +00:00
printf '%s\n' '' "Found the following modules to re-enable at completion:" \
" ${ enabled_modules [@] } " ''
if ( ( ${# managed_repos [@] } ) ) ; then
printf '%s\n' '' "In addition, since this system uses subscription-manger the following managed repos will be disabled:" \
" ${ managed_repos [@] } "
fi
2021-05-11 22:55:56 +00:00
}
convert_info_dir = /root/convert
2021-05-29 06:33:57 +00:00
unset convert_to_rocky reinstall_all_rpms verify_all_rpms update_efi
2021-05-11 22:55:56 +00:00
usage( ) {
printf '%s\n' \
" Usage: ${ 0 ##*/ } [OPTIONS] " \
'' \
'Options:' \
2021-05-29 06:33:57 +00:00
'-h Display this help' \
'-r Convert to rocky' \
'-V Verify switch' \
2021-05-11 22:55:56 +00:00
' !! USE WITH CAUTION !!'
exit 1
} >& 2
generate_rpm_info( ) {
mkdir /root/convert
printf '%s\n' " ${ blue } Creating a list of RPMs installed: $1 $nocolor "
rpm -qa --qf "%{NAME}|%{VERSION}|%{RELEASE}|%{INSTALLTIME}|%{VENDOR}|%{BUILDTIME}|%{BUILDHOST}|%{SOURCERPM}|%{LICENSE}|%{PACKAGER}\n" | sort > " ${ convert_info_dir } / $HOSTNAME -rpm-list- $1 .log "
printf '%s\n' " ${ blue } Verifying RPMs installed against RPM database: $1 $nocolor " ''
rpm -Va | sort -k3 > " ${ convert_info_dir } / $HOSTNAME -rpm-list-verified- $1 .log "
}
package_swaps( ) {
2021-05-31 16:41:27 +00:00
# prepare repo parameters
local -a dnfparameters
for repo in " ${ !repo_urls[@] } " ; do
dnfparameters += ( " --repofrompath= ${ repo } , ${ repo_urls [ ${ repo } ] } " )
dnfparameters += ( " --setopt= ${ repo } .gpgcheck=1 " )
dnfparameters += ( " --setopt= ${ repo } .gpgkey=file:// ${ gpg_key_file } " )
done
2021-05-11 22:55:56 +00:00
# Use dnf shell to swap the system packages out.
2021-06-04 10:11:15 +00:00
safednf -y shell --disablerepo= \* --noautoremove \
2021-05-13 14:26:20 +00:00
--setopt= protected_packages = --setopt= keepcache = True \
2021-05-31 16:41:27 +00:00
" ${ dnfparameters [@] } " \
<<EOF
2021-05-13 14:26:20 +00:00
remove ${ installed_pkg_map [@] } ${ addl_pkg_removes [@] }
2021-05-11 22:55:56 +00:00
install ${ !installed_pkg_map[@] }
run
exit
EOF
2021-05-13 14:26:20 +00:00
2021-05-31 16:41:27 +00:00
# rocky-repos and rocky-gpg-keys are now installed, so we don't need the key file anymore
rm -rf " $gpg_tmp_dir "
2021-05-13 14:26:20 +00:00
# We need to check to make sure that all of the original system packages
# have been removed and all of the new ones have been added. If a package
# was supposed to be removed and one with the same name added back then
# we're kind of screwed for this check, as we can't be certain, but all the
# packages we're adding start with "rocky-*" so this really shouldn't happen
# and we can safely not check for it. The worst that will happen is a rocky
# linux package will be removed and then installed again.
local -a check_removed check_installed
readarray -t check_removed < <(
2021-06-04 10:11:15 +00:00
saferpm -qa --qf '%{NAME}\n' " ${ installed_pkg_map [@] } " \
2021-05-13 14:26:20 +00:00
" ${ addl_pkg_removes [@] } " | sort -u
)
if ( ( ${# check_removed [@] } ) ) ; then
printf '%s\n' '' " ${ blue } Packages found on system that should still be removed. Forcibly removing them with rpm: $nocolor "
# Removed packages still found on the system. Forcibly remove them.
for pkg in " ${ check_removed [@] } " ; do
2021-06-04 10:11:15 +00:00
# Extra safety measure, skip if empty string
if [ [ -z $pkg ] ] ; then
continue
fi
2021-05-13 14:26:20 +00:00
printf '%s\n' " $pkg "
2021-06-04 10:11:15 +00:00
saferpm -e --allmatches --nodeps " $pkg " ||
saferpm -e --allmatches --nodeps --noscripts --notriggers " $pkg "
2021-05-13 14:26:20 +00:00
done
fi
# Check to make sure we installed everything we were supposed to.
readarray -t check_installed < <(
{
printf '%s\n' " ${ !installed_pkg_map[@] } " | sort -u
2021-06-04 10:11:15 +00:00
saferpm -qa --qf '%{NAME}\n' " ${ !installed_pkg_map[@] } " | sort -u
2021-05-13 14:26:20 +00:00
} | sort | uniq -u
)
if ( ( ${# check_installed [@] } ) ) ; then
printf '%s\n' '' " ${ blue } Some required packages were not installed by dnf. Attempting to force with rpm: $nocolor "
# Get a list of rpm packages to package names
local -A rpm_map
local -a file_list
for rpm in /var/cache/dnf/{ rockybaseos,rockyappstream} -*/packages/*.rpm
do
2021-05-14 03:18:43 +00:00
rpm_map[ $(
rpm -q --qf '%{NAME}\n' --nodigest " $rpm " 2>/dev/null
) ] = $rpm
2021-05-13 14:26:20 +00:00
done
# Attempt to install.
for pkg in " ${ check_installed [@] } " ; do
printf '%s\n' " $pkg "
2021-05-14 03:18:43 +00:00
if ! rpm -i --force --nodeps --nodigest " ${ rpm_map [ $pkg ] } " \
2>/dev/null; then
2021-05-13 14:26:20 +00:00
# Try to install the package in just the db, then clean it up.
2021-05-14 03:18:43 +00:00
rpm -i --force --justdb --nodeps --nodigest " ${ rpm_map [ $pkg ] } " \
2>/dev/null
2021-05-13 14:26:20 +00:00
# Get list of files that are still causing problems and donk
# them.
readarray -t file_list < <(
2021-05-14 03:18:43 +00:00
rpm -V " $pkg " 2>/dev/null | awk '$1!="missing" {print $2}'
2021-05-13 14:26:20 +00:00
)
for file in " ${ file_list [@] } " ; do
rmdir " $file " ||
rm -f " $file " ||
rm -rf " $file "
done
# Now try re-installing the package to replace the missing
# files. Regardless of the outcome here we just accept it and
# move on and hope for the best.
rpm -i --reinstall --force --nodeps --nodigest \
2021-05-14 03:18:43 +00:00
" ${ rpm_map [ $pkg ] } " 2>/dev/null
2021-05-13 14:26:20 +00:00
fi
done
2021-05-11 22:55:56 +00:00
fi
# Distrosync
printf '%s\n' '' " ${ blue } Removing dnf cache $nocolor "
rm -rf /var/cache/{ yum,dnf}
printf '%s\n' " ${ blue } Ensuring repos are enabled before the package swap $nocolor "
2021-06-04 10:11:15 +00:00
safednf -y config-manager --set-enabled " ${ !repo_map[@] } " || {
2021-05-11 22:55:56 +00:00
printf '%s\n' 'Repo name missing?'
exit 25
}
2021-05-14 03:18:43 +00:00
if ( ( ${# managed_repos [@] } ) ) ; then
# Filter the managed repos for ones still in the system.
readarray -t managed_repos < <(
2021-06-04 10:11:15 +00:00
safednf -q repolist " ${ managed_repos [@] } " | awk '$1!="repo" {print $1}'
2021-05-14 03:18:43 +00:00
)
if ( ( ${# managed_repos [@] } ) ) ; then
printf '%s\n' '' " ${ blue } Disabling subscription managed repos $nocolor . "
2021-06-04 10:11:15 +00:00
safednf -y config-manager --disable " ${ managed_repos [@] } "
2021-05-14 03:18:43 +00:00
fi
fi
2021-05-12 01:44:41 +00:00
if ( ( ${# enabled_modules [@] } ) ) ; then
printf '%s\n' " ${ blue } Enabling modules $nocolor " ''
2021-06-04 10:11:15 +00:00
safednf -y module enable " ${ enabled_modules [@] } " ||
2021-06-03 14:16:43 +00:00
exit_message " Can't enable modules ${ enabled_modules [*] } "
2021-05-12 01:44:41 +00:00
fi
2021-05-18 11:43:58 +00:00
# Make sure that excluded repos are disabled.
printf '%s\n' " ${ blue } Disabling excluded modules $nocolor " ''
2021-06-04 10:11:15 +00:00
safednf -y module disable " ${ module_excludes [@] } " ||
2021-06-03 14:16:43 +00:00
exit_message " Can't disable modules ${ module_excludes [*] } "
2021-05-18 11:43:58 +00:00
2021-05-11 22:55:56 +00:00
printf '%s\n' '' " ${ blue } Syncing packages $nocolor " ''
dnf -y distro-sync || exit_message "Error during distro-sync."
}
2021-05-30 12:15:59 +00:00
# Check if this system is running on EFI
# If yes, we'll need to run fix_efi() at the end of the conversion
efi_check ( ) {
# Check if we have /sys mounted and it is looking sane
if ! [ [ -d /sys/class/block ] ] ; then
exit_message "/sys is not accessible."
fi
# Now that we know /sys is reliable, use it to check if we are running on EFI or not
if [ [ -d /sys/firmware/efi/ ] ] ; then
declare -g update_efi
update_efi = true
fi
}
2021-05-29 06:33:57 +00:00
# Called to update the EFI boot.
fix_efi ( ) (
grub2-mkconfig -o /boot/efi/EFI/rocky/grub.cfg ||
exit_message "Error updating the grub config."
2021-05-30 11:47:25 +00:00
efibootmgr -c -d " $efi_mount " -L "Rocky Linux" -l /EFI/rocky/grubx64.efi ||
2021-05-29 06:33:57 +00:00
exit_message "Error updating uEFI firmware."
)
2021-05-31 16:41:27 +00:00
# Download and verify the Rocky Linux package signing key
establish_gpg_trust ( ) {
# create temp dir and verify it is really created and empty, so we are sure deleting it afterwards won't cause any harm
declare -g gpg_tmp_dir
if ! gpg_tmp_dir = $( mktemp -d) || [ [ ! -d " $gpg_tmp_dir " ] ] ; then
exit_message "Error creating temp dir"
fi
# failglob makes pathname expansion fail if empty, dotglob adds files starting with . to pathname expansion
if ( shopt -s failglob dotglob; : " $gpg_tmp_dir " /* ) 2>/dev/null ; then
exit_message "Temp dir not empty"
fi
# extract the filename from the url, use the temp dir just created
declare -g gpg_key_file = " $gpg_tmp_dir / ${ gpg_key_url ##*/ } "
if ! curl -o " $gpg_key_file " --silent --show-error " $gpg_key_url " ; then
rm -rf " $gpg_tmp_dir "
exit_message "Error downloading the Rocky Linux signing key."
fi
if ! sha512sum --quiet -c <<< " $gpg_key_sha512 $gpg_key_file " ; then
rm -rf " $gpg_tmp_dir "
exit_message "Error validating the signing key."
fi
}
2021-05-11 22:55:56 +00:00
## End actual work
noopts = 0
while getopts "hrVR" option; do
( ( noopts++ ) )
case " $option " in
h)
usage
; ;
r)
convert_to_rocky = true
; ;
V)
verify_all_rpms = true
; ;
*)
printf '%s\n' " ${ errcolor } Invalid switch. $nocolor "
usage
; ;
esac
done
if ( ( ! noopts ) ) ; then
usage
fi
2021-06-04 23:55:09 +00:00
pre_check
2021-05-30 12:15:59 +00:00
efi_check
2021-05-11 22:55:56 +00:00
bin_check
if [ [ $verify_all_rpms ] ] ; then
generate_rpm_info begin
fi
if [ [ $convert_to_rocky ] ] ; then
collect_system_info
2021-05-31 16:41:27 +00:00
establish_gpg_trust
2021-05-11 22:55:56 +00:00
package_swaps
fi
if [ [ $verify_all_rpms && $convert_to_rocky ] ] ; then
generate_rpm_info finish
printf '%s\n' " ${ blue } You may review the following files: $nocolor "
find /root/convert -type f -name " $HOSTNAME -rpms-*.log "
fi
2021-05-29 06:33:57 +00:00
if [ [ $update_efi && $convert_to_rocky ] ] ; then
fix_efi
fi
2021-05-11 22:55:56 +00:00
printf '\n\n\n'
if [ [ $convert_to_rocky ] ] ; then
2021-06-03 14:16:43 +00:00
awk 'NR<=15' < /etc/issue
2021-05-11 22:55:56 +00:00
printf '%s\n' " $blue " " Done, please reboot your system. $nocolor "
fi
logmessage