From a0dc3aacefd1b3f4abb1ccb61a4ac7fbe39fc3c7 Mon Sep 17 00:00:00 2001 From: Sonic Build Admin Date: Fri, 24 Oct 2025 20:30:08 +0000 Subject: [PATCH 1/3] [kdump-config] Update kdump default config with pre-defined value in /proc/cmdline (installer.conf) #### Why I did it Modify the hostcfgd to handle the kdump enabled to the CONFIG_DB when kdump is enabled by default in the platform installer.conf . Related PR for 202405 is: https://github.com/sonic-net/sonic-host-services/pull/236 ### How I did it Added a new method init_kdump_config_from_cmdline() in the KdumpCfg class to check the /proc/cmdline. If key "crashkernel=" exists in /proc/cmdline when system is up, this means that the kdump is enabled. init_kdump_config_from_cmdline() will update the kdump_defaults and CONFIG_DB when if the current config data are not matched the pre-defined data in the /proc/cmdline. This happens during a new image upgrade with the crashkernel is defined the platform installer.conf. ### How to verify it 1) install an image with predefine kdump enabled in the grub.conf. 2) execute the "config load_minigraph" - check it should not any error in the syslog - After the hostcfgd is running, execute "show kdump config" should show kdump is enabled. Output as below ``` admin@sonic:~$ show kdump config Kdump administrative mode: Enabled Kdump operational mode: Ready Kdump memory reservation: 8G-:1G Maximum number of Kdump files: 3 ``` 3) save config and reboot the system 4) show command should show the kdump is enabled and also there should not be any kdump/hostcfgd error log in syslog ### Which release branch to backport (provide reason below if selected) - [ ] 201811 - [ ] 201911 - [ ] 202006 - [ ] 202012 - [ ] 202106 - [ ] 202111 - [ ] 202205 - [ ] 202211 - [ ] 202305 - [x] 202405 --- scripts/hostcfgd | 38 +++++++++++++++++++++++++++++++++ tests/hostcfgd/hostcfgd_test.py | 28 ++++++++++++++++++++++++ tests/proc/cmdline | 1 + 3 files changed, 67 insertions(+) create mode 100644 tests/proc/cmdline diff --git a/scripts/hostcfgd b/scripts/hostcfgd index cedafcd9..ab017ee0 100644 --- a/scripts/hostcfgd +++ b/scripts/hostcfgd @@ -1137,6 +1137,40 @@ class KdumpCfg(object): "memory": "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M", "num_dumps": "3" } + # check if kdump is enabled by default with grub config + self.update_config_from_proc_cmdline = False + self.init_kdump_config_from_cmdline() + + def init_kdump_config_from_cmdline(self): + # Update the kdump_defaults with value found /proc/cmdline if + # key "crashkernel=" is pre-defined in and /proc/cmdline (grub.conf) + if os.environ.get("HOSTCFGD_UNIT_TESTING") == "2": + modules_path = os.path.join(os.path.dirname(__file__), "..") + tests_path = os.path.join(modules_path, "tests") + cmdline = os.path.join(tests_path, "proc","cmdline") + else: + cmdline = "/proc/cmdline" + + expected_str = ' crashkernel=' + if os.path.exists(cmdline): + lines= [line.rstrip('\n') for line in open(cmdline)] + p = lines[0].find(expected_str) + if p == -1: + return + kdump_config = self.config_db.get_entry("KDUMP", "config") + syslog.syslog(syslog.LOG_INFO, "kdump enabled is found in /proc/cmdline") + self.kdump_defaults["enabled"] = "true" + next_space = lines[0].find(" ", p+1) + if next_space == -1: + memory = lines[0][p+len(expected_str):] + else: + memory = lines[0][p+len(expected_str):next_space] + self.kdump_defaults["memory"] = memory + if not kdump_config or kdump_config.get("enabled") != self.kdump_defaults["enabled"] or kdump_config.get("memory") != self.kdump_defaults["memory"]: + self.update_config_from_proc_cmdline = True + syslog.syslog(syslog.LOG_INFO, "Update KDUMP config entry with data from /proc/cmdline") + self.config_db.mod_entry("KDUMP", "config", self.kdump_defaults) + def load(self, kdump_table): """ Set the KDUMP table in CFG DB to kdump_defaults if not set by the user @@ -1155,6 +1189,10 @@ class KdumpCfg(object): def kdump_update(self, key, data): syslog.syslog(syslog.LOG_INFO, "Kdump global configuration update") + if self.update_config_from_proc_cmdline and os.environ.get("HOSTCFGD_UNIT_TESTING") != "2": + self.update_config_from_proc_cmdline = False + syslog.syslog(syslog.LOG_INFO, "Kdump is enabled by default with /proc/cmdline. Skip the first update") + return if key == "config": # Admin mode kdump_enabled = self.kdump_defaults["enabled"] diff --git a/tests/hostcfgd/hostcfgd_test.py b/tests/hostcfgd/hostcfgd_test.py index 2c9c03da..e15b595b 100644 --- a/tests/hostcfgd/hostcfgd_test.py +++ b/tests/hostcfgd/hostcfgd_test.py @@ -236,6 +236,34 @@ def test_kdump_load(self): mocked_subprocess.check_call.assert_has_calls(expected, any_order=True) + def test_kdump_event_with_proc_cmdline(self): + os.environ["HOSTCFGD_UNIT_TESTING"] = "2" + MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB) + daemon = hostcfgd.HostConfigDaemon() + default=daemon.kdumpCfg.kdump_defaults + daemon.kdumpCfg.load(default) + daemon.register_callbacks() + MockConfigDb.event_queue = [('KDUMP', 'config')] + with mock.patch('hostcfgd.subprocess') as mocked_subprocess: + popen_mock = mock.Mock() + attrs = {'communicate.return_value': ('output', 'error')} + popen_mock.configure_mock(**attrs) + mocked_subprocess.Popen.return_value = popen_mock + try: + daemon.start() + except TimeoutError: + pass + expected = [ + call(['sonic-kdump-config', '--enable']), + call(['sonic-kdump-config', '--num_dumps', '3']), + call(['sonic-kdump-config', '--memory', '8G-:1G']), + call(['sonic-kdump-config', '--remote', 'false']), # Covering remote + call(['sonic-kdump-config', '--ssh_string', 'user@localhost']), # Covering ssh_string + call(['sonic-kdump-config', '--ssh_path', '/a/b/c']) # Covering ssh_path + ] + mocked_subprocess.check_call.assert_has_calls(expected, any_order=True) + os.environ["HOSTCFGD_UNIT_TESTING"] = "" + def test_devicemeta_event(self): """ Test handling DEVICE_METADATA events. diff --git a/tests/proc/cmdline b/tests/proc/cmdline new file mode 100644 index 00000000..ddfc9197 --- /dev/null +++ b/tests/proc/cmdline @@ -0,0 +1 @@ +BOOT_IMAGE=/image-202405.0-dirty-20250403.162657/boot/vmlinuz-6.1.0-22-2-amd64 root=UUID=bba2ec4f-9141-4069-a41e-230ecac4a5fb rw console=tty0 console=ttyS0,115200n8 quiet processor.max_cstate=1 amd_idle.max_cstate=0 sonic_fips=1 net.ifnames=0 biosdevname=0 loop=image-202405.0-dirty-20250403.162657/fs.squashfs loopfstype=squashfs systemd.unified_cgroup_hierarchy=0 apparmor=1 security=apparmor varlog_size=4096 usbcore.autosuspend=-1 amd_iommu=off pci=resource_alignment=48@00:03.1 crashkernel=8G-:1G \ No newline at end of file From 491762e1f5ba0360414760e018be31adae63fbc4 Mon Sep 17 00:00:00 2001 From: Tejaswini Chadaga Date: Mon, 27 Oct 2025 18:34:25 +0000 Subject: [PATCH 2/3] Remove unsupported options in the branch --- tests/hostcfgd/hostcfgd_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/hostcfgd/hostcfgd_test.py b/tests/hostcfgd/hostcfgd_test.py index e15b595b..4907ca59 100644 --- a/tests/hostcfgd/hostcfgd_test.py +++ b/tests/hostcfgd/hostcfgd_test.py @@ -257,9 +257,6 @@ def test_kdump_event_with_proc_cmdline(self): call(['sonic-kdump-config', '--enable']), call(['sonic-kdump-config', '--num_dumps', '3']), call(['sonic-kdump-config', '--memory', '8G-:1G']), - call(['sonic-kdump-config', '--remote', 'false']), # Covering remote - call(['sonic-kdump-config', '--ssh_string', 'user@localhost']), # Covering ssh_string - call(['sonic-kdump-config', '--ssh_path', '/a/b/c']) # Covering ssh_path ] mocked_subprocess.check_call.assert_has_calls(expected, any_order=True) os.environ["HOSTCFGD_UNIT_TESTING"] = "" From 51015b77fd8a2056714976b7925a38edf7a0fb03 Mon Sep 17 00:00:00 2001 From: Tejaswini Chadaga Date: Mon, 27 Oct 2025 18:36:14 +0000 Subject: [PATCH 3/3] Fix typo --- tests/hostcfgd/hostcfgd_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hostcfgd/hostcfgd_test.py b/tests/hostcfgd/hostcfgd_test.py index 4907ca59..dd23247d 100644 --- a/tests/hostcfgd/hostcfgd_test.py +++ b/tests/hostcfgd/hostcfgd_test.py @@ -256,7 +256,7 @@ def test_kdump_event_with_proc_cmdline(self): expected = [ call(['sonic-kdump-config', '--enable']), call(['sonic-kdump-config', '--num_dumps', '3']), - call(['sonic-kdump-config', '--memory', '8G-:1G']), + call(['sonic-kdump-config', '--memory', '8G-:1G']) ] mocked_subprocess.check_call.assert_has_calls(expected, any_order=True) os.environ["HOSTCFGD_UNIT_TESTING"] = ""