Skip to content

Commit bcbe20d

Browse files
committed
test(*-version): add --test hook and EOL-aware fixtures for redis, postgresql, mysql
Three pilot plugins for Category B (shell-driven version checkers). Each gets a `--test` hook that bypasses the live shell call and loads the version-string output from a stdout fixture, then runs the existing parser regex against it. The downstream `lib.version.check_eol()` HTTP call to endoflife.date still runs live, so the test result reflects today's actual EOL data. Coverage: - **redis-version**: 11 fixtures (Redis 5.0, 6.0, 6.2, 7.0, 7.2, 7.4, 8.0, 8.2, 8.4, 8.6, plus a garbage-output edge case). Captured from the official `redis:<tag>` images on Docker Hub - the upstream binary is the same regardless of base distro, so the `redis-server --version` strings are functionally identical. 4 of the 10 versions are currently EOL (5.0, 6.0, 7.0, 8.0) so the WARN code path is genuinely exercised, not just synthetic. - **postgresql-version**: 7 fixtures (PostgreSQL 13 through 18, plus a garbage-output edge case). Captured from the official `postgres:<tag>` images. PostgreSQL 13 hit EOL 2025-11-13 so it triggers the WARN path. - **mysql-version**: 7 fixtures captured from the Red Hat / CentOS Stream sclorg containers - `mariadb-105-c8s`, `mariadb-105-c9s`, `mariadb-1011-c10s`, `mysql-80-c8s`, `mysql-80-c9s`, `mysql-84-c10s`, plus a garbage-output edge case. Both the MariaDB-suffixed `Ver 10.x.y-MariaDB` format and the upstream `Ver 8.x.y` format are covered, and four of them are currently EOL or near-EOL. Each plugin's `--test` argument was added via the standard `lib.lftest.test()` shim and its `__version__` was bumped. The expected Nagios states in the TESTS list are pinned to live endoflife.date data as of today and will need re-pinning every few months as new releases roll out and old ones hit EOL.
1 parent 49f334d commit bcbe20d

31 files changed

+435
-17
lines changed

check-plugins/mysql-version/mysql-version

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ import sys
1616

1717
import lib.args
1818
import lib.base
19+
import lib.lftest
1920
import lib.shell
2021
import lib.version
2122
from lib.globals import STATE_UNKNOWN
2223

2324
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
24-
__version__ = '2026040801'
25+
__version__ = '2026041301'
2526

