From e48fe3aa5fd9c8ddb839b7ab60f533b4db037967 Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Mon, 13 Oct 2025 12:22:50 +0800 Subject: [PATCH] Set up crypttab for encrypted dump target Resolves: RHEL-11196 Signed-off-by: Coiby Xu --- 0005.patch | 84 ++++++++++++++++ 0006.patch | 202 ++++++++++++++++++++++++++++++++++++++ 0007.patch | 64 ++++++++++++ kdump-anaconda-addon.spec | 8 +- 4 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 0005.patch create mode 100644 0006.patch create mode 100644 0007.patch diff --git a/0005.patch b/0005.patch new file mode 100644 index 0000000..94f13ae --- /dev/null +++ b/0005.patch @@ -0,0 +1,84 @@ +From: Coiby Xu + +Subject: Check /usr/bin/systemctl instead of /systemctl + +Relates: https://issues.redhat.com/browse/RHEL-29039 +Conflict: None + +commit 067afd2904bb77d3f87b241506216eae98e111c0 +Author: Coiby Xu +Date: Wed Aug 13 12:06:33 2025 +0800 + + Check /usr/bin/systemctl instead of /systemctl + + The early patch checks sysroot/systemctl by mistake. Fix it. + + Fixes: 25c549c ("Handle the case where systemd isn't installed") + Signed-off-by: Coiby Xu + +Signed-off-by: Coiby Xu + +diff --git a/com_redhat_kdump/service/installation.py b/com_redhat_kdump/service/installation.py +index 1e0096aa5edb6c054228ff9eec9cc528731c7ed3..aae58c173cc4e879a2ff772417eb17fd8ca29864 100644 +--- a/com_redhat_kdump/service/installation.py ++++ b/com_redhat_kdump/service/installation.py +@@ -17,7 +17,6 @@ + # + import logging + import os +-import shutil + + from pyanaconda.core import util + from pyanaconda.modules.common.constants.objects import BOOTLOADER +@@ -143,7 +142,7 @@ class KdumpInstallationTask(Task): + # Anaconda may be used to create minimal container image which doesn't + # have systemd installed + # https://issues.redhat.com/browse/RHEL-41082?focusedId=26969576&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-26969576 +- if not shutil.which(self._sysroot + "/systemctl"): ++ if not os.path.exists(self._sysroot + "/usr/bin/systemctl"): + log.debug("systemd not installed, skip KdumpInstallationTask") + return + +diff --git a/test/unit_tests/test_installation.py b/test/unit_tests/test_installation.py +index 43f51669303c147d6528728f26a4d8ffca2a103a..e0d4109ad2fd9996c62a7c746e558fc09f1f5315 100644 +--- a/test/unit_tests/test_installation.py ++++ b/test/unit_tests/test_installation.py +@@ -181,9 +181,9 @@ class KdumpInstallationTestCase(TestCase): + assert mock_exec.call_count == 2 + + @patch("com_redhat_kdump.service.installation.util") +- @patch("shutil.which") +- def test_installation_kdump_disabled(self, mock_shutil, mock_util): +- mock_shutil.return_value = True ++ @patch("os.path.exists") ++ def test_installation_kdump_disabled(self, mock_os_path, mock_util): ++ mock_os_path.return_value = True + task = KdumpInstallationTask( + sysroot="/mnt/sysroot", + kdump_enabled=False +@@ -196,9 +196,9 @@ class KdumpInstallationTestCase(TestCase): + ) + + @patch("com_redhat_kdump.service.installation.util") +- @patch("shutil.which") +- def test_installation_kdump_enabled(self, mock_shutil, mock_util): +- mock_shutil.return_value = True ++ @patch("os.path.exists") ++ def test_installation_kdump_enabled(self, mock_os_path, mock_util): ++ mock_os_path.return_value = True + task = KdumpInstallationTask( + sysroot="/mnt/sysroot", + kdump_enabled=True +@@ -211,9 +211,9 @@ class KdumpInstallationTestCase(TestCase): + ) + + @patch("com_redhat_kdump.service.installation.util") +- @patch("shutil.which") +- def test_installation_kdump_disable_no_systemctl(self, mock_shutil, mock_util): +- mock_shutil.return_value = False ++ @patch("os.path.exists") ++ def test_installation_kdump_disable_no_systemctl(self, mock_os_path, mock_util): ++ mock_os_path.return_value = False + task = KdumpInstallationTask( + sysroot="/mnt/sysroot", + kdump_enabled=False diff --git a/0006.patch b/0006.patch new file mode 100644 index 0000000..c5984e5 --- /dev/null +++ b/0006.patch @@ -0,0 +1,202 @@ +From: Coiby Xu + +Subject: Call kdumpctl setup-crypttab so kdump will work on boot for encrypted dump target + +Resolves: https://issues.redhat.com/browse/RHEL-29039 +Conflict: None + +commit 181815c59574005582e4ff769e50638f4a0e0214 +Author: Coiby Xu +Date: Wed Sep 17 14:59:29 2025 +0800 + + Call kdumpctl setup-crypttab so kdump will work on boot for encrypted dump target + + Resolves: https://issues.redhat.com/browse/RHEL-29039 + + Call "kdumpctl setup-crypttab" to set up /etc/crypttab so the volume + keys can be passed to the crash kernel. + + Note Anaconda writes to /etc/crypttab at "Early storage configuration" + phase. So we set up /etc/crypttab at "Anaconda addon configuration" + phase which happens before Anaconda generates initramfs. So the updated + crypttab will be built into the initramfs. + + 01:52:19,877 INF installation: Queue started: Early storage configuration (3/18) + ... + ... + 01:56:17,041 INF installation: Queue started: Anaconda addon configuration (15/18) + 01:56:17,044 INF installation: Queue started: Initramfs generation (16/18) + + One benefit of setting up crypttab via kdump is "kdumpctl setup-crypttab" will + continue only the dumping target is truly encrypted and the logic to + detect encrypted dumping target is already there. + + After all architectures supports encrypted dump target, the current + implementing of detecting if any volume has been encrypted which may not + necessary be a dump target can be dropped. + + Assisted-by: Claude Code + Signed-off-by: Coiby Xu + +Signed-off-by: Coiby Xu + +diff --git a/com_redhat_kdump/service/installation.py b/com_redhat_kdump/service/installation.py +index aae58c173cc4e879a2ff772417eb17fd8ca29864..9f65a81e50037212559553882de425c91f5fb6f8 100644 +--- a/com_redhat_kdump/service/installation.py ++++ b/com_redhat_kdump/service/installation.py +@@ -29,7 +29,7 @@ from com_redhat_kdump.common import getLuksDevices + + log = logging.getLogger(__name__) + +-__all__ = ["KdumpBootloaderConfigurationTask", "KdumpInstallationTask"] ++__all__ = ["KdumpBootloaderConfigurationTask", "KdumpInstallationTask", "KdumpCrypttabSetupTask"] + + + class KdumpBootloaderConfigurationTask(Task): +@@ -156,3 +156,40 @@ class KdumpInstallationTask(Task): + [systemctl_action, "kdump.service"], + root=self._sysroot + ) ++ ++ ++class KdumpCrypttabSetupTask(Task): ++ """The task for setting up crypttab for kdump.""" ++ ++ def __init__(self, sysroot): ++ """Create a task.""" ++ super().__init__() ++ self._sysroot = sysroot ++ ++ @property ++ def name(self): ++ return "Setup crypttab for kdump" ++ ++ def _has_setup_crypttab_command(self): ++ """Check if kdumpctl has setup-crypttab subcommand by checking help output.""" ++ try: ++ help_output = util.execWithCapture("kdumpctl", ["help"], root=self._sysroot) ++ return "setup-crypttab" in help_output ++ except FileNotFoundError: ++ log.debug("kdumpctl command not found") ++ return False ++ except Exception as e: ++ log.warning("Failed to check kdumpctl help: %s", e) ++ return False ++ ++ def run(self): ++ """Run the task.""" ++ if not self._has_setup_crypttab_command(): ++ log.debug("kdumpctl setup-crypttab command not available, skipping") ++ return ++ ++ try: ++ util.execWithRedirect("kdumpctl", ["setup-crypttab"], root=self._sysroot) ++ log.debug("Successfully executed kdumpctl setup-crypttab") ++ except Exception as e: ++ log.warning("Failed to execute kdumpctl setup-crypttab: %s", e) +diff --git a/com_redhat_kdump/service/kdump.py b/com_redhat_kdump/service/kdump.py +index 8356d193e58000b35cb807e75862f34f1d845ffb..cecbfc3ec6ae34ab9602809091398b3f64917589 100755 +--- a/com_redhat_kdump/service/kdump.py ++++ b/com_redhat_kdump/service/kdump.py +@@ -26,7 +26,7 @@ from pyanaconda.modules.common.structures.requirement import Requirement + + from com_redhat_kdump.common import getMemoryBounds + from com_redhat_kdump.constants import KDUMP +-from com_redhat_kdump.service.installation import KdumpBootloaderConfigurationTask, KdumpInstallationTask ++from com_redhat_kdump.service.installation import KdumpBootloaderConfigurationTask, KdumpInstallationTask, KdumpCrypttabSetupTask + from com_redhat_kdump.service.kdump_interface import KdumpInterface + from com_redhat_kdump.service.kickstart import KdumpKickstartSpecification + +@@ -137,13 +137,22 @@ class KdumpService(KickstartService): + + :return: a list of tasks + """ +- return [ ++ tasks = [ + KdumpInstallationTask( + sysroot=conf.target.system_root, + kdump_enabled=self.kdump_enabled, + ) + ] + ++ if self.kdump_enabled: ++ tasks.append( ++ KdumpCrypttabSetupTask( ++ sysroot=conf.target.system_root ++ ) ++ ) ++ ++ return tasks ++ + def configure_bootloader_with_tasks(self, kernels): + return [ + KdumpBootloaderConfigurationTask( +diff --git a/test/unit_tests/test_installation.py b/test/unit_tests/test_installation.py +index e0d4109ad2fd9996c62a7c746e558fc09f1f5315..8bff6059db4a5ba926cbd70f8df852ec854aaf34 100644 +--- a/test/unit_tests/test_installation.py ++++ b/test/unit_tests/test_installation.py +@@ -1,7 +1,7 @@ + from unittest.case import TestCase + from unittest.mock import patch + from com_redhat_kdump.constants import FADUMP_CAPABLE_FILE +-from com_redhat_kdump.service.installation import KdumpBootloaderConfigurationTask, KdumpInstallationTask ++from com_redhat_kdump.service.installation import KdumpBootloaderConfigurationTask, KdumpInstallationTask, KdumpCrypttabSetupTask + + SYSROOT = "/sysroot" + +@@ -220,3 +220,55 @@ class KdumpInstallationTestCase(TestCase): + ) + task.run() + mock_util.execWithRedirect.assert_not_called() ++ ++ @patch("pyanaconda.core.util.execWithCapture") ++ def test_crypttab_setup_check_help_with_setup_crypttab(self, mock_exec): ++ mock_exec.return_value = "setup-crypttab Setup crypttab for kdump" ++ task = KdumpCrypttabSetupTask(sysroot="/mnt/sysroot") ++ result = task._has_setup_crypttab_command() ++ mock_exec.assert_called_once_with("kdumpctl", ["help"], root="/mnt/sysroot") ++ assert result is True ++ ++ @patch("pyanaconda.core.util.execWithCapture") ++ def test_crypttab_setup_check_help_without_setup_crypttab(self, mock_exec): ++ mock_exec.return_value = "start Start kdump\nstop Stop kdump" ++ task = KdumpCrypttabSetupTask(sysroot="/mnt/sysroot") ++ result = task._has_setup_crypttab_command() ++ mock_exec.assert_called_once_with("kdumpctl", ["help"], root="/mnt/sysroot") ++ assert result is False ++ ++ @patch("pyanaconda.core.util.execWithCapture") ++ def test_crypttab_setup_check_help_kdumpctl_not_found(self, mock_exec): ++ mock_exec.side_effect = FileNotFoundError() ++ task = KdumpCrypttabSetupTask(sysroot="/mnt/sysroot") ++ result = task._has_setup_crypttab_command() ++ mock_exec.assert_called_once_with("kdumpctl", ["help"], root="/mnt/sysroot") ++ assert result is False ++ ++ @patch("pyanaconda.core.util.execWithRedirect") ++ @patch("com_redhat_kdump.service.installation.KdumpCrypttabSetupTask._has_setup_crypttab_command") ++ def test_crypttab_setup_run_with_command_available(self, mock_has_command, mock_exec): ++ mock_has_command.return_value = True ++ task = KdumpCrypttabSetupTask(sysroot="/mnt/sysroot") ++ task.run() ++ mock_has_command.assert_called_once() ++ mock_exec.assert_called_once_with("kdumpctl", ["setup-crypttab"], root="/mnt/sysroot") ++ ++ @patch("pyanaconda.core.util.execWithRedirect") ++ @patch("com_redhat_kdump.service.installation.KdumpCrypttabSetupTask._has_setup_crypttab_command") ++ def test_crypttab_setup_run_without_command_available(self, mock_has_command, mock_exec): ++ mock_has_command.return_value = False ++ task = KdumpCrypttabSetupTask(sysroot="/mnt/sysroot") ++ task.run() ++ mock_has_command.assert_called_once() ++ mock_exec.assert_not_called() ++ ++ @patch("pyanaconda.core.util.execWithRedirect") ++ @patch("com_redhat_kdump.service.installation.KdumpCrypttabSetupTask._has_setup_crypttab_command") ++ def test_crypttab_setup_run_execution_failure(self, mock_has_command, mock_exec): ++ mock_has_command.return_value = True ++ mock_exec.side_effect = Exception("Command failed") ++ task = KdumpCrypttabSetupTask(sysroot="/mnt/sysroot") ++ task.run() ++ mock_has_command.assert_called_once() ++ mock_exec.assert_called_once_with("kdumpctl", ["setup-crypttab"], root="/mnt/sysroot") diff --git a/0007.patch b/0007.patch new file mode 100644 index 0000000..b116630 --- /dev/null +++ b/0007.patch @@ -0,0 +1,64 @@ +From: Coiby Xu + +Subject: Don't emit ENCRYPTION_WARNING for x86_64 + +Resolves: https://issues.redhat.com/browse/RHEL-29039 +Conflict: None + +commit a6c2cf4313e937e1ff43d6907c9df445f982e0ef +Author: Coiby Xu +Date: Wed Sep 17 09:43:55 2025 +0800 + + Don't emit ENCRYPTION_WARNING for x86_64 + + Resolves: https://issues.redhat.com/browse/RHEL-29039 + + x86_64 now supports encrypted dump target. There is no need for this + warning. + + Signed-off-by: Coiby Xu + +Signed-off-by: Coiby Xu + +diff --git a/com_redhat_kdump/gui/spokes/kdump.py b/com_redhat_kdump/gui/spokes/kdump.py +index c313f43479142d23c94e74bc329d8f3af70dc0c4..1339cff1713a23136ec8382dd702309ba6af55b0 100644 +--- a/com_redhat_kdump/gui/spokes/kdump.py ++++ b/com_redhat_kdump/gui/spokes/kdump.py +@@ -31,6 +31,7 @@ from pyanaconda.ui.categories.system import SystemCategory + from pyanaconda.ui.gui.spokes import NormalSpoke + from pyanaconda.ui.gui.utils import fancy_set_sensitive + from pyanaconda.ui.communication import hubQ ++import blivet.arch + + from com_redhat_kdump.i18n import _, N_ + from com_redhat_kdump.constants import FADUMP_CAPABLE_FILE, KDUMP, ENCRYPTION_WARNING +@@ -135,7 +136,7 @@ class KdumpSpoke(NormalSpoke): + self._enableButton.emit("toggled") + + self.clear_info() +- if self._luks_devs: ++ if self._luks_devs and blivet.arch.get_arch() != "x86_64": + self.set_warning(_(ENCRYPTION_WARNING)) + + def apply(self): +diff --git a/com_redhat_kdump/service/kdump.py b/com_redhat_kdump/service/kdump.py +index cecbfc3ec6ae34ab9602809091398b3f64917589..33d329089fb4e6ea76947f90815bd01ea25c8980 100755 +--- a/com_redhat_kdump/service/kdump.py ++++ b/com_redhat_kdump/service/kdump.py +@@ -29,6 +29,7 @@ from com_redhat_kdump.constants import KDUMP + from com_redhat_kdump.service.installation import KdumpBootloaderConfigurationTask, KdumpInstallationTask, KdumpCrypttabSetupTask + from com_redhat_kdump.service.kdump_interface import KdumpInterface + from com_redhat_kdump.service.kickstart import KdumpKickstartSpecification ++import blivet.arch + + log = logging.getLogger(__name__) + +@@ -144,7 +145,7 @@ class KdumpService(KickstartService): + ) + ] + +- if self.kdump_enabled: ++ if self.kdump_enabled and blivet.arch.get_arch() == "x86_64": + tasks.append( + KdumpCrypttabSetupTask( + sysroot=conf.target.system_root diff --git a/kdump-anaconda-addon.spec b/kdump-anaconda-addon.spec index 9dadc56..dd3088a 100644 --- a/kdump-anaconda-addon.spec +++ b/kdump-anaconda-addon.spec @@ -4,7 +4,7 @@ Name: kdump-anaconda-addon Version: 006 -Release: 15.%{snapshotdate}git%{gitshortcommit}%{?dist} +Release: 16.%{snapshotdate}git%{gitshortcommit}%{?dist} Url: https://github.com/daveyoung/kdump-anaconda-addon License: GPLv2 Summary: Kdump configuration anaconda addon @@ -23,6 +23,9 @@ Patch1: 0001.patch Patch2: 0002.patch Patch3: 0003.patch Patch4: 0004.patch +Patch5: 0005.patch +Patch6: 0006.patch +Patch7: 0007.patch %description Kdump anaconda addon @@ -46,6 +49,9 @@ Kdump anaconda addon %{_datadir}/icons/hicolor/scalable/apps/kdump.svg %changelog +* Mon Oct 13 2025 Coiby Xu - 006-16.20220128git9603258 +- Feature: Set up crypttab + * Tue Apr 29 2025 Coiby Xu - 006-15.20220128git9603258 - Handle the case where systemd isn't installed (RHEL-86873)