Skip to content

Commit 1503cb9

Browse files
committed
refactor: use default=None for argparse append parameters (fix #540)
1 parent 257e7f0 commit 1503cb9

17 files changed

Lines changed: 210 additions & 56 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
Build, CI/CD:
1919

20-
* Remove `flatdict` dependency as it breaks builds on newer targets (RHEL 10, SLE 15/16) and no fix is available that also supports older targets (such as RHEL 8). This has the consequence that the [statuspal plugin](check-plugins/statuspal) is currently broken until the affected code is rewritten (tracked in [#1044](https://github.com/Linuxfabrik/monitoring-plugins/issues/1044)).
20+
* Remove `flatdict` dependency as it breaks builds on newer targets (RHEL 10, SLE 15/16) and no fix is available that also supports older targets (such as RHEL 8). The statuspal plugin has been rewritten to no longer depend on `flatdict` ([#1044](https://github.com/Linuxfabrik/monitoring-plugins/issues/1044)).
2121

2222

2323
### Added
@@ -62,11 +62,13 @@ Grafana:
6262
Monitoring Plugins:
6363

6464
* all plugins: ignore unknown arguments instead of generating an error (this helps with updating Icinga and Nagios service definitions considerably)
65+
* by-ssh, by-winrm, disk-usage, example, file-ownership, fs-ro, infomaniak-events, journald-query, logfile, matomo-reporting, mysql-logfile, php-status, pip-updates, systemd-unit: fix `append` parameters so that user-specified values replace defaults instead of being appended to them ([#540](https://github.com/Linuxfabrik/monitoring-plugins/issues/540))
6566
* file-count: stopping when number of files actually exceed thresholds, therefore dramatically faster for large directories
6667
* nextcloud-version: modernize code
6768
* php-status: always assume http://localhost/monitoring.php and, if not found, be tolerant
6869
* redis-status, valkey-status: modernize code and unify both plugins again after [PR #954](https://github.com/Linuxfabrik/monitoring-plugins/pull/954)
6970
* rocketchat-stats: improve output
71+
* statuspal: replace `flatdict` dependency with a recursive approach ([#1044](https://github.com/Linuxfabrik/monitoring-plugins/issues/1044))
7072
* updates: adapt to updated powershell.py library
7173

7274

@@ -79,6 +81,17 @@ Tools:
7981

8082
### Fixed
8183

84+
Build, CI/CD:
85+
86+
* requirements.txt: add missing `setuptools` dependency (required by `pbr`)
87+
88+
89+
Tools:
90+
91+
* check2basket: fix missing `importlib.machinery` and `importlib.util` imports
92+
* check2basket: write `[]` as default value for `append` parameters with `default=None` in the Icinga Director basket
93+
94+
8295
Grafana:
8396

8497
* Icinga Dashboard: Use a query instead of a constant service name to allow the dashboard to be used even if the service name differs

check-plugins/by-ssh/by-ssh

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ from lib.globals import (STATE_CRIT, STATE_OK, # pylint: disable=C0413
2626

2727

2828
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
29-
__version__ = '2025111401'
29+
__version__ = '2026033101'
3030

3131
DESCRIPTION = """This plugin uses SSH to execute a command on a remote host,
3232
returning STDOUT and, in case of failure, STDERR and the command's return code.
@@ -93,7 +93,7 @@ def parse_args():
9393
'Can be specified multiple times.',
9494
dest='CRIT_PATTERN',
9595
action='append',
96-
default=[],
96+
default=None,
9797
)
9898

9999
parser.add_argument(
@@ -102,7 +102,7 @@ def parse_args():
102102
'Can be specified multiple times.',
103103
dest='CRIT_REGEX',
104104
action='append',
105-
default=[],
105+
default=None,
106106
)
107107

108108
parser.add_argument(
@@ -287,7 +287,7 @@ def parse_args():
287287
'Can be specified multiple times.',
288288
dest='WARN_PATTERN',
289289
action='append',
290-
default=[],
290+
default=None,
291291
)
292292

293293
parser.add_argument(
@@ -296,7 +296,7 @@ def parse_args():
296296
'Can be specified multiple times.',
297297
dest='WARN_REGEX',
298298
action='append',
299-
default=[],
299+
default=None,
300300
)
301301

302302
args, _ = parser.parse_known_args()
@@ -313,6 +313,16 @@ def main():
313313
except SystemExit:
314314
sys.exit(STATE_UNKNOWN)
315315

316+
# set default values for append parameters that were not specified
317+
if args.CRIT_PATTERN is None:
318+
args.CRIT_PATTERN = []
319+
if args.CRIT_REGEX is None:
320+
args.CRIT_REGEX = []
321+
if args.WARN_PATTERN is None:
322+
args.WARN_PATTERN = []
323+
if args.WARN_REGEX is None:
324+
args.WARN_REGEX = []
325+
316326
# fetch data - run ssh
317327
cmd = "ssh {} {} {} {} {} {} {} {} '{}'@'{}' '{}'".format(
318328
"-4" if args.IPV4 else '',

check-plugins/by-winrm/by-winrm

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ from lib.globals import (STATE_CRIT, STATE_OK, STATE_UNKNOWN, STATE_WARN)
2424

2525

2626
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
27-
__version__ = '2026030301'
27+
__version__ = '2026033101'
2828

2929
DESCRIPTION = """This plugin executes PowerShell commands or scripts on remote Windows hosts via
3030
WinRM, supporting JEA. It returns standard output (STDOUT) and, in case of failure, standard error
@@ -82,7 +82,7 @@ def parse_args():
8282
'Can be specified multiple times.',
8383
dest='CRIT_PATTERN',
8484
action='append',
85-
default=[],
85+
default=None,
8686
)
8787

8888
parser.add_argument(
@@ -91,7 +91,7 @@ def parse_args():
9191
'Can be specified multiple times.',
9292
dest='CRIT_REGEX',
9393
action='append',
94-
default=[],
94+
default=None,
9595
)
9696

9797
parser.add_argument(
@@ -178,7 +178,7 @@ def parse_args():
178178
'Can be specified multiple times.',
179179
dest='WARN_PATTERN',
180180
action='append',
181-
default=[],
181+
default=None,
182182
)
183183

184184
parser.add_argument(
@@ -187,7 +187,7 @@ def parse_args():
187187
'Can be specified multiple times.',
188188
dest='WARN_REGEX',
189189
action='append',
190-
default=[],
190+
default=None,
191191
)
192192

193193
parser.add_argument(
@@ -251,6 +251,16 @@ def main():
251251
except SystemExit:
252252
sys.exit(STATE_UNKNOWN)
253253

254+
# set default values for append parameters that were not specified
255+
if args.CRIT_PATTERN is None:
256+
args.CRIT_PATTERN = []
257+
if args.CRIT_REGEX is None:
258+
args.CRIT_REGEX = []
259+
if args.WARN_PATTERN is None:
260+
args.WARN_PATTERN = []
261+
if args.WARN_REGEX is None:
262+
args.WARN_REGEX = []
263+
254264
# fetch data - run WinRM command
255265
if args.TEST is None:
256266
timer_start = lib.time.now('float')

check-plugins/disk-usage/disk-usage

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ except ImportError:
2929

3030

3131
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
32-
__version__ = '2025100601'
32+
__version__ = '2026033101'
3333

3434
DESCRIPTION = 'Checks the used disk space, for each partition.'
3535

@@ -84,7 +84,7 @@ def parse_args():
8484
'Includes are matched before excludes.',
8585
dest='EXCLUDE_PATTERN',
8686
action='append',
87-
default=[],
87+
default=None,
8888
)
8989

9090
parser.add_argument(
@@ -96,7 +96,7 @@ def parse_args():
9696
'Includes are matched before excludes.',
9797
dest='EXCLUDE_REGEX',
9898
action='append',
99-
default=[],
99+
default=None,
100100
)
101101

102102
parser.add_argument(
@@ -110,7 +110,7 @@ def parse_args():
110110
'first (as file system types are machine dependent).',
111111
dest='FSTYPE',
112112
action='append',
113-
default=[],
113+
default=None,
114114
)
115115

116116
parser.add_argument(
@@ -123,7 +123,7 @@ def parse_args():
123123
'Includes are matched before excludes.',
124124
dest='INCLUDE_PATTERN',
125125
action='append',
126-
default=[],
126+
default=None,
127127
)
128128

129129
parser.add_argument(
@@ -135,7 +135,7 @@ def parse_args():
135135
'Includes are matched before excludes.',
136136
dest='INCLUDE_REGEX',
137137
action='append',
138-
default=[],
138+
default=None,
139139
)
140140

141141
parser.add_argument(
@@ -153,7 +153,7 @@ def parse_args():
153153
'Can be specified multiple times.',
154154
action='append',
155155
dest='PERFDATA_REGEX',
156-
default=[],
156+
default=None,
157157
)
158158

159159
parser.add_argument(
@@ -239,6 +239,21 @@ def main():
239239
args = parse_args()
240240
except SystemExit:
241241
sys.exit(STATE_UNKNOWN)
242+
243+
# set default values for append parameters that were not specified
244+
if args.EXCLUDE_PATTERN is None:
245+
args.EXCLUDE_PATTERN = []
246+
if args.EXCLUDE_REGEX is None:
247+
args.EXCLUDE_REGEX = []
248+
if args.FSTYPE is None:
249+
args.FSTYPE = []
250+
if args.INCLUDE_PATTERN is None:
251+
args.INCLUDE_PATTERN = []
252+
if args.INCLUDE_REGEX is None:
253+
args.INCLUDE_REGEX = []
254+
if args.PERFDATA_REGEX is None:
255+
args.PERFDATA_REGEX = []
256+
242257
# args.WARN[0] = number, args.WARN[1] = unit, args.WARN[2] = USED|FREE
243258
try:
244259
float(args.WARN[0])

check-plugins/example/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ Hints for the Author (delete those):
4040

4141
```text
4242
usage: example [-h] [-V] [--always-ok] [-c CRIT] [--ignore-regex IGNORE_REGEX]
43-
[--test TEST] --token TOKEN [-w WARN]
43+
[--module MODULE] [--name NAME] [--test TEST] --token TOKEN
44+
[-w WARN]
4445
4546
A working Linuxfabrik monitoring plugin, written in Python 3, as a basis for
4647
further development, and much more text to help admins get this check up and
@@ -55,6 +56,10 @@ options:
5556
Any english title matching this python regex will be
5657
ignored (repeating). Example: '(?i)linuxfabrik' for a
5758
case-insensitive search for "linuxfabrik".
59+
--module MODULE "modulename" to check (startswith), for example
60+
`--module json --module mbstring` (repeating)
61+
--name NAME Only check items with this name (repeating). If not
62+
specified, all items are checked.
5863
--test TEST For unit tests. Needs "path-to-stdout-file,path-to-
5964
stderr-file,expected-retc".
6065
--token TOKEN Software API token

check-plugins/example/example

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ except ImportError:
2929

3030

3131
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
32-
__version__ = '2025100601'
32+
__version__ = '2026033101'
3333

3434
DESCRIPTION = """A working Linuxfabrik monitoring plugin, written in Python 3, as a basis for
3535
further development, and much more text to help admins get this check up and
3636
running."""
3737

38-
DEFAULT_WARN = 80
3938
DEFAULT_CRIT = 90
39+
DEFAULT_MODULE = ['calendar', 'Core', 'ctype', 'date']
40+
DEFAULT_WARN = 80
4041

4142

4243
def parse_args():
@@ -67,17 +68,53 @@ def parse_args():
6768
default=DEFAULT_CRIT,
6869
)
6970

71+
# Append parameters must always use `default=None` instead of a list,
72+
# because argparse appends user values to the default list instead of
73+
# replacing it (see https://bugs.python.org/issue16399).
74+
# After parsing, assign the actual defaults in main() if the value is
75+
# still None.
76+
#
77+
# Case 1: "not specified" and "empty list" are the same thing.
78+
# The parameter is purely additive (e.g. patterns to match).
79+
# Assign `[]` as the default in main().
7080
parser.add_argument(
7181
'--ignore-regex',
7282
help='Any english title matching this python regex will be ignored '
7383
'(repeating). '
7484
'Example: \'(?i)linuxfabrik\' for a case-insensitive search for '
7585
'"linuxfabrik".',
7686
action='append',
77-
default=[],
87+
default=None,
7888
dest='IGNORE_REGEX',
7989
)
8090

91+
# Case 2: "not specified" and "empty list" are the same thing, but there
92+
# is a non-empty default list that should be used if the user
93+
# does not specify any values.
94+
# Assign `DEFAULT_X` as the default in main().
95+
parser.add_argument(
96+
'--module',
97+
help='"modulename" to check (startswith), for example '
98+
'`--module json --module mbstring` (repeating)',
99+
dest='MODULE',
100+
action='append',
101+
default=None,
102+
)
103+
104+
# Case 3: "not specified" means something different than "empty list".
105+
# For example, None = check all items, list = filter to only
106+
# the specified items.
107+
# Do NOT assign a default in main(). Instead, check for None
108+
# where the parameter is used: `if args.X is not None`.
109+
parser.add_argument(
110+
'--name',
111+
help='Only check items with this name (repeating). '
112+
'If not specified, all items are checked.',
113+
dest='NAME',
114+
action='append',
115+
default=None,
116+
)
117+
81118
parser.add_argument(
82119
'--test',
83120
help='For unit tests. Needs "path-to-stdout-file,path-to-stderr-file,expected-retc".',
@@ -115,6 +152,13 @@ def main():
115152
except SystemExit:
116153
sys.exit(STATE_UNKNOWN)
117154

155+
# set default values for append parameters that were not specified
156+
if args.IGNORE_REGEX is None: # case 1: default to empty list
157+
args.IGNORE_REGEX = []
158+
if args.MODULE is None: # case 2: default to non-empty list
159+
args.MODULE = DEFAULT_MODULE
160+
# args.NAME is not set here # case 3: None means "check all"
161+
118162
# fetch data
119163
if args.TEST is None:
120164
cmd = 'cat /etc/os-release'
@@ -138,6 +182,10 @@ def main():
138182

139183
# analyze data
140184
title = 'Lorem ipsum'
185+
if args.NAME is not None:
186+
# case 3: user specified --name, so filter
187+
if title not in args.NAME:
188+
pass # in loops: continue
141189
if any(item.search(title) for item in compiled_ignore_regex):
142190
pass # in loops: continue
143191
value = str(lib.time.now())[-2:]

check-plugins/file-ownership/file-ownership

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ from lib.globals import (STATE_OK, STATE_UNKNOWN, # pylint: disable=C0413
2121
STATE_WARN)
2222

2323
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
24-
__version__ = '2025100601'
24+
__version__ = '2026033101'
2525

2626
DESCRIPTION = 'Checks the ownership (owner and group, both have to be names) of a list of files.'
2727

@@ -85,7 +85,7 @@ def parse_args():
8585
help='File to be checked, in the format `owner:group,path` (repeatable).',
8686
action='append',
8787
dest='FILES',
88-
default=DEFAULT_FILES,
88+
default=None,
8989
)
9090

9191
args, _ = parser.parse_known_args()
@@ -102,6 +102,10 @@ def main():
102102
except SystemExit:
103103
sys.exit(STATE_UNKNOWN)
104104

105+
# set default values for append parameters that were not specified
106+
if args.FILES is None:
107+
args.FILES = DEFAULT_FILES
108+
105109
state = STATE_OK
106110
msg = ''
107111
cnt = 0

0 commit comments

Comments
 (0)