diff --git a/README.md b/README.md index 291f0d8..d628e6d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,9 @@ The script supports the following options: - `-d, --downgrade` - Allow downgrade from CentOS Stream to AlmaLinux stable - `-v, --version` - Print script version and exit - `-l=URL, --local-repo=URL` - Use AlmaLinux local repositories at specified URL/path (for systems without internet access) +- `--preserve-rhsm` - Preserve Red Hat Subscription Manager configuration. + Administrators need to ensure the correct repositories are set. + Only compatible with the -e option below, all other options will be ignored - `-e=pkg1*,pkg2*, --exclude=pkg1*,pkg2*` - Comma-separated list of packages to exclude during dnf distro-sync ### Environment Variables @@ -183,6 +186,7 @@ When migrating from RHEL, the script automatically: - Removes subscription-manager related packages - Disables RHEL-specific DNF plugins - Backs up and removes RHEL repository files +Using the '--preserve-rhsm' stops this behavior and preserves the subscription-manager configuration. Administrators must ensure the correct repositories are set for AlmaLinux. ### Container Environments The script detects OCI-compliant container environments and automatically: @@ -199,7 +203,7 @@ The script backs up and restores system alternatives (e.g., Python, Java version ### UEFI Secure Boot Support The script fully supports UEFI Secure Boot environments. During migration, it: - Reinstalls all Secure Boot related packages (shim, grub2, fwupd) with AlmaLinux signed versions -- Reinstalls the kernel package with AlmaLinux signed version +- Reinstalls the kernel package with AlmaLinux signed version. - Creates appropriate EFI boot entries using shim bootloaders (shimx64.efi for x86_64, shimaa64.efi for aarch64) - Handles BTRFS subvolume paths correctly for EL10+ systems @@ -210,6 +214,7 @@ For Oracle Linux migrations, the script automatically resets and restores module ### Repository Mapping The script intelligently maps enabled repositories from your source distribution to equivalent AlmaLinux repositories: +Using the '--preserve-rhsm' option does not do these mappings. It is up to the Administrator to ensure the correct repositories are set for AlmaLinux. - **extras** - Extra packages for Enterprise Linux - Maps: CentOS/Rocky `extras`, `extras-common`, MiracleLinux `9/10-latest-extras`, Oracle Linux `ol8/9/10_addons` diff --git a/README_PRESERVE_RHSM.md b/README_PRESERVE_RHSM.md new file mode 100644 index 0000000..2cee721 --- /dev/null +++ b/README_PRESERVE_RHSM.md @@ -0,0 +1,48 @@ +The '--preserve-rhsm' option is used to preserve the Red Hat Subscription Manager (RHSM) configuration. +This option totally removes all the intelligence the authors have put into the script to manage repositories. + +In addition the script will install `python3-dnf-plugin-post-transaction-actions `and create `/etc/dnf/plugins/post-transaction-actions.d/almalinux-repos.conf`. +`/etc/dnf/plugins/post-transaction-actions.d/almalinux-repos.conf` will remove `/etc/yum.repos.d/almalinux*.repo` files as soon as an AlmaLinux release or repos RPM creates them. +This enables your servers to not have a proxy setup in `dnf.conf` or other access to the internet. + +You, the Administrator, must make sure your systems are ready for migration and that the repositories are configured correctly. +You will probably do this by running a preparation script on the target server. + +An simple example will be: +``` +#!/usr/bin/bash + +. /etc/os-release +OS_VER=${VERSION_ID%.*} + +CodeReadyRepoInstalled=$(/usr/bin/dnf repolist | /usr/bin/awk '/codeready-builder/{print $1}') +if [ "${CodeReadyRepoInstalled}" ]; then + case ${OS_VER} in + 8) + CRB_REPO="--enable=ORG_AlmaLinux_${OS_VER}_PowerTools --disable ${CodeReadyRepoInstalled}" + ;; + 9|10) + CRB_REPO="--enable=ORG_AlmaLinux_${OS_VER}_CRB --disable ${CodeReadyRepoInstalled}" + ;; + esac +fi + +# We have no satellite-client repository in AlmaLinux +/usr/bin/dnf remove $(/usr/bin/dnf list installed | /usr/bin/awk '/satellite-client/{print $1}') +/usr/bin/dnf upgrade -y >/dev/null || exit 1 + +# Your Repo naming is different. This is an example only. +/usr/bin/subscription-manager repos --enable ORG_AlmaLinux_${OS_VER}_BaseOS_RPMs \ + --enable ORG_AlmaLinux_${OS_VER}_AppStream_RPMs \ + --enable ORG_EPEL_EPEL${OS_VER} \ + --enable ORG_Zabbix_7_4-AL${OS_VER} \ + --disable rhel-${OS_VER}-for-x86_64-appstream-rpms \ + --disable rhel-${OS_VER}-for-x86_64-baseos-rpms \ + --disable satellite-client-6-for-rhel-${OS_VER}-x86_64-rpms \ + --disable ORG_Zabbix_7_4-RHEL${OS_VER} ${CRB_REPO} +``` + +The Zabbix repository is shown here as an example of a non RedHat repository that has a RedHat and AlmaLinux version. + +Download the almalinux-deploy.sh script from your internal systems (pub directory of the foreman server is a suggestion); + and run it with the '--preserve-rhsm' option. diff --git a/almalinux-deploy.sh b/almalinux-deploy.sh index 93d4cf2..0fd482c 100755 --- a/almalinux-deploy.sh +++ b/almalinux-deploy.sh @@ -22,6 +22,8 @@ VERSION='0.1.13' DOWNGRADE='NO' REPO_URL=https://repo.almalinux.org/almalinux LOCAL_REPO='NO' +PRESERVE_RHSM='NO' +DNF_UPGRADE='NO' BRANDING_PKGS=("centos-backgrounds" "centos-logos" "centos-indexhtml" \ "centos-logos-ipa" "centos-logos-httpd" \ @@ -179,6 +181,8 @@ show_usage() { echo ' -v , --version print version information and exit' echo ' -l=URL/path , --local-repo=URL/path use AlmaLinux local repositories at URL/path, like http://mirror.example.com/almalinux' echo ' in case if migrated system does not have internet access' + echo ' --preserve-rhsm Preserve Red Hat Subscription Manager configuration' + echo ' Only compatible with the -e option below, all other options will be ignored.' echo ' -e=pkg1*,pkg2 , --exclude=pkg1*,pkg2* list of packages separated with comma to exclude on dnf distro-sync' } @@ -493,9 +497,14 @@ assert_dnf_plugins_core() { # # Prints almalinux-release RPM package download URL. get_release_file_url() { - local -r os_version="${1%%.*}" - local -r arch="${2}" - echo "${ALMA_RELEASE_URL:-${REPO_URL}/almalinux-release-latest-${os_version}.${arch}.rpm}" + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + local -r os_version="${1%%.*}" + local -r arch="${2}" + echo "${ALMA_RELEASE_URL:-${REPO_URL}/almalinux-release-latest-${os_version}.${arch}.rpm}" + else + # get the url of this system's almalinux-release package from dnf + dnf download --url almalinux-release 2>/dev/null | grep http + fi } # Returns a latest almalinux-repos RPM package download URL. @@ -505,9 +514,14 @@ get_release_file_url() { # # Prints almalinux-release RPM package download URL. get_repos_file_url() { - local -r os_version="${1%%.*}" - local -r arch="${2}" - echo "${ALMA_REPOS_URL:-${REPO_URL}/almalinux-repos-latest-${os_version}.${arch}.rpm}" + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + local -r os_version="${1%%.*}" + local -r arch="${2}" + echo "${ALMA_REPOS_URL:-${REPO_URL}/almalinux-repos-latest-${os_version}.${arch}.rpm}" + else + # get the url of this system's almalinux-release package from dnf + dnf download --url almalinux-repos 2>/dev/null | grep http + fi } # Returns a latest almalinux-gpg-keys RPM package download URL. @@ -517,9 +531,14 @@ get_repos_file_url() { # # Prints almalinux-gpg-keys RPM package download URL. get_gpg_keys_file_url() { - local -r os_version="${1%%.*}" - local -r arch="${2}" - echo "${ALMA_REPOS_URL:-${REPO_URL}/almalinux-gpg-keys-latest-${os_version}.${arch}.rpm}" + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + local -r os_version="${1%%.*}" + local -r arch="${2}" + echo "${ALMA_REPOS_URL:-${REPO_URL}/almalinux-gpg-keys-latest-${os_version}.${arch}.rpm}" + else + # get the url of this system's almalinux-release package from dnf + dnf download --url almalinux-gpg-keys 2>/dev/null | grep http + fi } # Downloads and installs the AlmaLinux public PGP key. @@ -532,7 +551,12 @@ install_rpm_pubkey() { fi local -r tmp_dir="${1}" local -r os_version="${2%%.*}" - local -r pubkey_url="${ALMA_PUBKEY_URL:-${REPO_URL}/RPM-GPG-KEY-AlmaLinux-${os_version}}" + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + local -r pubkey_url="${ALMA_PUBKEY_URL:-${REPO_URL}/RPM-GPG-KEY-AlmaLinux-${os_version}}" + else + local -r repo=$(dnf repolist | awk '/BaseOS/{print $1}') + local -r pubkey_url=$(python3 -c "import configparser; c = configparser.ConfigParser(); c.read('/etc/yum.repos.d/redhat.repo'); print(c.get('$repo', 'gpgkey'))") + fi local -r pubkey_path="${tmp_dir}/RPM-GPG-KEY-AlmaLinux" local -r step='Download RPM-GPG-KEY-AlmaLinux' local output @@ -557,7 +581,7 @@ install_rpm_pubkey() { download_release_files() { local -r tmp_dir="${1}" local -r release_url="${2}" - local -r release_path="${tmp_dir}/almalinux-release-latest.rpm" + [[ "${PRESERVE_RHSM}" == "NO" ]] && local -r release_path="${tmp_dir}/almalinux-release-latest.rpm" || local -r release_path="${tmp_dir}/almalinux-release.rpm" local output if ! output=$(curl -f -s -S -o "${release_path}" "${release_url}" 2>&1); then report_step_error 'Download almalinux packages - release' "${output}" @@ -726,9 +750,9 @@ cleanup_sss_cache() { fi if [[ "${DOWNGRADE}" == 'YES' ]]; then for file in /var/lib/sss/db/cache_*.ldb; do - if [ -f "${file}" ]; then - mv -f "${file}" "${file}.bak" - fi + if [ -f "${file}" ]; then + mv -f "${file}" "${file}.bak" + fi done fi save_status_of_stage "cleanup_sss_cache" @@ -785,6 +809,11 @@ install_almalinux_release_package() { fi local -r release_path="${1}" rpm -Uvh --nodeps "${release_path}" + case "${os_version}" in + 8*) + [[ "${PRESERVE_RHSM}" == "YES" ]] && rm -f /etc/yum.repos.d/almalinux*.repo + ;; + esac report_step_done 'Install almalinux-release package' save_status_of_stage "install_almalinux_release_package" } @@ -796,6 +825,7 @@ install_almalinux_repos_package() { fi local -r repos_path="${1}" rpm -Uvh --nodeps "${repos_path}" + [[ "${PRESERVE_RHSM}" == "YES" ]] && rm -f /etc/yum.repos.d/almalinux*.repo report_step_done 'Install almalinux-repos package' save_status_of_stage "install_almalinux_repos_package" } @@ -909,14 +939,17 @@ distro_sync() { local -r step='Run dnf distro-sync -y' local ret_code=0 local -r os_version="${1}" - case "${os_version}" in - 8*) - local dnf_repos="--enablerepo=powertools" - ;; - 9*|10*) - local dnf_repos="--enablerepo=crb" - ;; - esac + local dnf_repos="" + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + case "${os_version}" in + 8*) + local dnf_repos="--enablerepo=powertools" + ;; + 9*|10*) + local dnf_repos="--enablerepo=crb" + ;; + esac + fi local exclude_pkgs="--exclude=" # create needed repo if [ "${panel_type}" == "plesk" ]; then @@ -938,11 +971,20 @@ distro_sync() { if [ -n "${EXCLUDE_PKGS}" ]; then exclude_pkgs+=",${EXCLUDE_PKGS}" fi - dnf distro-sync -y "${dnf_repos}" "${exclude_pkgs}" || { - ret_code=${?} - report_step_error "${step}. Exit code: ${ret_code}" - exit ${ret_code} - } + # We can't have a empty dnf_repos variable, because dnf will fail with "No package installed." (note double space) + if [[ "${dnf_repos}" == "" ]]; then + dnf distro-sync -y "${exclude_pkgs}" || { + ret_code=${?} + report_step_error "${step}. Exit code: ${ret_code}" + exit ${ret_code} + } + else + dnf distro-sync -y "${dnf_repos}" "${exclude_pkgs}" || { + ret_code=${?} + report_step_error "${step}. Exit code: ${ret_code}" + exit ${ret_code} + } + fi # remove unnecessary repo if [ "${panel_type}" == "plesk" ]; then plesk installer --select-release-current --show-components @@ -1251,7 +1293,6 @@ _restore_alternative() { fi done done - } # backup existing alternatives, including the current states of alternatives @@ -1346,7 +1387,7 @@ reinstall_secure_boot_packages() { local kernel_package for pkg in $(rpm -qa | grep -E 'shim|fwupd|grub2'); do if [[ "AlmaLinux" != "$(rpm -q --queryformat '%{vendor}' "$pkg")" ]]; then - yum reinstall "${pkg}" -y + yum reinstall -y "${pkg}" fi done kernel_path="$(grubby --default-kernel)" @@ -1362,7 +1403,23 @@ reinstall_secure_boot_packages() { fi kernel_package="$(rpm -qf "$kernel_path")" if [[ "AlmaLinux" != "$(rpm -q --queryformat '%{vendor}' "${kernel_package}")" ]]; then - yum reinstall "${kernel_package}" -y + if ! yum reinstall -y "$kernel_package"; then + # This exact kernel version isn't in AlmaLinux repositories yet. + # A kernel signed by another vendor won't boot with Secure Boot enabled, + # so make sure the latest AlmaLinux kernel is installed and is the default. + dnf install -y kernel + local alma_kernel + alma_kernel="$(rpm -q kernel --queryformat '%{VENDOR}|%{VERSION}-%{RELEASE}.%{ARCH}\n' \ + | awk -F'|' '$1 == "AlmaLinux" {print $2}' | sort -V | tail -n 1)" + if [[ -z "${alma_kernel}" ]]; then + report_step_error 'Install AlmaLinux kernel' \ + "${kernel_package} is not available in AlmaLinux repositories and no AlmaLinux kernel is installed" + exit 1 + fi + grubby --set-default "/boot/vmlinuz-${alma_kernel}" + echo "${kernel_package} is not available in AlmaLinux repositories yet;" \ + "default kernel set to ${alma_kernel}. The remaining kernel(s) are reported below." + fi fi fi report_step_done "All Secure Boot related packages which were not released by AlmaLinux are reinstalled" @@ -1413,7 +1470,12 @@ remove_redhat_rhsm_rpms() { if get_status_of_stage "remove_redhat_rhsm_rpms"; then return 0 fi - rpm -e --nodeps "${REDHAT_RHSM_RPMS[@]}" >/dev/null 2>&1 || true + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + rpm -e --nodeps "${REDHAT_RHSM_RPMS[@]}" >/dev/null 2>&1 || true + else + # We want dependencies here + dnf remove -y insights-core rhc >/dev/null 2>&1 || true + fi report_step_done "Red Hat Subscription Manager packages are removed (with rpm --nodeps)" save_status_of_stage "remove_redhat_rhsm_rpms" } @@ -1432,6 +1494,32 @@ remove_redhat_repo_files() { save_status_of_stage "remove_redhat_repo_files" } +# Installs the dnf post-transaction-actions plugin and a hook which removes +# AlmaLinux repository files as soon as almalinux-release/almalinux-repos +# create them. Only used with --preserve-rhsm, where repositories are +# managed by subscription-manager (Foreman/Katello). +setup_preserve_rhsm_hook() { + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + return 0 + fi + if get_status_of_stage "setup_preserve_rhsm_hook"; then + return 0 + fi + local -r step='Install dnf post-transaction-actions hook for --preserve-rhsm' + local -r hook_dir='/etc/dnf/plugins/post-transaction-actions.d' + local output + if ! output=$(dnf install -y python3-dnf-plugin-post-transaction-actions 2>&1); then + report_step_error "${step}" "${output}" + exit 1 + fi + mkdir -p "${hook_dir}" + printf '%s\n' '# AlmaLinux Repo files break dnf if no proxy is available' \ + 'almalinux-re*:in:/usr/bin/rm -f /etc/yum.repos.d/almalinux*.repo' \ + > "${hook_dir}/almalinux-repos.conf" + report_step_done "${step}" + save_status_of_stage "setup_preserve_rhsm_hook" +} + main() { is_migration_completed local arch @@ -1443,6 +1531,7 @@ main() { local panel_type local panel_version assert_run_as_root + setup_preserve_rhsm_hook arch="$(get_system_arch)" os_type="$(get_os_release_var 'ID')" os_version="$(get_os_version "${os_type}")" @@ -1451,7 +1540,7 @@ main() { assert_supported_system "${os_type}" "${os_version}" "${arch}" assert_supported_filesystem "${os_version}" assert_dnf_plugins_core - check_local_repo "${os_version}" "${arch}" + [[ "${PRESERVE_RHSM}" == "NO" ]] && check_local_repo "${os_version}" "${arch}" get_enabled_repos read -r panel_type panel_version < <(get_panel_info) @@ -1482,9 +1571,11 @@ main() { backup_issue if [[ "${os_type}" == "rhel" ]]; then - subscription_manager_unregister "${os_version}" + if [[ "${PRESERVE_RHSM}" == "NO" ]]; then + subscription_manager_unregister "${os_version}" + remove_redhat_repo_files + fi remove_redhat_rhsm_rpms - remove_redhat_repo_files fi case "${os_version}" in @@ -1511,9 +1602,9 @@ main() { esac backup_alternatives - switch_to_local_repo "${os_version}" "${arch}" + [[ "${PRESERVE_RHSM}" == "NO" ]] && switch_to_local_repo "${os_version}" "${arch}" reset_wrong_module_streams - enable_repos "${os_version}" + [[ "${PRESERVE_RHSM}" == "NO" ]] && enable_repos "${os_version}" distro_sync "${os_version}" restore_module_streams restore_alternatives @@ -1540,7 +1631,7 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then exit 0 ;; -f | --full) - dnf_upgrade + DNF_UPGRADE='YES' ;; -v | --version) echo "${VERSION}" @@ -1552,6 +1643,9 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then -t | --tests) exit 0 ;; + --preserve-rhsm) + PRESERVE_RHSM='YES' + ;; -e=* | --exclude=*) EXCLUDE_PKGS="${opt#*=}" shift @@ -1568,6 +1662,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then ;; esac done + if [[ "${PRESERVE_RHSM}" == "YES" ]]; then + LOCAL_REPO='NO' + REPO_URL='' + DNF_UPGRADE='NO' + fi + [[ "${DNF_UPGRADE}" == "YES" ]] && dnf_upgrade setup_log_files set -x main