leapp-repository/SOURCES/0015-Scanpkgmanager-detect-...

258 lines
11 KiB
Diff

From 876e93f233c41aa6c1742ed874ac167f0ddc4dbb Mon Sep 17 00:00:00 2001
From: PeterMocary <petermocary@gmail.com>
Date: Fri, 24 Jun 2022 15:23:30 +0200
Subject: [PATCH 15/32] Scanpkgmanager: detect proxy configuration
This new information enables targetuserspacecreator actor to inform user why the package installation might have failed
---
.../libraries/scanpkgmanager.py | 53 ++++++++++++++++++-
.../tests/test_scanpkgmanager.py | 49 +++++++++++++++++
.../actors/targetuserspacecreator/actor.py | 4 ++
.../libraries/userspacegen.py | 24 +++++++--
.../common/models/packagemanagerinfo.py | 5 ++
.../common/models/repositoriesfacts.py | 1 +
6 files changed, 131 insertions(+), 5 deletions(-)
diff --git a/repos/system_upgrade/common/actors/scanpkgmanager/libraries/scanpkgmanager.py b/repos/system_upgrade/common/actors/scanpkgmanager/libraries/scanpkgmanager.py
index 6f6a79d2..7c97fb1a 100644
--- a/repos/system_upgrade/common/actors/scanpkgmanager/libraries/scanpkgmanager.py
+++ b/repos/system_upgrade/common/actors/scanpkgmanager/libraries/scanpkgmanager.py
@@ -1,9 +1,13 @@
import os
+import re
from leapp.libraries.common.config.version import get_source_major_version
from leapp.libraries.stdlib import api
from leapp.models import PkgManagerInfo
+YUM_CONFIG_PATH = '/etc/yum.conf'
+DNF_CONFIG_PATH = '/etc/dnf/dnf.conf'
+
def _get_releasever_path():
default_manager = 'yum' if get_source_major_version() == '7' else 'dnf'
@@ -28,5 +32,52 @@ def get_etc_releasever():
return releasever
+def _get_config_contents(config_path):
+ if os.path.isfile(config_path):
+ with open(config_path, 'r') as config:
+ return config.read()
+ return ''
+
+
+def _get_proxy_if_set(manager_config_path):
+ """
+ Get proxy address from specified package manager config.
+
+ :param manager_config_path: path to a package manager config
+ :returns: proxy address or None when not set
+ :rtype: String
+ """
+
+ config = _get_config_contents(manager_config_path)
+
+ for line in config.split('\n'):
+ if re.match('^proxy[ \t]*=', line):
+ proxy_address = line.split('=', 1)[1]
+ return proxy_address.strip()
+
+ return None
+
+
+def get_configured_proxies():
+ """
+ Get a list of proxies used in dnf and yum configuration files.
+
+ :returns: sorted list of unique proxies
+ :rtype: List
+ """
+
+ configured_proxies = set()
+ for config_path in (DNF_CONFIG_PATH, YUM_CONFIG_PATH):
+ proxy = _get_proxy_if_set(config_path)
+ if proxy:
+ configured_proxies.add(proxy)
+
+ return sorted(configured_proxies)
+
+
def process():
- api.produce(PkgManagerInfo(etc_releasever=get_etc_releasever()))
+ pkg_manager_info = PkgManagerInfo()
+ pkg_manager_info.etc_releasever = get_etc_releasever()
+ pkg_manager_info.configured_proxies = get_configured_proxies()
+
+ api.produce(pkg_manager_info)
diff --git a/repos/system_upgrade/common/actors/scanpkgmanager/tests/test_scanpkgmanager.py b/repos/system_upgrade/common/actors/scanpkgmanager/tests/test_scanpkgmanager.py
index 3be6fa2f..e78b532f 100644
--- a/repos/system_upgrade/common/actors/scanpkgmanager/tests/test_scanpkgmanager.py
+++ b/repos/system_upgrade/common/actors/scanpkgmanager/tests/test_scanpkgmanager.py
@@ -9,6 +9,9 @@ from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
from leapp.libraries.stdlib import api
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
+PROXY_ADDRESS = 'https://192.168.121.123:3128'
+YUM_CONFIG_PATH = '/etc/yum.conf'
+DNF_CONFIG_PATH = '/etc/dnf/dnf.conf'
def mock_releasever_exists(overrides):
@@ -36,6 +39,8 @@ def test_get_etcreleasever(monkeypatch, etcrelease_exists):
monkeypatch.setattr(scanpkgmanager.api, 'produce', produce_mocked())
monkeypatch.setattr(scanpkgmanager.api, 'current_actor', CurrentActorMocked())
monkeypatch.setattr(scanpkgmanager, '_get_releasever_path', mocked_get_releasever_path)
+ monkeypatch.setattr(scanpkgmanager, '_get_proxy_if_set', lambda x: None)
+ monkeypatch.setattr(pluginscanner, 'scan_enabled_package_manager_plugins', lambda: [])
scanpkgmanager.process()
@@ -44,3 +49,47 @@ def test_get_etcreleasever(monkeypatch, etcrelease_exists):
assert api.produce.model_instances[0].etc_releasever
else:
assert not api.produce.model_instances[0].etc_releasever
+
+
+@pytest.mark.parametrize('proxy_set', [True, False])
+def test_get_proxy_if_set(monkeypatch, proxy_set):
+
+ config_path = '/path/to/config.conf'
+ config_contents = '[main]\n'
+ if proxy_set:
+ config_contents += 'proxy = \t{} '.format(PROXY_ADDRESS)
+
+ def mocked_get_config_contents(path):
+ assert path == config_path
+ return config_contents
+
+ monkeypatch.setattr(scanpkgmanager, '_get_config_contents', mocked_get_config_contents)
+
+ proxy = scanpkgmanager._get_proxy_if_set(config_path)
+
+ if proxy_set:
+ assert proxy == PROXY_ADDRESS
+
+ assert proxy_set == bool(proxy)
+
+
+@pytest.mark.parametrize(
+ ('proxy_set_in_dnf_config', 'proxy_set_in_yum_config', 'expected_output'),
+ [
+ (True, True, [PROXY_ADDRESS]),
+ (True, False, [PROXY_ADDRESS]),
+ (False, False, [])
+ ]
+)
+def test_get_configured_proxies(monkeypatch, proxy_set_in_dnf_config, proxy_set_in_yum_config, expected_output):
+
+ def mocked_get_proxy_if_set(path):
+ proxy = PROXY_ADDRESS if proxy_set_in_yum_config else None
+ if path == DNF_CONFIG_PATH:
+ proxy = PROXY_ADDRESS if proxy_set_in_dnf_config else None
+ return proxy
+
+ monkeypatch.setattr(scanpkgmanager, '_get_proxy_if_set', mocked_get_proxy_if_set)
+
+ configured_proxies = scanpkgmanager.get_configured_proxies()
+ assert configured_proxies == expected_output
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/actor.py b/repos/system_upgrade/common/actors/targetuserspacecreator/actor.py
index 7e5c7db7..04fb2e8b 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/actor.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/actor.py
@@ -5,7 +5,9 @@ from leapp.models import RequiredTargetUserspacePackages # deprecated
from leapp.models import TMPTargetRepositoriesFacts # deprecated all the time
from leapp.models import (
CustomTargetRepositoryFile,
+ PkgManagerInfo,
Report,
+ RepositoriesFacts,
RepositoriesMapping,
RHSMInfo,
RHUIInfo,
@@ -36,12 +38,14 @@ class TargetUserspaceCreator(Actor):
CustomTargetRepositoryFile,
RHSMInfo,
RHUIInfo,
+ RepositoriesFacts,
RepositoriesMapping,
RequiredTargetUserspacePackages,
StorageInfo,
TargetRepositories,
TargetUserSpacePreupgradeTasks,
XFSPresence,
+ PkgManagerInfo,
)
produces = (TargetUserSpaceInfo, UsedTargetRepositories, Report, TMPTargetRepositoriesFacts,)
tags = (IPUWorkflowTag, TargetTransactionFactsPhaseTag)
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index c39af66f..00acacd9 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -12,6 +12,8 @@ from leapp.models import RequiredTargetUserspacePackages # deprecated
from leapp.models import TMPTargetRepositoriesFacts # deprecated
from leapp.models import (
CustomTargetRepositoryFile,
+ PkgManagerInfo,
+ RepositoriesFacts,
RHSMInfo,
RHUIInfo,
StorageInfo,
@@ -166,10 +168,24 @@ def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
try:
context.call(cmd, callback_raw=utils.logging_handler)
except CalledProcessError as exc:
- raise StopActorExecutionError(
- message='Unable to install RHEL {} userspace packages.'.format(target_major_version),
- details={'details': str(exc), 'stderr': exc.stderr}
- )
+ message = 'Unable to install RHEL {} userspace packages.'.format(target_major_version)
+ details = {'details': str(exc), 'stderr': exc.stderr}
+
+ # If a proxy was set in dnf config, it should be the reason why dnf
+ # failed since leapp does not support updates behind proxy yet.
+ for manager_info in api.consume(PkgManagerInfo):
+ if manager_info.configured_proxies:
+ details['details'] = ("DNF failed to install userspace packages, likely due to the proxy "
+ "configuration detected in the YUM/DNF configuration file.")
+
+ # Similarly if a proxy was set specifically for one of the repositories.
+ for repo_facts in api.consume(RepositoriesFacts):
+ for repo_file in repo_facts.repositories:
+ if any(repo_data.proxy and repo_data.enabled for repo_data in repo_file.data):
+ details['details'] = ("DNF failed to install userspace packages, likely due to the proxy "
+ "configuration detected in a repository configuration file.")
+
+ raise StopActorExecutionError(message=message, details=details)
def _get_all_rhui_pkgs():
diff --git a/repos/system_upgrade/common/models/packagemanagerinfo.py b/repos/system_upgrade/common/models/packagemanagerinfo.py
index ba6391c3..aa450978 100644
--- a/repos/system_upgrade/common/models/packagemanagerinfo.py
+++ b/repos/system_upgrade/common/models/packagemanagerinfo.py
@@ -17,3 +17,8 @@ class PkgManagerInfo(Model):
In case the value is empty string, it means the file exists but it is empty. In such a case the
original configuration is obviously broken.
"""
+
+ configured_proxies = fields.List(fields.String(), default=[])
+ """
+ A sorted list of proxies present in yum and dnf configuration files.
+ """
diff --git a/repos/system_upgrade/common/models/repositoriesfacts.py b/repos/system_upgrade/common/models/repositoriesfacts.py
index 722c579f..cd2124fc 100644
--- a/repos/system_upgrade/common/models/repositoriesfacts.py
+++ b/repos/system_upgrade/common/models/repositoriesfacts.py
@@ -13,6 +13,7 @@ class RepositoryData(Model):
mirrorlist = fields.Nullable(fields.String())
enabled = fields.Boolean(default=True)
additional_fields = fields.Nullable(fields.String())
+ proxy = fields.Nullable(fields.String())
class RepositoryFile(Model):
--
2.38.1