From cc419236dd66e007089da7063256b6dbb6b7d7fe Mon Sep 17 00:00:00 2001 From: Fabian Fulga Date: Wed, 1 Jul 2026 12:31:31 +0300 Subject: [PATCH] Refactor osdetect for rhel family OSes --- coriolis/osmorphing/centos.py | 6 +- coriolis/osmorphing/oracle.py | 4 +- coriolis/osmorphing/osdetect/centos.py | 41 ++------ coriolis/osmorphing/osdetect/oracle.py | 26 +---- coriolis/osmorphing/osdetect/redhat.py | 34 +------ coriolis/osmorphing/osdetect/redhat_common.py | 63 ++++++++++++ coriolis/osmorphing/osdetect/rocky.py | 34 +------ .../tests/osmorphing/osdetect/test_centos.py | 95 +++++++++++-------- .../tests/osmorphing/osdetect/test_oracle.py | 38 ++++++-- .../tests/osmorphing/osdetect/test_redhat.py | 42 ++++---- .../osmorphing/osdetect/test_redhat_common.py | 78 +++++++++++++++ .../tests/osmorphing/osdetect/test_rocky.py | 77 ++++++++------- 12 files changed, 312 insertions(+), 226 deletions(-) create mode 100644 coriolis/osmorphing/osdetect/redhat_common.py create mode 100644 coriolis/tests/osmorphing/osdetect/test_redhat_common.py diff --git a/coriolis/osmorphing/centos.py b/coriolis/osmorphing/centos.py index f25956c1a..d7628d8d8 100644 --- a/coriolis/osmorphing/centos.py +++ b/coriolis/osmorphing/centos.py @@ -22,7 +22,11 @@ class BaseCentOSMorphingTools(redhat.BaseRedHatMorphingTools): @classmethod def check_os_supported(cls, detected_os_info): supported_oses = [ - CENTOS_STREAM_DISTRO_IDENTIFIER, CENTOS_DISTRO_IDENTIFIER] + CENTOS_STREAM_DISTRO_IDENTIFIER, + CENTOS_DISTRO_IDENTIFIER, + "CentOS Linux", + "AlmaLinux", + ] if detected_os_info['distribution_name'] not in supported_oses: return False return cls._version_supported_util( diff --git a/coriolis/osmorphing/oracle.py b/coriolis/osmorphing/oracle.py index e41415fa2..6e652ed9a 100644 --- a/coriolis/osmorphing/oracle.py +++ b/coriolis/osmorphing/oracle.py @@ -18,8 +18,8 @@ class BaseOracleMorphingTools(redhat.BaseRedHatMorphingTools): @classmethod def check_os_supported(cls, detected_os_info): - if detected_os_info['distribution_name'] != ( - ORACLE_DISTRO_IDENTIFIER): + if detected_os_info['distribution_name'] not in ( + ORACLE_DISTRO_IDENTIFIER, "Oracle Linux Server"): return False return cls._version_supported_util( detected_os_info['release_version'], minimum=6) diff --git a/coriolis/osmorphing/osdetect/centos.py b/coriolis/osmorphing/osdetect/centos.py index 135a15b2f..db7c2f457 100644 --- a/coriolis/osmorphing/osdetect/centos.py +++ b/coriolis/osmorphing/osdetect/centos.py @@ -1,46 +1,17 @@ # Copyright 2020 Cloudbase Solutions Srl # All Rights Reserved. -import re - -from coriolis import constants from coriolis.osmorphing.osdetect import base -from oslo_log import log as logging +from coriolis.osmorphing.osdetect import redhat_common -LOG = logging.getLogger(__name__) -CENTOS_DISTRO_IDENTIFIER = "CentOS" -CENTOS_STREAM_DISTRO_IDENTIFIER = "CentOS Stream" -ALMA_IDENTIFIER = "AlmaLinux" +CENTOS_DISTRO_IDENTIFIER = redhat_common.CENTOS_DISTRO_IDENTIFIER +CENTOS_STREAM_DISTRO_IDENTIFIER = redhat_common.CENTOS_STREAM_DISTRO_IDENTIFIER class CentOSOSDetectTools(base.BaseLinuxOSDetectTools): def detect_os(self): - info = {} - redhat_release_path = "etc/redhat-release" - if self._test_path(redhat_release_path): - release_info = self._read_file( - redhat_release_path).decode().splitlines() - if release_info: - m = re.match(r"^(.*) release ([0-9]+(\.[0-9]+)*)( \(.*\))?.*$", - release_info[0].strip()) - if m: - distro, version, _, _ = m.groups() - if (CENTOS_DISTRO_IDENTIFIER not in distro and - ALMA_IDENTIFIER not in distro): - LOG.debug( - "Distro does not appear to be a CentOS or Alma: " - f"{distro}") - return {} - - distribution_name = CENTOS_DISTRO_IDENTIFIER - if CENTOS_STREAM_DISTRO_IDENTIFIER in distro: - distribution_name = CENTOS_STREAM_DISTRO_IDENTIFIER - info = { - "os_type": constants.OS_TYPE_LINUX, - "distribution_name": distribution_name, - "release_version": version, - "friendly_release_name": "%s Version %s" % ( - distribution_name, version)} - return info + return redhat_common.detect_os_from_os_release( + self._get_os_release(), + match_ids={"centos", "almalinux"}) diff --git a/coriolis/osmorphing/osdetect/oracle.py b/coriolis/osmorphing/osdetect/oracle.py index c52ea3d5d..5cdca8ac8 100644 --- a/coriolis/osmorphing/osdetect/oracle.py +++ b/coriolis/osmorphing/osdetect/oracle.py @@ -1,32 +1,16 @@ # Copyright 2020 Cloudbase Solutions Srl # All Rights Reserved. -import re - -from coriolis import constants from coriolis.osmorphing.osdetect import base +from coriolis.osmorphing.osdetect import redhat_common -ORACLE_DISTRO_IDENTIFIER = "Oracle Linux" +ORACLE_DISTRO_IDENTIFIER = redhat_common.ORACLE_DISTRO_IDENTIFIER class OracleOSDetectTools(base.BaseLinuxOSDetectTools): def detect_os(self): - info = {} - oracle_release_path = "etc/oracle-release" - if self._test_path(oracle_release_path): - release_info = self._read_file( - oracle_release_path).decode().splitlines() - if release_info: - m = re.match(r"^(.*) release ([0-9].*)$", - release_info[0].strip()) - if m: - distro, version = m.groups() - info = { - "os_type": constants.OS_TYPE_LINUX, - "distribution_name": ORACLE_DISTRO_IDENTIFIER, - "release_version": version, - "friendly_release_name": "%s Version %s" % ( - distro, version)} - return info + return redhat_common.detect_os_from_os_release( + self._get_os_release(), + match_ids={"ol"}) diff --git a/coriolis/osmorphing/osdetect/redhat.py b/coriolis/osmorphing/osdetect/redhat.py index 90f12a354..2629e4301 100644 --- a/coriolis/osmorphing/osdetect/redhat.py +++ b/coriolis/osmorphing/osdetect/redhat.py @@ -1,40 +1,16 @@ # Copyright 2020 Cloudbase Solutions Srl # All Rights Reserved. -import re - -from oslo_log import log as logging - -from coriolis import constants from coriolis.osmorphing.osdetect import base +from coriolis.osmorphing.osdetect import redhat_common -LOG = logging.getLogger(__name__) -RED_HAT_DISTRO_IDENTIFIER = "Red Hat Enterprise Linux" +RED_HAT_DISTRO_IDENTIFIER = redhat_common.RED_HAT_DISTRO_IDENTIFIER class RedHatOSDetectTools(base.BaseLinuxOSDetectTools): def detect_os(self): - info = {} - redhat_release_path = "etc/redhat-release" - if self._test_path(redhat_release_path): - release_info = self._read_file( - redhat_release_path).decode().splitlines() - if release_info: - m = re.match(r"^(.*) release ([0-9].*) \((.*)\).*$", - release_info[0].strip()) - if m: - distro, version, _ = m.groups() - if RED_HAT_DISTRO_IDENTIFIER not in distro: - LOG.debug( - "Distro does not appear to be a RHEL: %s", distro) - return {} - - info = { - "os_type": constants.OS_TYPE_LINUX, - "distribution_name": RED_HAT_DISTRO_IDENTIFIER, - "release_version": version, - "friendly_release_name": "%s Version %s" % ( - RED_HAT_DISTRO_IDENTIFIER, version)} - return info + return redhat_common.detect_os_from_os_release( + self._get_os_release(), + match_ids={"rhel"}) diff --git a/coriolis/osmorphing/osdetect/redhat_common.py b/coriolis/osmorphing/osdetect/redhat_common.py new file mode 100644 index 000000000..27c5a1956 --- /dev/null +++ b/coriolis/osmorphing/osdetect/redhat_common.py @@ -0,0 +1,63 @@ +# Copyright 2026 Cloudbase Solutions Srl +# All Rights Reserved. + +"""Shared /etc/os-release parsing for RHEL-family osdetect tools.""" + +from typing import Dict +from typing import Optional +from typing import Set + +from oslo_log import log as logging + +from coriolis import constants + +LOG = logging.getLogger(__name__) + +ROCKY_LINUX_DISTRO_IDENTIFIER = "Rocky Linux" +CENTOS_DISTRO_IDENTIFIER = "CentOS" +CENTOS_STREAM_DISTRO_IDENTIFIER = "CentOS Stream" +RED_HAT_DISTRO_IDENTIFIER = "Red Hat Enterprise Linux" +ORACLE_DISTRO_IDENTIFIER = "Oracle Linux" + + +def detect_os_from_os_release( + os_release: Optional[Dict[str, str]], + *, + match_ids: Set[str]) -> Dict[str, str]: + """Detect a RHEL-family distro from /etc/os-release. + + :param os_release: dict populated by ``/etc/os-release`` values, as + returned by ``BaseLinuxOSDetectTools._get_os_release()``. + :param match_ids: ``ID`` value(s) this osdetect module handles, e.g. + ``{"rocky"}`` or ``{"centos", "almalinux"}``. + """ + if not os_release: + LOG.warning( + "Could not detect OS from /etc/os-release: os_release dict " + "was not provided") + return {} + + os_id = (os_release.get("ID") or "").lower() + if os_id not in match_ids: + return {} + + distribution_name = os_release.get("NAME") + if not distribution_name: + LOG.warning( + "Could not detect OS from /etc/os-release: matched OS ID '%s' " + "but NAME is missing", os_id) + return {} + + version = os_release.get("VERSION_ID") + if not version: + LOG.warning( + "Could not detect OS from /etc/os-release: matched OS ID '%s' " + "but VERSION_ID is missing", os_id) + return {} + + return { + "os_type": constants.OS_TYPE_LINUX, + "distribution_name": distribution_name, + "release_version": version, + "friendly_release_name": "%s Version %s" % ( + distribution_name, version)} diff --git a/coriolis/osmorphing/osdetect/rocky.py b/coriolis/osmorphing/osdetect/rocky.py index b79ea0ef9..7281d0226 100644 --- a/coriolis/osmorphing/osdetect/rocky.py +++ b/coriolis/osmorphing/osdetect/rocky.py @@ -1,40 +1,16 @@ # Copyright 2023 Cloudbase Solutions Srl # All Rights Reserved. -import re - -from coriolis import constants from coriolis.osmorphing.osdetect import base -from oslo_log import log as logging +from coriolis.osmorphing.osdetect import redhat_common -LOG = logging.getLogger(__name__) -ROCKY_LINUX_DISTRO_IDENTIFIER = "Rocky Linux" +ROCKY_LINUX_DISTRO_IDENTIFIER = redhat_common.ROCKY_LINUX_DISTRO_IDENTIFIER class RockyLinuxOSDetectTools(base.BaseLinuxOSDetectTools): def detect_os(self): - info = {} - redhat_release_path = "etc/redhat-release" - if self._test_path(redhat_release_path): - release_info = self._read_file( - redhat_release_path).decode().splitlines() - if release_info: - m = re.match(r"^(.*) release ([0-9]+(\.[0-9]+)*)( \(.*\))?.*$", - release_info[0].strip()) - if m: - distro, version, _, _ = m.groups() - if ROCKY_LINUX_DISTRO_IDENTIFIER not in distro: - LOG.debug( - "Distro does not appear to be a Rocky Linux: %s", - distro) - return {} - - info = { - "os_type": constants.OS_TYPE_LINUX, - "distribution_name": ROCKY_LINUX_DISTRO_IDENTIFIER, - "release_version": version, - "friendly_release_name": "%s Version %s" % ( - ROCKY_LINUX_DISTRO_IDENTIFIER, version)} - return info + return redhat_common.detect_os_from_os_release( + self._get_os_release(), + match_ids={"rocky"}) diff --git a/coriolis/tests/osmorphing/osdetect/test_centos.py b/coriolis/tests/osmorphing/osdetect/test_centos.py index a77f80b4d..dc6cb3532 100644 --- a/coriolis/tests/osmorphing/osdetect/test_centos.py +++ b/coriolis/tests/osmorphing/osdetect/test_centos.py @@ -1,9 +1,9 @@ # Copyright 2024 Cloudbase Solutions Srl # All Rights Reserved. -import logging from unittest import mock +from coriolis import constants from coriolis.osmorphing.osdetect import base from coriolis.osmorphing.osdetect import centos from coriolis.tests import test_base @@ -18,35 +18,37 @@ def setUp(self): mock.sentinel.conn, mock.sentinel.os_root_dir, mock.sentinel.operation_timeout) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"CentOS Linux release 7.9 (Core)" + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "centos", + "VERSION_ID": "7.9", + "NAME": "CentOS Linux", + } expected_info = { - "os_type": centos.constants.OS_TYPE_LINUX, - "distribution_name": centos.CENTOS_DISTRO_IDENTIFIER, + "os_type": constants.OS_TYPE_LINUX, + "distribution_name": "CentOS Linux", "release_version": '7.9', - "friendly_release_name": "%s Version %s" % ( - centos.CENTOS_DISTRO_IDENTIFIER, '7.9') + "friendly_release_name": "CentOS Linux Version 7.9", } result = self.centos_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + mock_get_os_release.assert_called_once_with() self.assertEqual(result, expected_info) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os_centos_stream(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"CentOS Stream release 8.3" + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_centos_stream(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "centos", + "VERSION_ID": "8.3", + "NAME": "CentOS Stream", + } expected_info = { - "os_type": centos.constants.OS_TYPE_LINUX, + "os_type": constants.OS_TYPE_LINUX, "distribution_name": centos.CENTOS_STREAM_DISTRO_IDENTIFIER, "release_version": '8.3', "friendly_release_name": "%s Version %s" % ( @@ -55,19 +57,20 @@ def test_detect_os_centos_stream(self, mock_read_file, mock_test_path): result = self.centos_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + mock_get_os_release.assert_called_once_with() self.assertEqual(result, expected_info) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os_centos_stream_10(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"CentOS Stream release 10" + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_centos_stream_10(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "centos", + "VERSION_ID": "10", + "NAME": "CentOS Stream", + } expected_info = { - "os_type": centos.constants.OS_TYPE_LINUX, + "os_type": constants.OS_TYPE_LINUX, "distribution_name": centos.CENTOS_STREAM_DISTRO_IDENTIFIER, "release_version": '10', "friendly_release_name": "%s Version %s" % ( @@ -78,17 +81,35 @@ def test_detect_os_centos_stream_10(self, mock_read_file, mock_test_path): self.assertEqual(result, expected_info) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os_not_centos(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"dummy release 8.3" + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_almalinux(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "almalinux", + "VERSION_ID": "9.4", + "NAME": "AlmaLinux", + "ID_LIKE": "rhel centos fedora", + } + + expected_info = { + "os_type": constants.OS_TYPE_LINUX, + "distribution_name": "AlmaLinux", + "release_version": '9.4', + "friendly_release_name": "AlmaLinux Version 9.4", + } + + result = self.centos_os_detect_tools.detect_os() - with self.assertLogs('coriolis.osmorphing.osdetect.centos', - level=logging.DEBUG): - result = self.centos_os_detect_tools.detect_os() + self.assertEqual(result, expected_info) - self.assertEqual(result, {}) + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_not_centos(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "rocky", + "VERSION_ID": "8.3", + "NAME": "Rocky Linux", + } + + result = self.centos_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + self.assertEqual(result, {}) + mock_get_os_release.assert_called_once_with() diff --git a/coriolis/tests/osmorphing/osdetect/test_oracle.py b/coriolis/tests/osmorphing/osdetect/test_oracle.py index 9386057af..e04f96343 100644 --- a/coriolis/tests/osmorphing/osdetect/test_oracle.py +++ b/coriolis/tests/osmorphing/osdetect/test_oracle.py @@ -3,6 +3,7 @@ from unittest import mock +from coriolis import constants from coriolis.osmorphing.osdetect import base from coriolis.osmorphing.osdetect import oracle from coriolis.tests import test_base @@ -11,17 +12,19 @@ class OracleOSDetectToolsTestCase(test_base.CoriolisBaseTestCase): """Test suite for the OracleOSDetectTools class.""" - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"Oracle Linux release 8.4" + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "ol", + "VERSION_ID": "8.4", + "NAME": "Oracle Linux Server", + } expected_info = { - "os_type": oracle.constants.OS_TYPE_LINUX, - "distribution_name": oracle.ORACLE_DISTRO_IDENTIFIER, + "os_type": constants.OS_TYPE_LINUX, + "distribution_name": "Oracle Linux Server", "release_version": '8.4', - "friendly_release_name": "Oracle Linux Version 8.4" + "friendly_release_name": "Oracle Linux Server Version 8.4" } oracle_os_detect_tools = oracle.OracleOSDetectTools( @@ -29,7 +32,22 @@ def test_detect_os(self, mock_read_file, mock_test_path): mock.sentinel.operation_timeout) result = oracle_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/oracle-release") - mock_read_file.assert_called_once_with("etc/oracle-release") + mock_get_os_release.assert_called_once_with() self.assertEqual(result, expected_info) + + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_not_oracle(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "rhel", + "VERSION_ID": "9.8", + "NAME": "Red Hat Enterprise Linux", + } + + oracle_os_detect_tools = oracle.OracleOSDetectTools( + mock.sentinel.conn, mock.sentinel.os_root_dir, + mock.sentinel.operation_timeout) + + result = oracle_os_detect_tools.detect_os() + + self.assertEqual(result, {}) diff --git a/coriolis/tests/osmorphing/osdetect/test_redhat.py b/coriolis/tests/osmorphing/osdetect/test_redhat.py index 350aaa6ad..047481955 100644 --- a/coriolis/tests/osmorphing/osdetect/test_redhat.py +++ b/coriolis/tests/osmorphing/osdetect/test_redhat.py @@ -1,9 +1,9 @@ # Copyright 2024 Cloudbase Solutions Srl # All Rights Reserved. -import logging from unittest import mock +from coriolis import constants from coriolis.osmorphing.osdetect import base from coriolis.osmorphing.osdetect import redhat from coriolis.tests import test_base @@ -18,15 +18,16 @@ def setUp(self): mock.sentinel.conn, mock.sentinel.os_root_dir, mock.sentinel.operation_timeout) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = ( - b"Red Hat Enterprise Linux release 8.4 (Ootpa)") + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "rhel", + "VERSION_ID": "8.4", + "NAME": "Red Hat Enterprise Linux", + } expected_info = { - "os_type": redhat.constants.OS_TYPE_LINUX, + "os_type": constants.OS_TYPE_LINUX, "distribution_name": redhat.RED_HAT_DISTRO_IDENTIFIER, "release_version": '8.4', "friendly_release_name": "%s Version %s" % ( @@ -35,22 +36,19 @@ def test_detect_os(self, mock_read_file, mock_test_path): result = self.redhat_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + mock_get_os_release.assert_called_once_with() self.assertEqual(result, expected_info) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os_no_redhat(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"CentOS Linux release 8.4 (Ootpa)" - - with self.assertLogs('coriolis.osmorphing.osdetect.redhat', - level=logging.DEBUG): - result = self.redhat_os_detect_tools.detect_os() + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_no_redhat(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "centos", + "VERSION_ID": "8.4", + "NAME": "CentOS Linux", + } - self.assertEqual(result, {}) + result = self.redhat_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + self.assertEqual(result, {}) + mock_get_os_release.assert_called_once_with() diff --git a/coriolis/tests/osmorphing/osdetect/test_redhat_common.py b/coriolis/tests/osmorphing/osdetect/test_redhat_common.py new file mode 100644 index 000000000..0cb140ae1 --- /dev/null +++ b/coriolis/tests/osmorphing/osdetect/test_redhat_common.py @@ -0,0 +1,78 @@ +# Copyright 2026 Cloudbase Solutions Srl +# All Rights Reserved. + +import logging + +from coriolis import constants +from coriolis.osmorphing.osdetect import redhat_common +from coriolis.tests import test_base + + +class RedHatCommonOSDetectTestCase(test_base.CoriolisBaseTestCase): + """Test suite for the RHEL-family os-release detect helper.""" + + def test_detect_os_from_os_release_empty_release(self): + with self.assertLogs( + 'coriolis.osmorphing.osdetect.redhat_common', + level=logging.WARNING) as logs: + self.assertEqual( + redhat_common.detect_os_from_os_release( + {}, match_ids={"rocky"}), {}) + self.assertEqual( + redhat_common.detect_os_from_os_release( + None, match_ids={"rocky"}), {}) + self.assertEqual(len(logs.output), 2) + + def test_detect_os_from_os_release_id_mismatch(self): + os_release = { + "ID": "centos", "VERSION_ID": "9", "NAME": "CentOS Linux" + } + self.assertEqual( + redhat_common.detect_os_from_os_release( + os_release, match_ids={"rocky"}), {}) + + def test_detect_os_from_os_release_missing_name(self): + os_release = {"ID": "rocky", "VERSION_ID": "8"} + with self.assertLogs( + 'coriolis.osmorphing.osdetect.redhat_common', + level=logging.WARNING): + self.assertEqual( + redhat_common.detect_os_from_os_release( + os_release, match_ids={"rocky"}), {}) + + def test_detect_os_from_os_release_missing_version(self): + os_release = {"ID": "rocky", "NAME": "Rocky Linux"} + with self.assertLogs( + 'coriolis.osmorphing.osdetect.redhat_common', + level=logging.WARNING): + self.assertEqual( + redhat_common.detect_os_from_os_release( + os_release, match_ids={"rocky"}), {}) + + def test_detect_os_from_os_release_centos_stream(self): + os_release = { + "ID": "centos", + "VERSION_ID": "9", + "NAME": "CentOS Stream", + } + expected = { + "os_type": constants.OS_TYPE_LINUX, + "distribution_name": "CentOS Stream", + "release_version": "9", + "friendly_release_name": "CentOS Stream Version 9", + } + self.assertEqual( + redhat_common.detect_os_from_os_release( + os_release, match_ids={"centos", "almalinux"}), + expected) + + def test_detect_os_from_os_release_almalinux(self): + os_release = { + "ID": "almalinux", + "VERSION_ID": "9.4", + "NAME": "AlmaLinux", + } + result = redhat_common.detect_os_from_os_release( + os_release, match_ids={"centos", "almalinux"}) + self.assertEqual(result["distribution_name"], "AlmaLinux") + self.assertEqual(result["release_version"], "9.4") diff --git a/coriolis/tests/osmorphing/osdetect/test_rocky.py b/coriolis/tests/osmorphing/osdetect/test_rocky.py index fbbcc5637..ed0498bcd 100644 --- a/coriolis/tests/osmorphing/osdetect/test_rocky.py +++ b/coriolis/tests/osmorphing/osdetect/test_rocky.py @@ -3,6 +3,7 @@ from unittest import mock +from coriolis import constants from coriolis.osmorphing.osdetect import base from coriolis.osmorphing.osdetect import rocky from coriolis.tests import test_base @@ -11,65 +12,61 @@ class RockyLinuxOSDetectToolsTestCase(test_base.CoriolisBaseTestCase): """Test suite for the RockyLinuxOSDetectTools class.""" - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"Rocky Linux release 8.4" + def setUp(self): + super(RockyLinuxOSDetectToolsTestCase, self).setUp() + self.rocky_os_detect_tools = rocky.RockyLinuxOSDetectTools( + mock.sentinel.conn, mock.sentinel.os_root_dir, + mock.sentinel.operation_timeout) + + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "rocky", + "VERSION_ID": "8.4", + "NAME": "Rocky Linux", + } expected_info = { - "os_type": rocky.constants.OS_TYPE_LINUX, + "os_type": constants.OS_TYPE_LINUX, "distribution_name": rocky.ROCKY_LINUX_DISTRO_IDENTIFIER, "release_version": '8.4', "friendly_release_name": "Rocky Linux Version 8.4" } - rocky_os_detect_tools = rocky.RockyLinuxOSDetectTools( - mock.sentinel.conn, mock.sentinel.os_root_dir, - mock.sentinel.operation_timeout) - - result = rocky_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + result = self.rocky_os_detect_tools.detect_os() + mock_get_os_release.assert_called_once_with() self.assertEqual(result, expected_info) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os_rocky_10(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = ( - b"Rocky Linux release 10.1 (Red Quartz)") + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_rocky_10(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "rocky", + "VERSION_ID": "10.1", + "NAME": "Rocky Linux", + "PRETTY_NAME": "Rocky Linux 10.1 (Red Quartz)", + } expected_info = { - "os_type": rocky.constants.OS_TYPE_LINUX, + "os_type": constants.OS_TYPE_LINUX, "distribution_name": rocky.ROCKY_LINUX_DISTRO_IDENTIFIER, "release_version": '10.1', "friendly_release_name": "Rocky Linux Version 10.1" } - rocky_os_detect_tools = rocky.RockyLinuxOSDetectTools( - mock.sentinel.conn, mock.sentinel.os_root_dir, - mock.sentinel.operation_timeout) - - result = rocky_os_detect_tools.detect_os() + result = self.rocky_os_detect_tools.detect_os() self.assertEqual(result, expected_info) - @mock.patch.object(base.BaseLinuxOSDetectTools, '_test_path') - @mock.patch.object(base.BaseLinuxOSDetectTools, '_read_file') - def test_detect_os_no_rocky(self, mock_read_file, mock_test_path): - mock_test_path.return_value = True - mock_read_file.return_value = b"CentOS Linux release 8.4" - - with self.assertLogs('coriolis.osmorphing.osdetect.rocky', - level="DEBUG"): - rocky_os_detect_tools = rocky.RockyLinuxOSDetectTools( - mock.sentinel.conn, mock.sentinel.os_root_dir, - mock.sentinel.operation_timeout) - result = rocky_os_detect_tools.detect_os() + @mock.patch.object(base.BaseLinuxOSDetectTools, '_get_os_release') + def test_detect_os_no_rocky(self, mock_get_os_release): + mock_get_os_release.return_value = { + "ID": "centos", + "VERSION_ID": "8.4", + "NAME": "CentOS Linux", + } - self.assertEqual(result, {}) + result = self.rocky_os_detect_tools.detect_os() - mock_test_path.assert_called_once_with("etc/redhat-release") - mock_read_file.assert_called_once_with("etc/redhat-release") + self.assertEqual(result, {}) + mock_get_os_release.assert_called_once_with()