leapp-repository/0036-Copy-dnf.conf-to-target-userspace-and-allow-a-custom.patch

276 lines
13 KiB
Diff
Raw Normal View History

From 5bd7bdf5e9c81ec306e567a147dc270adfd27da2 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Tue, 14 Nov 2023 09:51:41 +0100
Subject: [PATCH 36/38] Copy dnf.conf to target userspace and allow a custom
one
This change allows working around the fact that source and target
`dnf.conf` files might be incompatible. For example some of the proxy
configuration between RHEL7 and RHEL8.
Target system compatible configuration can be specified in
/etc/leapp/files/dnf.conf. If this file is present it is copied into
the target userspace and also applied to the target system. If it
doesn't exist, the `/etc/dnf/dnf.conf` from the source system will be
copied instead.
Errors that could be caused by incompatible/incorrect proxy
configuration now contain a hint with a remediation with the steps above
mentioned.
* pstodulk@redhat.com: Updated text in the error msg.
Jira: OAMG-6544
---
.../common/actors/applycustomdnfconf/actor.py | 19 ++++++++++++++
.../libraries/applycustomdnfconf.py | 15 +++++++++++
.../tests/test_applycustomdnfconf.py | 23 ++++++++++++++++
.../copydnfconfintotargetuserspace/actor.py | 24 +++++++++++++++++
.../copydnfconfintotargetuserspace.py | 19 ++++++++++++++
.../tests/test_dnfconfuserspacecopy.py | 26 +++++++++++++++++++
.../libraries/userspacegen.py | 18 ++++++++++---
.../common/libraries/dnfplugin.py | 24 ++++++++++++++++-
8 files changed, 163 insertions(+), 5 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/applycustomdnfconf/actor.py
create mode 100644 repos/system_upgrade/common/actors/applycustomdnfconf/libraries/applycustomdnfconf.py
create mode 100644 repos/system_upgrade/common/actors/applycustomdnfconf/tests/test_applycustomdnfconf.py
create mode 100644 repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/actor.py
create mode 100644 repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/libraries/copydnfconfintotargetuserspace.py
create mode 100644 repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/tests/test_dnfconfuserspacecopy.py
diff --git a/repos/system_upgrade/common/actors/applycustomdnfconf/actor.py b/repos/system_upgrade/common/actors/applycustomdnfconf/actor.py
new file mode 100644
index 00000000..d7c7fe87
--- /dev/null
+++ b/repos/system_upgrade/common/actors/applycustomdnfconf/actor.py
@@ -0,0 +1,19 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import applycustomdnfconf
+from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag
+
+
+class ApplyCustomDNFConf(Actor):
+ """
+ Move /etc/leapp/files/dnf.conf to /etc/dnf/dnf.conf if it exists
+
+ An actor in FactsPhase copies this file to the target userspace if present.
+ In such case we also want to use the file on the target system.
+ """
+ name = "apply_custom_dnf_conf"
+ consumes = ()
+ produces = ()
+ tags = (ApplicationsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ applycustomdnfconf.process()
diff --git a/repos/system_upgrade/common/actors/applycustomdnfconf/libraries/applycustomdnfconf.py b/repos/system_upgrade/common/actors/applycustomdnfconf/libraries/applycustomdnfconf.py
new file mode 100644
index 00000000..2eabd678
--- /dev/null
+++ b/repos/system_upgrade/common/actors/applycustomdnfconf/libraries/applycustomdnfconf.py
@@ -0,0 +1,15 @@
+import os
+
+from leapp.libraries.stdlib import api, CalledProcessError, run
+
+CUSTOM_DNF_CONF_PATH = "/etc/leapp/files/dnf.conf"
+
+
+def process():
+ if os.path.exists(CUSTOM_DNF_CONF_PATH):
+ try:
+ run(["mv", CUSTOM_DNF_CONF_PATH, "/etc/dnf/dnf.conf"])
+ except (CalledProcessError, OSError) as e:
+ api.current_logger().debug(
+ "Failed to move /etc/leapp/files/dnf.conf to /etc/dnf/dnf.conf: {}".format(e)
+ )
diff --git a/repos/system_upgrade/common/actors/applycustomdnfconf/tests/test_applycustomdnfconf.py b/repos/system_upgrade/common/actors/applycustomdnfconf/tests/test_applycustomdnfconf.py
new file mode 100644
index 00000000..6dbc4291
--- /dev/null
+++ b/repos/system_upgrade/common/actors/applycustomdnfconf/tests/test_applycustomdnfconf.py
@@ -0,0 +1,23 @@
+import os
+
+import pytest
+
+from leapp.libraries.actor import applycustomdnfconf
+
+
+@pytest.mark.parametrize(
+ "exists,should_move",
+ [(False, False), (True, True)],
+)
+def test_copy_correct_dnf_conf(monkeypatch, exists, should_move):
+ monkeypatch.setattr(os.path, "exists", lambda _: exists)
+
+ run_called = [False]
+
+ def mocked_run(_):
+ run_called[0] = True
+
+ monkeypatch.setattr(applycustomdnfconf, 'run', mocked_run)
+
+ applycustomdnfconf.process()
+ assert run_called[0] == should_move
diff --git a/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/actor.py b/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/actor.py
new file mode 100644
index 00000000..46ce1934
--- /dev/null
+++ b/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/actor.py
@@ -0,0 +1,24 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import copydnfconfintotargetuserspace
+from leapp.models import TargetUserSpacePreupgradeTasks
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
+
+
+class CopyDNFConfIntoTargetUserspace(Actor):
+ """
+ Copy dnf.conf into target userspace
+
+ Copies /etc/leapp/files/dnf.conf to target userspace. If it isn't available
+ /etc/dnf/dnf.conf is copied instead. This allows specifying a different
+ config for the target userspace, which might be required if the source
+ system configuration file isn't compatible with the target one. One such
+ example is incompatible proxy configuration between RHEL7 and RHEL8 DNF
+ versions.
+ """
+ name = "copy_dnf_conf_into_target_userspace"
+ consumes = ()
+ produces = (TargetUserSpacePreupgradeTasks,)
+ tags = (FactsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ copydnfconfintotargetuserspace.process()
diff --git a/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/libraries/copydnfconfintotargetuserspace.py b/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/libraries/copydnfconfintotargetuserspace.py
new file mode 100644
index 00000000..4e74acdb
--- /dev/null
+++ b/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/libraries/copydnfconfintotargetuserspace.py
@@ -0,0 +1,19 @@
+import os
+
+from leapp.libraries.stdlib import api
+from leapp.models import CopyFile, TargetUserSpacePreupgradeTasks
+
+
+def process():
+ src = "/etc/dnf/dnf.conf"
+ if os.path.exists("/etc/leapp/files/dnf.conf"):
+ src = "/etc/leapp/files/dnf.conf"
+
+ api.current_logger().debug(
+ "Copying dnf.conf at {} to the target userspace".format(src)
+ )
+ api.produce(
+ TargetUserSpacePreupgradeTasks(
+ copy_files=[CopyFile(src=src, dst="/etc/dnf/dnf.conf")]
+ )
+ )
diff --git a/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/tests/test_dnfconfuserspacecopy.py b/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/tests/test_dnfconfuserspacecopy.py
new file mode 100644
index 00000000..6c99925e
--- /dev/null
+++ b/repos/system_upgrade/common/actors/copydnfconfintotargetuserspace/tests/test_dnfconfuserspacecopy.py
@@ -0,0 +1,26 @@
+import os
+
+import pytest
+
+from leapp.libraries.actor import copydnfconfintotargetuserspace
+from leapp.libraries.common.testutils import logger_mocked, produce_mocked
+
+
+@pytest.mark.parametrize(
+ "userspace_conf_exists,expected",
+ [(False, "/etc/dnf/dnf.conf"), (True, "/etc/leapp/files/dnf.conf")],
+)
+def test_copy_correct_dnf_conf(monkeypatch, userspace_conf_exists, expected):
+ monkeypatch.setattr(os.path, "exists", lambda _: userspace_conf_exists)
+
+ mocked_produce = produce_mocked()
+ monkeypatch.setattr(copydnfconfintotargetuserspace.api, 'produce', mocked_produce)
+ monkeypatch.setattr(copydnfconfintotargetuserspace.api, 'current_logger', logger_mocked())
+
+ copydnfconfintotargetuserspace.process()
+
+ assert mocked_produce.called == 1
+ assert len(mocked_produce.model_instances) == 1
+ assert len(mocked_produce.model_instances[0].copy_files) == 1
+ assert mocked_produce.model_instances[0].copy_files[0].src == expected
+ assert mocked_produce.model_instances[0].copy_files[0].dst == "/etc/dnf/dnf.conf"
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 050ad7fe..e015a741 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -269,15 +269,25 @@ def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
# 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.")
+ details['details'] = (
+ "DNF failed to install userspace packages, likely due to the proxy "
+ "configuration detected in the YUM/DNF configuration file. "
+ "Make sure the proxy is properly configured in /etc/dnf/dnf.conf. "
+ "It's also possible the proxy settings in the DNF configuration file are "
+ "incompatible with the target system. A compatible configuration can be "
+ "placed in /etc/leapp/files/dnf.conf which, if present, will be used during "
+ "the upgrade instead of /etc/dnf/dnf.conf. "
+ "In such case the configuration will also be applied to the target system."
+ )
# 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.")
+ 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)
diff --git a/repos/system_upgrade/common/libraries/dnfplugin.py b/repos/system_upgrade/common/libraries/dnfplugin.py
index 26810e94..d3ec5901 100644
--- a/repos/system_upgrade/common/libraries/dnfplugin.py
+++ b/repos/system_upgrade/common/libraries/dnfplugin.py
@@ -178,8 +178,30 @@ def _handle_transaction_err_msg(stage, xfs_info, err, is_container=False):
return # not needed actually as the above function raises error, but for visibility
NO_SPACE_STR = 'more space needed on the'
message = 'DNF execution failed with non zero exit code.'
- details = {'STDOUT': err.stdout, 'STDERR': err.stderr}
if NO_SPACE_STR not in err.stderr:
+ # if there was a problem reaching repos and proxy is configured in DNF/YUM configs, the
+ # proxy is likely the problem.
+ # NOTE(mmatuska): We can't consistently detect there was a problem reaching some repos,
+ # because it isn't clear what are all the possible DNF error messages we can encounter,
+ # such as: "Failed to synchronize cache for repo ..." or "Errors during downloading
+ # metadata for # repository" or "No more mirrors to try - All mirrors were already tried
+ # without success"
+ # NOTE(mmatuska): We could check PkgManagerInfo to detect if proxy is indeed configured,
+ # however it would be pretty ugly to pass it all the way down here
+ proxy_hint = (
+ "If there was a problem reaching remote content (see stderr output) and proxy is "
+ "configured in the YUM/DNF configuration file, the proxy configuration is likely "
+ "causing this error. "
+ "Make sure the proxy is properly configured in /etc/dnf/dnf.conf. "
+ "It's also possible the proxy settings in the DNF configuration file are "
+ "incompatible with the target system. A compatible configuration can be "
+ "placed in /etc/leapp/files/dnf.conf which, if present, it will be used during "
+ "some parts of the upgrade instead of original /etc/dnf/dnf.conf. "
+ "In such case the configuration will also be applied to the target system. "
+ "Note that /etc/dnf/dnf.conf needs to be still configured correctly "
+ "for your current system to pass the early phases of the upgrade process."
+ )
+ details = {'STDOUT': err.stdout, 'STDERR': err.stderr, 'hint': proxy_hint}
raise StopActorExecutionError(message=message, details=details)
# Disk Requirements:
--
2.41.0