276 lines
13 KiB
Diff
276 lines
13 KiB
Diff
|
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
|
||
|
|