2627
DESCRIPTION = """Checks the installed MySQL/MariaDB version against the endoflife.date API and alerts if
2728
the version is end-of-life or if newer major, minor, or patch releases are available.
@@ -103,6 +104,13 @@ def parse_args():
103104
default=DEFAULT_OFFSET_EOL,
104105
)
105106

107+
parser.add_argument(
108+
'--test',
109+
help=lib.args.help('--test'),
110+
dest='TEST',
111+
type=lib.args.csv,
112+
)
113+
106114
parser.add_argument(
107115
'--timeout',
108116
help=lib.args.help('--timeout') + ' Default: %(default)s (seconds)',
@@ -115,7 +123,21 @@ def parse_args():
115123
return args
116124

117125

118-
def get_installed_version():
126+
def get_installed_version(test_arg=None):
127+
# In test mode, read the fixture once and try both regexes
128+
# against it. The mysqld output matches the first one; the
129+
# mariadb / mysql client outputs match the second.
130+
if test_arg is not None:
131+
stdout, _, _ = lib.lftest.test(test_arg)
132+
stdout = stdout.strip()
133+
m = re.search(r'Ver (.*?) ', stdout)
134+
if m:
135+
return m.group(1).strip()
136+
m = re.search(r'(?i)b (.*?),', stdout)
137+
if m:
138+
return m.group(1).strip()
139+
return ''
140+
119141
success, result = lib.shell.shell_exec('mysqld --version')
120142
if success:
121143
stdout = result[0].strip()
@@ -153,7 +175,7 @@ def main():
153175
sys.exit(STATE_UNKNOWN)
154176

155177
# fetch data
156-
installed_version = get_installed_version()
178+
installed_version = get_installed_version(args.TEST)
157179
if not installed_version:
158180
lib.base.cu('MariaDB/MySQL not found.')
159181
mariadb = 'MariaDB' in installed_version
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8; py-indent-offset: 4 -*-
3+
#
4+
# Author: Linuxfabrik GmbH, Zurich, Switzerland
5+
# Contact: info (at) linuxfabrik (dot) ch
6+
# https://www.linuxfabrik.ch/
7+
# License: The Unlicense, see LICENSE file.
8+
9+
# https://github.com/Linuxfabrik/monitoring-plugins/blob/main/CONTRIBUTING.md
10+
11+
"""Unit tests for the mysql-version check plugin.
12+
13+
The plugin probes for either MySQL Community Server or MariaDB by
14+
running `mysqld --version` first and falling back to
15+
`mariadb --version` / `mysql --version` if the server binary is not
16+
available. Two regexes parse the two output formats:
17+
18+
- mysqld output: `mysqld Ver 10.11.15-MariaDB for Linux ...`
19+
`/usr/libexec/mysqld Ver 8.0.45 for Linux ...`
20+
- client output: `mysql Ver 15.1 Distrib 10.11.x-MariaDB, for ...`
21+
22+
The fixtures in `stdout/` are the real `mysqld --version` strings
23+
captured from the Red Hat / CentOS Stream sclorg containers
24+
(`quay.io/sclorg/mariadb-105-c8s`, `mariadb-105-c9s`,
25+
`mariadb-1011-c10s`, `mysql-80-c8s`, `mysql-80-c9s`,
26+
`mysql-84-c10s`). Both the MariaDB-suffixed format and the
27+
upstream-MySQL format are covered.
28+
29+
Each testcase pins the expected Nagios state to whatever
30+
`lib.version.check_eol()` returned when these fixtures were saved
31+
against the live https://endoflife.date/api/{mysql,mariadb}.json
32+
data. The EOL table drifts; assertions need re-pinning every few
33+
months.
34+
"""
35+
36+
import sys
37+
sys.path.insert(0, '..')
38+
39+
import unittest
40+
41+
from lib.globals import STATE_OK, STATE_UNKNOWN, STATE_WARN
42+
import lib.lftest
43+
44+
45+
TESTS = [
46+
{
47+
# MariaDB 10.5 reached EOL 2025-06-24.
48+
'id': 'warn-mariadb-10-5-c8s-eol',
49+
'test': 'stdout/mysqld-version-mariadb-10.5-c8s,,0',
50+
'assert-retc': STATE_WARN,
51+
'assert-in': ['MariaDB v10.5.9', 'EOL 2025-06-24', '[WARNING]'],
52+
},
53+
{
54+
'id': 'warn-mariadb-10-5-c9s-eol',
55+
'test': 'stdout/mysqld-version-mariadb-10.5-c9s,,0',
56+
'assert-retc': STATE_WARN,
57+
'assert-in': ['MariaDB v10.5.29', 'EOL 2025-06-24', '[WARNING]'],
58+
},
59+
{
60+
# MariaDB 10.11 LTS, EOL 2028-02-16.
61+
'id': 'ok-mariadb-10-11-c10s-supported',
62+
'test': 'stdout/mysqld-version-mariadb-10.11-c10s,,0',
63+
'assert-retc': STATE_OK,
64+
'assert-in': ['MariaDB v10.11.15', 'EOL 2028-02-16'],
65+
},
66+
{
67+
# MySQL 8.0 - full support already ended, hard EOL 2026-04-30.
68+
'id': 'warn-mysql-8-0-c8s-near-eol',
69+
'test': 'stdout/mysqld-version-mysql-8.0-c8s,,0',
70+
'assert-retc': STATE_WARN,
71+
'assert-in': [
72+
'MySQL v8.0.26',
73+
'full support ended on 2025-04-30',
74+
'EOL 2026-04-30',
75+
'[WARNING]',
76+
],
77+
},
78+
{
79+
'id': 'warn-mysql-8-0-c9s-near-eol',
80+
'test': 'stdout/mysqld-version-mysql-8.0-c9s,,0',
81+
'assert-retc': STATE_WARN,
82+
'assert-in': ['MySQL v8.0.45', 'EOL 2026-04-30', '[WARNING]'],
83+
},
84+
{
85+
# MySQL 8.4 LTS, EOL 2032-04-30.
86+
'id': 'ok-mysql-8-4-c10s-supported',
87+
'test': 'stdout/mysqld-version-mysql-8.4-c10s,,0',
88+
'assert-retc': STATE_OK,
89+
'assert-in': ['MySQL v8.4.8', 'EOL 2032-04-30'],
90+
},
91+
{
92+
# Parser edge case: command not found.
93+
'id': 'unknown-garbage-output',
94+
'test': 'stdout/garbage-output,,0',
95+
'assert-retc': STATE_UNKNOWN,
96+
'assert-in': ['MariaDB/MySQL not found.'],
97+
},
98+
]
99+
100+
101+
class TestCheck(unittest.TestCase):
102+
103+
check = '../mysql-version'
104+
105+
def test(self):
106+
for t in TESTS:
107+
with self.subTest(id=t['id']):
108+
lib.lftest.run(self, self.check, t)
109+
110+
111+
if __name__ == '__main__':
112+
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bash: mysqld: command not found
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mysqld Ver 10.11.15-MariaDB for Linux on x86_64 (MariaDB Server)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mysqld Ver 10.5.9-MariaDB for Linux on x86_64 (MariaDB Server)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mysqld Ver 10.5.29-MariaDB for Linux on x86_64 (MariaDB Server)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/usr/libexec/mysqld Ver 8.0.26 for Linux on x86_64 (Source distribution)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/usr/libexec/mysqld Ver 8.0.45 for Linux on x86_64 (Source distribution)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/usr/libexec/mysqld Ver 8.4.8 for Linux on x86_64 (Source distribution)

check-plugins/postgresql-version/postgresql-version

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ import sys
1616

1717
import lib.args
1818
import lib.base
19+
import lib.lftest
1920
import lib.shell
2021
import lib.version
2122
from lib.globals import STATE_UNKNOWN
2223

2324
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
24-
__version__ = '2026040801'
25+
__version__ = '2026041301'
2526

2627
DESCRIPTION = """Checks the installed PostgreSQL version against the endoflife.date API and alerts if
2728
the version is end-of-life or if newer major, minor, or patch releases are available.
@@ -112,6 +113,13 @@ def parse_args():
112113
default=DEFAULT_TIMEOUT,
113114
)
114115

116+
parser.add_argument(
117+
'--test',
118+
help=lib.args.help('--test'),
119+
dest='TEST',
120+
type=lib.args.csv,
121+
)
122+
115123
parser.add_argument(
116124
'--username',
117125
help='PostgreSQL username for running `psql`. Default: %(default)s',
@@ -124,12 +132,16 @@ def parse_args():
124132

125133

126134
def get_installed_version(args):
127-
success, result = lib.shell.shell_exec(
128-
f'psql --username={args.USERNAME} --command="SELECT version();"',
129-
)
130-
if not success:
131-
return ''
132-
stdout = result[0].strip()
135+
if args.TEST is None:
136+
success, result = lib.shell.shell_exec(
137+
f'psql --username={args.USERNAME} --command="SELECT version();"',
138+
)
139+
if not success:
140+
return ''
141+
stdout = result[0].strip()
142+
else:
143+
stdout, _, _ = lib.lftest.test(args.TEST)
144+
stdout = stdout.strip()
133145
# where to find the version number in output?
134146
version_regex = r'L (\d+\.\d+)'
135147
try:

0 commit comments

Comments
 (0)