From 3e6a6741aeaa42783d41339128de64f62cd74232 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Mon, 1 Jun 2026 08:15:39 -0600 Subject: [PATCH 1/3] test: prefer reading journalctl transport=syslog over /var/log/syslog Recent versions of journalctl and rsyslog avoid mirroring /dev/console messages to /var/log/syslog. Prefer to ask journalctl directly about _TRANSPORT=syslog type messages to track what cloud-init writes to console as this approach works in both legacy and current rsyslog/journald behavior. --- tests/integration_tests/util.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/integration_tests/util.py b/tests/integration_tests/util.py index 6e86b677552..ff3e1f36128 100644 --- a/tests/integration_tests/util.py +++ b/tests/integration_tests/util.py @@ -584,6 +584,13 @@ def get_syslog_or_console(client: "IntegrationInstance") -> str: if OS_IMAGE_TYPE == "minimal" and HAS_CONSOLE_LOG: return get_console_log(client) else: + # Prefer syslog transport categorized messages over presence of + # /var/log/syslog as recent versions of rsyslog will avoid mirroring + # /dev/console to syslog. + if client.execute(["which", "journalctl"]).ok: + return client.execute( + ["journalctl", "_TRANSPORT=syslog", "-b", "0"] + ) return client.read_from_file("/var/log/syslog") From 2f254b06fbb98a7a76933c66ed8156ac82f40c7d Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Mon, 1 Jun 2026 12:54:40 -0600 Subject: [PATCH 2/3] tests: simplify get_syslog_or_console to get_journal_syslog for systemd-v255 --- .../modules/test_keys_to_console.py | 20 ++++++-------- .../modules/test_ssh_auth_key_fingerprints.py | 4 +-- tests/integration_tests/util.py | 26 +++++++------------ 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/tests/integration_tests/modules/test_keys_to_console.py b/tests/integration_tests/modules/test_keys_to_console.py index b8e74f57ba8..f20578ffd44 100644 --- a/tests/integration_tests/modules/test_keys_to_console.py +++ b/tests/integration_tests/modules/test_keys_to_console.py @@ -12,7 +12,7 @@ from tests.integration_tests.util import ( HAS_CONSOLE_LOG, get_console_log, - get_syslog_or_console, + get_journal_syslog, ) BLACKLIST_USER_DATA = """\ @@ -52,16 +52,14 @@ class TestKeysToConsoleBlacklist: @pytest.mark.parametrize("key_type", ["ECDSA"]) def test_excluded_keys(self, class_client, key_type): - assert "({})".format(key_type) not in get_syslog_or_console( - class_client - ) + assert "({})".format(key_type) not in get_journal_syslog(class_client) # retry decorator here because it can take some time to be reflected # in syslog @retry(tries=60, delay=1) @pytest.mark.parametrize("key_type", ["ED25519", "RSA"]) def test_included_keys(self, class_client, key_type): - assert "({})".format(key_type) in get_syslog_or_console(class_client) + assert "({})".format(key_type) in get_journal_syslog(class_client) @pytest.mark.user_data(BLACKLIST_ALL_KEYS_USER_DATA) @@ -75,12 +73,12 @@ class TestAllKeysToConsoleBlacklist: """ def test_header_excluded(self, class_client): - assert "BEGIN SSH HOST KEY FINGERPRINTS" not in get_syslog_or_console( + assert "BEGIN SSH HOST KEY FINGERPRINTS" not in get_journal_syslog( class_client ) def test_footer_excluded(self, class_client): - assert "END SSH HOST KEY FINGERPRINTS" not in get_syslog_or_console( + assert "END SSH HOST KEY FINGERPRINTS" not in get_journal_syslog( class_client ) @@ -95,17 +93,15 @@ class TestKeysToConsoleDisabled: @pytest.mark.parametrize("key_type", ["ECDSA", "ED25519", "RSA"]) def test_keys_excluded(self, class_client, key_type): - assert "({})".format(key_type) not in get_syslog_or_console( - class_client - ) + assert "({})".format(key_type) not in get_journal_syslog(class_client) def test_header_excluded(self, class_client): - assert "BEGIN SSH HOST KEY FINGERPRINTS" not in get_syslog_or_console( + assert "BEGIN SSH HOST KEY FINGERPRINTS" not in get_journal_syslog( class_client ) def test_footer_excluded(self, class_client): - assert "END SSH HOST KEY FINGERPRINTS" not in get_syslog_or_console( + assert "END SSH HOST KEY FINGERPRINTS" not in get_journal_syslog( class_client ) diff --git a/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py b/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py index d55cba91e70..c43fb13ade5 100644 --- a/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py +++ b/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py @@ -19,7 +19,7 @@ OS_IMAGE_TYPE, PLATFORM, ) -from tests.integration_tests.util import HAS_CONSOLE_LOG, get_syslog_or_console +from tests.integration_tests.util import HAS_CONSOLE_LOG, get_journal_syslog USER_DATA_SSH_AUTHKEY_DISABLE = """\ #cloud-config @@ -55,7 +55,7 @@ def test_ssh_authkey_fingerprints_disable(self, client): reason=f"No console_log available for minimal images on {PLATFORM}", ) def test_ssh_authkey_fingerprints_enable(self, client): - syslog_output = get_syslog_or_console(client) + syslog_output = get_journal_syslog(client) assert re.search(r"256 SHA256:.*(ECDSA)", syslog_output) is not None assert re.search(r"256 SHA256:.*(ED25519)", syslog_output) is not None assert re.search(r"2048 SHA256:.*(RSA)", syslog_output) is None diff --git a/tests/integration_tests/util.py b/tests/integration_tests/util.py index ff3e1f36128..b7a41001c9b 100644 --- a/tests/integration_tests/util.py +++ b/tests/integration_tests/util.py @@ -16,10 +16,7 @@ from cloudinit.subp import subp from tests.integration_tests.decorators import retry -from tests.integration_tests.integration_settings import ( - OS_IMAGE_TYPE, - PLATFORM, -) +from tests.integration_tests.integration_settings import PLATFORM from tests.integration_tests.releases import CURRENT_RELEASE, NOBLE LOG = logging.getLogger("integration_testing.util") @@ -579,19 +576,14 @@ def get_console_log(client: "IntegrationInstance"): @retry(tries=5, delay=1) # Retry on get_console_log failures -def get_syslog_or_console(client: "IntegrationInstance") -> str: - """minimal OS_IMAGE_TYPE does not contain rsyslog""" - if OS_IMAGE_TYPE == "minimal" and HAS_CONSOLE_LOG: - return get_console_log(client) - else: - # Prefer syslog transport categorized messages over presence of - # /var/log/syslog as recent versions of rsyslog will avoid mirroring - # /dev/console to syslog. - if client.execute(["which", "journalctl"]).ok: - return client.execute( - ["journalctl", "_TRANSPORT=syslog", "-b", "0"] - ) - return client.read_from_file("/var/log/syslog") +def get_journal_syslog(client: "IntegrationInstance") -> str: + """Syslog events are categorized _TRANSPORT=syslog from systemd v205.""" + # Prefer syslog transport categorized messages over presence of + # /var/log/syslog as systemd v255 introduced systemd-executor + # which sandboxes unit processes resulting in direct writes to + # /dev/console being logged directly to journal binary instead + # of mirrored as rsyslog events. + return client.execute(["journalctl", "_TRANSPORT=syslog", "-b", "0"]) @lru_cache() From 63980161732cbcf0079be724169f3786b070f954 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Thu, 4 Jun 2026 17:18:58 +0000 Subject: [PATCH 3/3] ai: copilot review comment resolution --- tests/integration_tests/modules/test_keys_to_console.py | 2 +- .../modules/test_ssh_auth_key_fingerprints.py | 8 ++++---- tests/integration_tests/util.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/integration_tests/modules/test_keys_to_console.py b/tests/integration_tests/modules/test_keys_to_console.py index f20578ffd44..2f53fd7f4df 100644 --- a/tests/integration_tests/modules/test_keys_to_console.py +++ b/tests/integration_tests/modules/test_keys_to_console.py @@ -55,7 +55,7 @@ def test_excluded_keys(self, class_client, key_type): assert "({})".format(key_type) not in get_journal_syslog(class_client) # retry decorator here because it can take some time to be reflected - # in syslog + # in the journal @retry(tries=60, delay=1) @pytest.mark.parametrize("key_type", ["ED25519", "RSA"]) def test_included_keys(self, class_client, key_type): diff --git a/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py b/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py index c43fb13ade5..8cc68ae7880 100644 --- a/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py +++ b/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py @@ -55,10 +55,10 @@ def test_ssh_authkey_fingerprints_disable(self, client): reason=f"No console_log available for minimal images on {PLATFORM}", ) def test_ssh_authkey_fingerprints_enable(self, client): - syslog_output = get_journal_syslog(client) - assert re.search(r"256 SHA256:.*(ECDSA)", syslog_output) is not None - assert re.search(r"256 SHA256:.*(ED25519)", syslog_output) is not None - assert re.search(r"2048 SHA256:.*(RSA)", syslog_output) is None + log_output = get_journal_syslog(client) + assert re.search(r"256 SHA256:.*(ECDSA)", log_output) is not None + assert re.search(r"256 SHA256:.*(ED25519)", log_output) is not None + assert re.search(r"2048 SHA256:.*(RSA)", log_output) is None @pytest.mark.user_data( diff --git a/tests/integration_tests/util.py b/tests/integration_tests/util.py index b7a41001c9b..69b3778622f 100644 --- a/tests/integration_tests/util.py +++ b/tests/integration_tests/util.py @@ -575,7 +575,7 @@ def get_console_log(client: "IntegrationInstance"): return console_log -@retry(tries=5, delay=1) # Retry on get_console_log failures +@retry(tries=5, delay=1) # Retry on transient journalctl failures def get_journal_syslog(client: "IntegrationInstance") -> str: """Syslog events are categorized _TRANSPORT=syslog from systemd v205.""" # Prefer syslog transport categorized messages over presence of