Skip to content

Commit 89c2e4d

Browse files
committed
feat(haproxy-status): add --ignore regex parameter for proxies, frontends, backends and servers
Filters rows out of the HAProxy stats output by matching a Python regular expression against the combined `<proxy>/<svname>` identifier. The canonical use case is an on-demand certbot backend that is only UP during cert renewal and would otherwise flood the check with DOWN alerts. The regex is case-sensitive by default, matching the lib.args --match / --ignore-regex convention; admins can opt into case-insensitive matching with the inline `(?i)` flag. Can be specified multiple times so individual patterns stay self-contained both on the command line and in the Icinga Director basket (where the parameter is exposed as a DataTypeArray). Closes #835
1 parent 5cecee5 commit 89c2e4d

File tree

6 files changed

+140
-7
lines changed

6 files changed

+140
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Monitoring Plugins:
3535
* by-winrm: executes commands on remote Windows hosts by WinRM, supporting JEA (including the JEA endpoint via `--winrm-configuration-name`)
3636
* infomaniak-swiss-backup-devices: add `--ignore-customer`, `--ignore-name`, `--ignore-tag`, `--ignore-user` parameters to skip devices by regex
3737
* infomaniak-swiss-backup-products: add `--ignore-customer`, `--ignore-tag` parameters to skip products by regex
38+
* haproxy-status: add `--ignore` parameter to filter out proxies, frontends, backends or servers by regex on the combined `<proxy>/<svname>` identifier, e.g. to skip an on-demand certbot backend that is only UP during cert renewal ([#835](https://github.com/Linuxfabrik/monitoring-plugins/issues/835))
3839
* ipmi-sel: add `--ignore` parameter to filter out SEL entries by regex, e.g. auto-generated "Log area reset/cleared" entries after `ipmitool sel clear` ([#982](https://github.com/Linuxfabrik/monitoring-plugins/issues/982))
3940
* json-values: add `--token` and `--header` parameters for HTTP bearer-token and custom header authentication when fetching JSON from protected endpoints, add `--warning-key` / `--warning` and `--critical-key` / `--critical` to alert on a numeric value at a specific JSON key (with Nagios range syntax), and support dot-notation for nested keys in all `--*-key` parameters (e.g. `--state-key=meta.state`) ([#1005](https://github.com/Linuxfabrik/monitoring-plugins/issues/1005))
4041
* librenms-alerts: add device-type `management`

check-plugins/haproxy-status/README.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,33 @@ Monitors HAProxy performance and health via the stats endpoint. Reports frontend
5555
## Help
5656
5757
```text
58-
usage: haproxy-status [-h] [-V] [--always-ok] [-c CRIT] [--insecure]
59-
[--lengthy] [--no-proxy] [-p PASSWORD] [--test TEST]
60-
[--timeout TIMEOUT] [-u URL] [--username USERNAME]
61-
[-w WARN]
58+
usage: haproxy-status [-h] [-V] [--always-ok] [-c CRIT] [--ignore IGNORE]
59+
[--insecure] [--lengthy] [--no-proxy] [-p PASSWORD]
60+
[--test TEST] [--timeout TIMEOUT] [-u URL]
61+
[--username USERNAME] [-w WARN]
6262
6363
Monitors HAProxy performance and health via the stats endpoint. Reports
6464
frontend and backend session usage, request rates, response times, error
6565
rates, and server states. Alerts when session usage exceeds the configured
66-
thresholds. Supports extended reporting via --lengthy.
66+
thresholds. Proxies, frontends, backends or individual servers can be filtered
67+
out with --ignore (e.g. an on-demand certbot backend that is only UP during
68+
cert renewal). Supports extended reporting via --lengthy.
6769
6870
options:
6971
-h, --help show this help message and exit
7072
-V, --version show program's version number and exit
7173
--always-ok Always returns OK.
7274
-c, --critical CRIT CRIT threshold in percent. Default: >= 95
75+
--ignore IGNORE Ignore proxies, frontends, backends or servers
76+
matching this Python regular expression on the
77+
combined `<proxy>/<svname>` identifier (where `svname`
78+
is `FRONTEND`, `BACKEND` or an individual server
79+
name). Case-sensitive by default; use `(?i)` for case-
80+
insensitive matching. Can be specified multiple times.
81+
Example: `--ignore="^certbot/"` to ignore everything
82+
under the certbot proxy. Example:
83+
`--ignore="(?i)^certbot/"` for a case-insensitive
84+
match. Default: None
7385
--insecure This option explicitly allows insecure SSL
7486
connections.
7587
--lengthy Extended reporting.

check-plugins/haproxy-status/haproxy-status

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import argparse
1414
import base64
15+
import re
1516
import sys
1617

1718
import lib.args
@@ -24,9 +25,13 @@ import lib.url
2425
from lib.globals import STATE_OK, STATE_UNKNOWN, STATE_WARN
2526

2627
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
27-
__version__ = '2026041001'
28+
__version__ = '2026041403'
2829

29-
DESCRIPTION = """Monitors HAProxy performance and health via the stats endpoint. Reports frontend and backend session usage, request rates, response times, error rates, and server states. Alerts when session usage exceeds the configured thresholds. Supports extended reporting via --lengthy."""
30+
DESCRIPTION = """Monitors HAProxy performance and health via the stats endpoint. Reports
31+
frontend and backend session usage, request rates, response times, error rates, and server
32+
states. Alerts when session usage exceeds the configured thresholds. Proxies, frontends,
33+
backends or individual servers can be filtered out with --ignore (e.g. an on-demand certbot
34+
backend that is only UP during cert renewal). Supports extended reporting via --lengthy."""
3035

3136
DEFAULT_CRIT = 95 # %
3237
DEFAULT_INSECURE = False
@@ -68,6 +73,22 @@ def parse_args():
6873
default=DEFAULT_CRIT,
6974
)
7075

76+
parser.add_argument(
77+
'--ignore',
78+
help='Ignore proxies, frontends, backends or servers matching this '
79+
'Python regular expression on the combined `<proxy>/<svname>` '
80+
'identifier (where `svname` is `FRONTEND`, `BACKEND` or an individual '
81+
'server name). Case-sensitive by default; use `(?i)` for '
82+
'case-insensitive matching. '
83+
'Can be specified multiple times. '
84+
'Example: `--ignore="^certbot/"` to ignore everything under the certbot proxy. '
85+
'Example: `--ignore="(?i)^certbot/"` for a case-insensitive match. '
86+
'Default: %(default)s',
87+
dest='IGNORE',
88+
action='append',
89+
default=None,
90+
)
91+
7192
parser.add_argument(
7293
'--insecure',
7394
help=lib.args.help('--insecure'),
@@ -156,6 +177,17 @@ def main():
156177
except SystemExit:
157178
sys.exit(STATE_UNKNOWN)
158179

180+
if args.IGNORE is None:
181+
args.IGNORE = []
182+
183+
# compile ignore patterns (case-sensitive by default, matching the
184+
# lib.args convention for --match / --ignore-regex; the user can
185+
# opt into case-insensitive matching with the inline `(?i)` flag).
186+
try:
187+
ignore_patterns = [re.compile(p) for p in args.IGNORE]
188+
except re.error as e:
189+
lib.base.cu(f'Invalid regular expression: {e}')
190+
159191
# fetch data
160192
result = ''
161193
if args.TEST is None:
@@ -272,6 +304,14 @@ def main():
272304
except (ValueError, IndexError):
273305
lib.base.cu('Malformed HAProxy status info.')
274306

307+
# Skip rows matched by --ignore. The combined `<pxname>/<svname>`
308+
# identifier is unique per row and lets the user target a whole
309+
# proxy (`^certbot/`), every backend aggregate (`/BACKEND$`) or
310+
# a specific server in a specific proxy (`^web/server-02$`).
311+
ignore_key = f'{ha_pxname}/{ha_svname}'
312+
if any(pattern.search(ignore_key) for pattern in ignore_patterns):
313+
continue
314+
275315
# Status check
276316
status_state = STATE_OK
277317
if ha_status not in GOOD_STATUSES:

check-plugins/haproxy-status/icingaweb2-module-director/haproxy-status.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
"--critical": {
99
"value": "$haproxy_status_critical$"
1010
},
11+
"--ignore": {
12+
"value": "$haproxy_status_ignore$",
13+
"repeat_key": true
14+
},
1115
"--insecure": {
1216
"set_if": "$haproxy_status_insecure$"
1317
},
@@ -85,6 +89,11 @@
8589
"datafield_id": 10,
8690
"is_required": "n",
8791
"var_filter": null
92+
},
93+
{
94+
"datafield_id": 11,
95+
"is_required": "n",
96+
"var_filter": null
8897
}
8998
],
9099
"imports": [],
@@ -141,6 +150,7 @@
141150
"criticality": "C",
142151
"haproxy_status_always_ok": false,
143152
"haproxy_status_critical": 95,
153+
"haproxy_status_ignore": [],
144154
"haproxy_status_insecure": false,
145155
"haproxy_status_lengthy": false,
146156
"haproxy_status_no_proxy": false,
@@ -256,6 +266,17 @@
256266
"visibility": "visible"
257267
},
258268
"uuid": "56b69da6-81a7-43cc-b0bb-43670f84f4dd"
269+
},
270+
"11": {
271+
"varname": "haproxy_status_ignore",
272+
"caption": "HAProxy Status: Ignore",
273+
"description": "Ignore proxies, frontends, backends or servers matching this Python regular expression (case-insensitive) on the combined `<proxy>/<svname>` identifier. Can be specified multiple times.",
274+
"datatype": "Icinga\\Module\\Director\\DataType\\DataTypeArray",
275+
"format": null,
276+
"settings": {
277+
"visibility": "visible"
278+
},
279+
"uuid": "2392ebdf-b033-47a1-9dcc-ae94f72db5a4"
259280
}
260281
}
261282
}

check-plugins/haproxy-status/unit-test/run

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,59 @@ TESTS = [
9191
'Proxy name',
9292
],
9393
},
94+
95+
# #835: without --ignore, an on-demand certbot backend in MAINT/DOWN
96+
# produces a WARN; --ignore='^certbot/' filters the whole proxy and
97+
# the check comes back OK while still reporting the rest of the
98+
# HAProxy topology. The regex is case-sensitive by default (matching
99+
# the lib.args --match / --ignore-regex convention), so
100+
# --ignore='^CERTBOT/' does NOT match; the user opts into
101+
# case-insensitive matching with the inline `(?i)` flag.
102+
{
103+
'id': 'warn-certbot-backend-down',
104+
'test': 'stdout/certbot-backend-down,,0',
105+
'assert-retc': STATE_WARN,
106+
'assert-in': [
107+
'certbot certbot_challenge: MAINT',
108+
'certbot BACKEND: DOWN',
109+
],
110+
},
111+
{
112+
'id': 'ok-certbot-ignored',
113+
'test': 'stdout/certbot-backend-down,,0',
114+
'params': "--ignore='^certbot/'",
115+
'assert-retc': STATE_OK,
116+
'assert-in': ['Everything is ok.', 'web', 'FRONTEND'],
117+
'assert-not-in': ['certbot'],
118+
},
119+
{
120+
'id': 'warn-certbot-default-case-sensitive',
121+
'test': 'stdout/certbot-backend-down,,0',
122+
# Uppercase pattern must NOT match lowercase certbot: the regex
123+
# default is case-sensitive, so this ignore is a no-op and the
124+
# certbot proxy still triggers a WARN.
125+
'params': "--ignore='^CERTBOT/'",
126+
'assert-retc': STATE_WARN,
127+
'assert-in': ['certbot BACKEND: DOWN'],
128+
},
129+
{
130+
'id': 'ok-certbot-ignored-case-insensitive-opt-in',
131+
'test': 'stdout/certbot-backend-down,,0',
132+
# Opt into case-insensitive matching with the inline `(?i)`
133+
# flag, which is the lib.args convention for --match /
134+
# --ignore-regex parameters.
135+
'params': "--ignore='(?i)^certbot/'",
136+
'assert-retc': STATE_OK,
137+
'assert-in': ['Everything is ok.'],
138+
'assert-not-in': ['certbot certbot_challenge: MAINT'],
139+
},
140+
{
141+
'id': 'unknown-ignore-invalid-regex',
142+
'test': 'stdout/certbot-backend-down,,0',
143+
'params': "--ignore='('",
144+
'assert-retc': STATE_UNKNOWN,
145+
'assert-in': ['Invalid regular expression'],
146+
},
94147
]
95148

96149

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,
2+
web,FRONTEND,,,12,50,3000,4321,1234567,7654321,0,0,0,,,,,OPEN,,,,,,,,,1,1,0,,,,0,0,0,10,,,,0,4000,0,0,0,0,,1,20,4321,,,0,0,0,0,,,,,,,,
3+
web,srv01,0,0,0,1,,4321,1234567,7654321,,0,,0,0,0,0,UP,1,1,0,0,0,100,0,,1,1,1,,4321,,2,0,,10,L4OK,,0,0,4000,0,0,0,0,0,,,,0,0,,,,,10,,,0,1,5,50,
4+
web,BACKEND,0,0,0,1,300,4321,1234567,7654321,0,0,,0,0,0,0,UP,1,1,0,,0,100,0,,1,1,0,,4321,,1,0,,10,,,,0,4000,0,0,0,0,,,,,0,0,0,0,0,0,10,,,0,1,5,50,
5+
certbot,certbot_challenge,0,0,0,0,,0,0,0,,0,,0,0,0,0,MAINT,1,1,0,0,1,100,1,,1,2,1,,0,,2,0,,0,L4OK,,1,,,,,,,,,,0,0,,,,,-1,,,0,0,0,0,
6+
certbot,BACKEND,0,0,0,0,300,0,0,0,0,0,,0,0,0,0,DOWN,1,1,0,,1,100,1,,1,2,0,,0,,1,0,,0,,,,,,,,,,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,

0 commit comments

Comments
 (0)