leapp-repository/SOURCES/0028-feat-command_utils-allow-missing-minor-major-version.patch
eabdullin b1bd6e77a6 Import from CS git
(cherry picked from commit 5bdc5cf293)
2025-05-15 11:55:21 +03: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