leapp-repository/0028-feat-command_utils-allow-missing-minor-major-version.patch
Petr Stodulka cb46739ce0 IPU 9.7 -> 10.1: CTC 1 candidate 1
- Require leapp-framework >= 6.1
- Simplified use of the LiveMode experimental feature with additional enhancements
- Fix the check of deprecated PCI devices and drivers
- Add RHEL 10.1 product certificates
- Gracefully handle CentOS OS versioning style
- Ensure the leapp-upgrade-el9toel10 RPM is not touched during the upgrade transaction
- Create proper error message when swap of RHUI clients fails
- Introduced the --enable-experimental-feature to simplify use of experimental features
- Manage RPM GPG keys during the upgrade respecting used linux distributions
- Prevent a crach during post-upgrade phases when no custom SELinux modules needs to be migrated
- Update leapp upgrade data files
- Minor fixes in reports
- Resolves: RHEL-49402, RHEL-72544, RHEL-77175, RHEL-80334, RHEL-80335, RHEL-80336, RHEL-80550, RHEL-86689
2025-05-14 10:46:55 +02:00

207 lines
7.6 KiB
Diff

From 097981dd9505d1609b91fbed4e6d28e960161926 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 14 Apr 2025 13:02:40 +0200
Subject: [PATCH 28/37] feat(command_utils): allow missing minor/major version
for CentOS
CentOS versioning consists only of the major version number. Therefore,
in case we are running on CentOS, we do not want to enforce version to
have the format MAJOR.MINOR. Rather, we want to check that the version
is of the form MAJOR. This patch introduces the necessary
infrastructure, allowing easy extensibility of version format checking
for also other distributions. In case we do not know what version
format should a distro use, we default to MINOR.MAJOR.
Jira-ref: RHEL-80334
---
commands/command_utils.py | 92 ++++++++++++++++++++++++++++++---------
commands/upgrade/util.py | 4 +-
2 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/commands/command_utils.py b/commands/command_utils.py
index a13ca59b..155bacad 100644
--- a/commands/command_utils.py
+++ b/commands/command_utils.py
@@ -3,6 +3,8 @@ import json
import os
import re
import resource
+from collections import namedtuple
+from enum import Enum
from leapp.actors import config as actor_config
from leapp.exceptions import CommandError
@@ -16,26 +18,52 @@ LEAPP_UPGRADE_FLAVOUR_DEFAULT = 'default'
LEAPP_UPGRADE_FLAVOUR_SAP_HANA = 'saphana'
LEAPP_UPGRADE_PATHS = 'upgrade_paths.json'
-VERSION_REGEX = re.compile(r"^([1-9]\d*)\.(\d+)$")
+_VersionFormat = namedtuple('VersionFormat', ('human_readable', 'regex'))
-def check_version(version):
+
+class VersionFormats(Enum):
+ MAJOR_ONLY = _VersionFormat('MAJOR_VER', re.compile(r'^[1-9]\d*$'))
+ MAJOR_MINOR = _VersionFormat('MAJOR_VER.MINOR_VER', re.compile(r"^([1-9]\d*)\.(\d+)$"))
+
+
+class _VersionKind(str, Enum):
+ """ Enum encoding information whether the given OS version is source or target. """
+ SOURCE = 'source'
+ TARGET = 'target'
+
+
+class DistroIDs(str, Enum):
+ RHEL = 'rhel'
+ CENTOS = 'centos'
+
+
+_DISTRO_VERSION_FORMATS = {
+ DistroIDs.RHEL: VersionFormats.MAJOR_MINOR,
+ DistroIDs.CENTOS: VersionFormats.MAJOR_ONLY,
+}
+"""
+Maps distro ID to the expected OS version format.
+
+If a distro is not listed in the dictionary, then VersionFormats.MAJOR_MINOR
+is used as a default.
+"""
+
+
+def assert_version_format(version_str, desired_format, version_kind):
"""
- Versioning schema: MAJOR.MINOR
- In case version contains an invalid version string, an CommandError will be raised.
+ Check whether a given version_str has the given desired format.
+
+ In case the version does not conform to the desired_format, an CommandError will be raised.
:raises: CommandError
- :return: release tuple
"""
- if not re.match(VERSION_REGEX, version):
- raise CommandError(
- "Unexpected format of target version: {}. "
- "The required format is 'X.Y' (major and minor version).".format(version)
- )
- return version.split('.')
+ if not re.match(desired_format.regex, version_str):
+ error_str = 'Unexpected format of target version: {0}. The required format is \'{1}\'.'
+ raise CommandError(error_str.format(version_str, desired_format.human_readable))
-def get_major_version(version):
+def get_major_version_from_a_valid_version(version):
"""
Return the major version from the given version string.
@@ -45,7 +73,7 @@ def get_major_version(version):
:rtype: str
:returns: The major version from the given version string.
"""
- return str(check_version(version)[0])
+ return version.split('.')[0]
def detect_sap_hana():
@@ -71,7 +99,7 @@ def get_upgrade_flavour():
return LEAPP_UPGRADE_FLAVOUR_DEFAULT
-def _retrieve_os_release_contents(_os_release_path='/etc/os-release'):
+def _retrieve_os_release_contents(_os_release_path='/etc/os-release', strip_double_quotes=True):
"""
Retrieve the contents of /etc/os-release
@@ -79,7 +107,20 @@ def _retrieve_os_release_contents(_os_release_path='/etc/os-release'):
"""
with open(_os_release_path) as os_release_handle:
lines = os_release_handle.readlines()
- return dict(line.strip().split('=', 1) for line in lines if '=' in line)
+
+ os_release_contents = {}
+ for line in lines:
+ if '=' not in line:
+ continue
+
+ key, value = line.strip().split('=', 1)
+
+ if strip_double_quotes:
+ value = value.strip('"')
+
+ os_release_contents[key] = value
+
+ return os_release_contents
def get_os_release_version_id(filepath):
@@ -88,7 +129,7 @@ def get_os_release_version_id(filepath):
:return: `str` version_id
"""
- return _retrieve_os_release_contents(_os_release_path=filepath).get('VERSION_ID', '').strip('"')
+ return _retrieve_os_release_contents(_os_release_path=filepath).get('VERSION_ID', '')
def get_upgrade_paths_config():
@@ -117,15 +158,20 @@ def get_supported_target_versions(flavour=get_upgrade_flavour()):
"""
os_release_contents = _retrieve_os_release_contents()
- current_version_id = os_release_contents.get('VERSION_ID', '').strip('"')
- distro_id = os_release_contents.get('ID', '').strip('"')
+ current_version_id = os_release_contents.get('VERSION_ID', '')
+ distro_id = os_release_contents.get('ID', '')
+
+ # We want to guarantee our actors that if they see 'centos'/'rhel'/...
+ # then they will always see expected version format
+ expected_version_format = _DISTRO_VERSION_FORMATS.get(distro_id, VersionFormats.MAJOR_MINOR).value
+ assert_version_format(current_version_id, expected_version_format, _VersionKind.SOURCE)
target_versions = get_target_versions_from_config(current_version_id, distro_id, flavour)
if not target_versions:
# If we cannot find a particular major.minor version in the map,
# we fallback to pick a target version just based on a major version.
# This can happen for example when testing not yet released versions
- major_version = get_major_version(current_version_id)
+ major_version = get_major_version_from_a_valid_version(current_version_id)
target_versions = get_target_versions_from_config(major_version, distro_id, flavour)
return target_versions
@@ -145,9 +191,15 @@ def vet_upgrade_path(args):
"""
flavor = get_upgrade_flavour()
env_version_override = os.getenv('LEAPP_DEVEL_TARGET_RELEASE')
+
if env_version_override:
- check_version(env_version_override)
+ os_release_contents = _retrieve_os_release_contents()
+ distro_id = os_release_contents.get('ID', '')
+ expected_version_format = _DISTRO_VERSION_FORMATS.get(distro_id, VersionFormats.MAJOR_MINOR).value
+ assert_version_format(env_version_override, expected_version_format, _VersionKind.TARGET)
+
return (env_version_override, flavor)
+
target_release = args.target or get_target_version(flavor)
return (target_release, flavor)
diff --git a/commands/upgrade/util.py b/commands/upgrade/util.py
index 6cdfa6d8..b54b0b34 100644
--- a/commands/upgrade/util.py
+++ b/commands/upgrade/util.py
@@ -260,8 +260,8 @@ def prepare_configuration(args):
current_version = command_utils.get_os_release_version_id('/etc/os-release')
os.environ['LEAPP_IPU_IN_PROGRESS'] = '{source}to{target}'.format(
- source=command_utils.get_major_version(current_version),
- target=command_utils.get_major_version(target_version)
+ source=command_utils.get_major_version_from_a_valid_version(current_version),
+ target=command_utils.get_major_version_from_a_valid_version(target_version)
)
configuration = {
--
2.49.0