Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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

Expand All @@ -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`
Expand Down
48 changes: 48 additions & 0 deletions README_PRESERVE_RHSM.md
Original file line number Diff line number Diff line change
@@ -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.
134 changes: 97 additions & 37 deletions almalinux-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ VERSION='0.1.13'
DOWNGRADE='NO'
REPO_URL=https://repo.almalinux.org/almalinux
LOCAL_REPO='NO'
PRESERVE_RHSM='NO'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the line 1630: DNF_UPGRADE: unbound variable

Suggested change
PRESERVE_RHSM='NO'
PRESERVE_RHSM='NO'
DNF_UPGRADE='NO'


BRANDING_PKGS=("centos-backgrounds" "centos-logos" "centos-indexhtml" \
"centos-logos-ipa" "centos-logos-httpd" \
Expand Down Expand Up @@ -179,6 +180,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'
}

Expand Down Expand Up @@ -493,9 +496,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.
Expand All @@ -505,9 +513,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.
Expand All @@ -517,9 +530,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.
Expand All @@ -532,7 +550,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
Expand All @@ -557,7 +580,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}"
Expand Down Expand Up @@ -726,9 +749,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"
Expand Down Expand Up @@ -785,6 +808,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"
}
Expand All @@ -796,6 +824,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"
}
Expand Down Expand Up @@ -909,14 +938,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
Expand All @@ -938,11 +970,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
Expand Down Expand Up @@ -1251,7 +1292,6 @@ _restore_alternative() {
fi
done
done

}

# backup existing alternatives, including the current states of alternatives
Expand Down Expand Up @@ -1346,7 +1386,8 @@ 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
# There is a timing issue where some packages are available on RHEL but not yet on AlmaLinux mirrors, so we ignore errors here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Secure Boot package reinstall is a safety regression and unrelated to the feature. And we can't ignore errors here.

Suggested change
# There is a timing issue where some packages are available on RHEL but not yet on AlmaLinux mirrors, so we ignore errors here

yum reinstall -y "${pkg}" || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the AlmaLinux-signed shim/kernel isn't actually installed, a Secure Boot machine won't boot after migration.

Suggested change
yum reinstall -y "${pkg}" || true
yum reinstall "${pkg}" -y

@nlaphine nlaphine Aug 26, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies this comment landed on the wrong suggested update.

That's incorrect. The almalinux kernel that you install is the one it boots to. I have machines with a newer RH kernel but boots to the AL kernel. This is safe.
Not putting this in means people have to waiting until AL catches up with the latest kernel.
It's why I put the change in. The script just errors out because that kernel is not available in AL yet.

Alternately in some other backend process, AL must move kernel packages thru faster.

As an example, I am just going to allow the system to slowly move the kernels through their natural cycle :

sudo dnf list installed | grep kernel.x86_64
kernel.x86_64                                      5.14.0-687.33.1.el9_8                 @rhel-9-for-x86_64-baseos-rpms
kernel.x86_64                                      5.14.0-687.36.1.el9_8                 @rhel-9-for-x86_64-baseos-rpms
kernel.x86_64                                      5.14.0-687.38.1.el9_8                 @rhel-9-for-x86_64-baseos-rpms
kernel.x86_64                                      5.14.0-687.39.1.el9_8                 @NLA_AlmaLinux_9_BaseOS_RPMs
kernel.x86_64                                      5.14.0-687.41.1.el9_8                 @rhel-9-for-x86_64-baseos-rpms

uname -r
5.14.0-687.39.1.el9_8.x86_64

What i should do is remove 5.14.0-687.41.1.el9_8 so that it can reinstalled from AL repo.
P

fi
done
kernel_path="$(grubby --default-kernel)"
Expand All @@ -1362,7 +1403,8 @@ 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
# There is a timing issue where kernel packages are available on RHEL but not yet on AlmaLinux mirrors, so we ignore errors here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Secure Boot package reinstall is a safety regression and unrelated to the feature. And we can't ignore errors here.

Suggested change
# There is a timing issue where kernel packages are available on RHEL but not yet on AlmaLinux mirrors, so we ignore errors here

yum reinstall -y "$kernel_package" || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the AlmaLinux-signed shim/kernel isn't actually installed, a Secure Boot machine won't boot after migration.

Suggested change
yum reinstall -y "$kernel_package" || true
yum reinstall "${pkg}" -y

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not put parameters like -y, etc at the end of commands. It's a security risk, though I can not find the original article any more.

It's not a good habit to be in, that's why i swapped them

fi
fi
report_step_done "All Secure Boot related packages which were not released by AlmaLinux are reinstalled"
Expand Down Expand Up @@ -1413,7 +1455,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"
}
Expand Down Expand Up @@ -1451,7 +1498,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)
Expand Down Expand Up @@ -1482,9 +1529,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
Expand All @@ -1511,9 +1560,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
Expand All @@ -1540,7 +1589,7 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
exit 0
;;
-f | --full)
dnf_upgrade
DNF_UPGRADE='YES'
;;
-v | --version)
echo "${VERSION}"
Expand All @@ -1552,6 +1601,9 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
-t | --tests)
exit 0
;;
--preserve-rhsm)
PRESERVE_RHSM='YES'
;;
-e=* | --exclude=*)
EXCLUDE_PKGS="${opt#*=}"
shift
Expand All @@ -1568,6 +1620,14 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
;;
esac
done
if [[ "${PRESERVE_RHSM}" == "YES" ]]; then
LOCAL_REPO='NO'
REPO_URL=''
DNF_UPGRADE='NO'
dnf install -y python3-dnf-plugin-post-transaction-actions >/dev/null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

System-modifying in the option-parsing block, before root check, logging, etc ...

Suggested change
dnf install -y python3-dnf-plugin-post-transaction-actions >/dev/null

echo -e '# AlmaLinux Repo files break dnf if no proxy is available\nalmalinux-re*:in:/usr/bin/rm -f /etc/yum.repos.d/almalinux*.repo' > /etc/dnf/plugins/post-transaction-actions.d/almalinux-repos.conf

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this into a proper stage function called from main() (after assert_run_as_root)

Suggested change
echo -e '# AlmaLinux Repo files break dnf if no proxy is available\nalmalinux-re*:in:/usr/bin/rm -f /etc/yum.repos.d/almalinux*.repo' > /etc/dnf/plugins/post-transaction-actions.d/almalinux-repos.conf

fi
[[ "${DNF_UPGRADE}" == "YES" ]] && dnf_upgrade
setup_log_files
set -x
main
Expand Down