-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcheck_bird_blackholes.py
102 lines (75 loc) · 2.95 KB
/
check_bird_blackholes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/python3
#
# This script is licensed under GPL-2+
#
'''Nagios/icinga plugin ensuring a set of Bird tables are empty.
This is used for monitoring within the Bird networking daemon some tables that
have a special purpose and which should be empty in normal circumstances. For
example, tables where blackhole routes are inserted with ip-route and then
learned automatically by Bird.
'''
import sys
import os
import argparse
import subprocess
# Nagios plugin exit codes
OK = 0
WARNING = 1
CRITICAL = 2
UNKNOWN = 3
birdc = '/usr/sbin/birdc'
class WarningReached(Exception):
pass
class CriticalReached(Exception):
pass
class ExecutionError(Exception):
pass
def debug(*args):
if os.environ.get('DEBUG', None):
print(f"debug: {args}")
def check_bird_table_empty(table, warn, crit):
cmd = [birdc, '-r', '-v', 'show', 'route', 'table', table]
debug("running command: ", cmd)
res = subprocess.run(cmd, encoding='utf8',
capture_output=True, check=True)
output = res.stdout.split("\n")[2:]
debug("output line count: ", len(output))
debug("output lines: ", output)
# Error codes with bird start with 8000
if int(output[0][0:4]) > 8000:
raise ExecutionError(' '.join(output))
routes = [r for r in output if r and not r.startswith('1007-')]
debug("found routes: ", routes)
if crit is not None and len(routes) >= crit:
raise CriticalReached(f"Routes found in table {table}: {len(routes)}")
if warn is not None and len(routes) >= warn:
raise WarningReached(f"Routes found in table {table}: {len(routes)}")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Ensure a set of Bird tables are empty')
parser.add_argument('-w', '--warning-threshold', type=int,
help='Number of routes in each table at which the check enters warning state')
parser.add_argument('-c', '--critical-threshold', type=int,
help='Number of routes in each table at which the check enters critical state')
parser.add_argument('tables', nargs='+', help='Bird tables that get inspected')
args = parser.parse_args()
tables = args.tables
if len(tables) == 0:
print("error: no table names were specified")
sys.exit(UNKNOWN)
debug("arguments: warning=", args.warning_threshold, " critical=", args.critical_threshold)
check_state = OK
for t in tables:
try:
check_bird_table_empty(t, warn=args.warning_threshold, crit=args.critical_threshold)
except (subprocess.CalledProcessError, ExecutionError) as e:
print(f"error: {e}")
sys.exit(UNKNOWN)
except WarningReached as e:
print(e)
if check_state < WARNING:
check_state = WARNING
except CriticalReached as e:
print(e)
if check_state < CRITICAL:
check_state = CRITICAL
sys.exit(check_state)