From 477e6d9b701a63d10d5cf25621d4cffdc0c6ded6 Mon Sep 17 00:00:00 2001 From: Nanook Date: Tue, 5 May 2026 01:43:06 +0000 Subject: [PATCH] fix(analyze): return integer exit code from analyze_boot analyze_boot returned a string status_code ("successful", "failure", "container") which sys.exit() interpreted as exit code 1, printing the string to stderr. This caused -- Most Recent Boot Record -- Kernel Started at: 2026-04-16 04:48:35.716519+00:00 Kernel ended boot at: 2026-04-16 04:48:38.956376+00:00 Kernel time to boot (seconds): 3.2398569583892822 Cloud-init activated by systemd at: 2026-04-16 04:48:35.716519+00:00 Time between Kernel end boot and Cloud-init activation (seconds): -3.2398569583892822 Cloud-init start: 2024-11-20 00:52:10.535000+00:00 to always exit with return code 1, even on successful analysis. Return 0 for success/container and 1 for failure instead. --- cloudinit/analyze/__init__.py | 4 ++-- tests/unittests/analyze/test_boot.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cloudinit/analyze/__init__.py b/cloudinit/analyze/__init__.py index ea2144cb387..ae978ba7a01 100644 --- a/cloudinit/analyze/__init__.py +++ b/cloudinit/analyze/__init__.py @@ -115,7 +115,7 @@ def get_parser( return parser -def analyze_boot(name: str, args: argparse.Namespace) -> str: +def analyze_boot(name: str, args: argparse.Namespace) -> int: """Report a list of how long different boot operations took. For Example: @@ -199,7 +199,7 @@ def analyze_boot(name: str, args: argparse.Namespace) -> str: outfh.write(status_map[status_code].format(**kwargs)) clean_io(infh, outfh) - return status_code + return 1 if status_code == show.FAIL_CODE else 0 def analyze_blame(name, args: argparse.Namespace) -> None: diff --git a/tests/unittests/analyze/test_boot.py b/tests/unittests/analyze/test_boot.py index 6487790ddc6..9e89ef8867e 100644 --- a/tests/unittests/analyze/test_boot.py +++ b/tests/unittests/analyze/test_boot.py @@ -160,7 +160,7 @@ def test_container_no_ci_log_line(self, m_is_container, m_subp): finish_code = analyze_boot(name_default, args) self.remove_dummy_file(path, log_path) - assert FAIL_CODE == finish_code + assert 1 == finish_code @mock.patch("cloudinit.util.is_container", return_value=True) @mock.patch("cloudinit.subp.subp", return_value=("U=1000000", None)) @@ -190,7 +190,7 @@ def test_container_ci_log_line(self, m_is_container, m_subp, m_get, m_g): finish_code = analyze_boot(name_default, args) self.remove_dummy_file(path, log_path) - assert CONTAINER_CODE == finish_code + assert 0 == finish_code @mock.patch("cloudinit.analyze.show.SystemctlReader") @pytest.mark.parametrize(