|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""Syslog Log RPC |
| 3 | +
|
| 4 | +Verify the infix-syslog:log RPC, used by the test system to inject |
| 5 | +markers in a DUT's system log. A message logged with the full RFC 5424 |
| 6 | +header must show up in an RFC 5424 formatted log file with the given |
| 7 | +app-name, msgid, and structured data. A message logged with only the |
| 8 | +mandatory text must fall back to the documented defaults. |
| 9 | +
|
| 10 | +""" |
| 11 | + |
| 12 | +import re |
| 13 | + |
| 14 | +import infamy |
| 15 | +from infamy.util import parallel, until |
| 16 | + |
| 17 | +LOG_FILE = "/var/log/rpc-log" |
| 18 | + |
| 19 | + |
| 20 | +def logfile(): |
| 21 | + """Return contents of the RFC 5424 test log file, or empty string""" |
| 22 | + rc = tgtssh.runsh(f"cat {LOG_FILE} 2>/dev/null") |
| 23 | + return rc.stdout if rc.returncode == 0 else "" |
| 24 | + |
| 25 | + |
| 26 | +with infamy.Test() as test: |
| 27 | + with test.step("Set up topology and attach to target DUT"): |
| 28 | + env = infamy.Env() |
| 29 | + target, tgtssh = parallel(lambda: env.attach("target", "mgmt"), |
| 30 | + lambda: env.attach("target", "mgmt", "ssh")) |
| 31 | + |
| 32 | + with test.step("Clean up old log file from previous test runs"): |
| 33 | + tgtssh.runsh(f"sudo rm -f {LOG_FILE}") |
| 34 | + |
| 35 | + with test.step("Configure an RFC 5424 formatted log file for all facilities"): |
| 36 | + target.put_config_dicts({ |
| 37 | + "ietf-syslog": { |
| 38 | + "syslog": { |
| 39 | + "actions": { |
| 40 | + "file": { |
| 41 | + "log-file": [{ |
| 42 | + "name": f"file:{LOG_FILE}", |
| 43 | + "infix-syslog:log-format": "rfc5424", |
| 44 | + "facility-filter": { |
| 45 | + "facility-list": [{ |
| 46 | + "facility": "all", |
| 47 | + "severity": "info" |
| 48 | + }] |
| 49 | + } |
| 50 | + }] |
| 51 | + } |
| 52 | + } |
| 53 | + } |
| 54 | + } |
| 55 | + }) |
| 56 | + until(lambda: tgtssh.runsh(f"test -f {LOG_FILE}").returncode == 0, attempts=10) |
| 57 | + |
| 58 | + with test.step("Log message with severity, facility, app-name, msgid, and structured data"): |
| 59 | + target.log("Kilroy was here", severity="warning", facility="daemon", |
| 60 | + app_name="infamy", msgid="test-start", |
| 61 | + sd={"test@32473": {"name": "rpc_log", "step": "3"}}) |
| 62 | + until(lambda: "Kilroy was here" in logfile(), attempts=10) |
| 63 | + |
| 64 | + with test.step("Verify RFC 5424 header fields of the logged message"): |
| 65 | + line = [ln for ln in logfile().splitlines() if "Kilroy was here" in ln][0] |
| 66 | + if not re.search(r"\binfamy - test-start \[test@32473 [^]]*\] Kilroy was here$", line): |
| 67 | + test.fail(f"Unexpected app-name, msgid, or structured data: {line}") |
| 68 | + for param in ('name="rpc_log"', 'step="3"'): |
| 69 | + if param not in line: |
| 70 | + test.fail(f"Missing structured data param {param}: {line}") |
| 71 | + |
| 72 | + with test.step("Log message with only the mandatory text"): |
| 73 | + target.log("Plain message, no frills") |
| 74 | + until(lambda: "Plain message" in logfile(), attempts=10) |
| 75 | + |
| 76 | + with test.step("Verify default app-name is set and msgid and structured data are empty"): |
| 77 | + line = [ln for ln in logfile().splitlines() if "Plain message" in ln][0] |
| 78 | + if not re.search(r" \S+ - - - Plain message, no frills$", line): |
| 79 | + test.fail(f"Unexpected header for default message: {line}") |
| 80 | + if re.search(r" - - - - Plain message", line): |
| 81 | + test.fail(f"Default app-name should not be empty: {line}") |
| 82 | + |
| 83 | + test.succeed() |
0 commit comments