mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-21 02:33:18 +00:00
foomuuri: plugin to graph Foomuuri statistics
Add new plugin to graph statistics from Foomuuri. Foomuuri is a multizone bidirectional nftables firewall. See: https://github.com/FoobarOy/foomuuri
This commit is contained in:
parent
f777b73725
commit
93f940f8fb
1 changed files with 228 additions and 0 deletions
228
plugins/foomuuri/foomuuri
Executable file
228
plugins/foomuuri/foomuuri
Executable file
|
@ -0,0 +1,228 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""Munin plugin to graph Foomuuri statistics.
|
||||
|
||||
=head1 NAME
|
||||
|
||||
foomuuri - graph Foomuuri statistics.
|
||||
|
||||
=head1 APPLICABLE SYSTEMS
|
||||
|
||||
Linux systems with Foomuuri running.
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
This plugin must be run as root.
|
||||
|
||||
[foomuuri]
|
||||
user root
|
||||
|
||||
# Optional: counter names to graph, wildcards are supported
|
||||
env.counter_names *
|
||||
|
||||
# Optional: set names to graph, wildcards are supported
|
||||
env.set_names _lograte*
|
||||
|
||||
# Optional: monitor statistics filename
|
||||
env.monitor_statistics /var/lib/foomuuri/monitor.statistics
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Kim B. Heino <b@bbbs.net>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv2
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=auto
|
||||
#%# capabilities=autoconf
|
||||
|
||||
=cut
|
||||
|
||||
"""
|
||||
|
||||
import fnmatch
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
import unicodedata
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def safename(name):
|
||||
"""Return safe variable name."""
|
||||
# Convert ä->a as isalpha('ä') is true
|
||||
value = unicodedata.normalize('NFKD', name)
|
||||
value = value.encode('ASCII', 'ignore').decode('utf-8')
|
||||
|
||||
# Remove non-alphanumeric chars
|
||||
return ''.join(char.lower() if char.isalnum() else '_' for char in value)
|
||||
|
||||
|
||||
def read_stats():
|
||||
"""Read Foomuuri monitor statistics file."""
|
||||
# Monitor
|
||||
filename = os.getenv('monitor_statistics',
|
||||
'/var/lib/foomuuri/monitor.statistics')
|
||||
try:
|
||||
monitor = json.loads(pathlib.Path(filename).read_text('utf-8'))
|
||||
except (FileNotFoundError, ValueError):
|
||||
monitor = {}
|
||||
|
||||
# Read Foomuuri ruleset from nft
|
||||
try:
|
||||
nftdata = json.loads(subprocess.run(
|
||||
['nft', '--json', 'list', 'table', 'inet', 'foomuuri'],
|
||||
stdout=subprocess.PIPE, check=False, encoding='utf-8').stdout)
|
||||
except (OSError, ValueError):
|
||||
nftdata = {}
|
||||
|
||||
# Set size - merge IPv4 and IPv6 to single value
|
||||
sets = Counter()
|
||||
names = os.getenv('set_names', '_lograte*').split()
|
||||
for item in nftdata.get('nftables', {}):
|
||||
if 'set' in item:
|
||||
name = item['set']['name'][:-2] # Without _4
|
||||
if any(fnmatch.fnmatch(name, matcher) for matcher in names):
|
||||
sets.update({name: len(item['set'].get('elem', []))})
|
||||
|
||||
# Named counters
|
||||
counters = {}
|
||||
names = os.getenv('counter_names', '*').split()
|
||||
for item in nftdata.get('nftables', {}):
|
||||
if 'counter' in item:
|
||||
name = item['counter']['name']
|
||||
if any(fnmatch.fnmatch(name, matcher) for matcher in names):
|
||||
counters[name] = {
|
||||
'bytes': item['counter']['bytes'],
|
||||
'packets': item['counter']['packets'],
|
||||
}
|
||||
|
||||
# Return data
|
||||
ret = {}
|
||||
if monitor:
|
||||
ret['monitor'] = monitor
|
||||
if sets:
|
||||
ret['set'] = sets
|
||||
if counters:
|
||||
ret['counter'] = counters
|
||||
return ret
|
||||
|
||||
|
||||
def print_labels(labels, *, warning=None, derive=False):
|
||||
"""Print config labels."""
|
||||
for label in sorted(labels):
|
||||
safe = safename(label)
|
||||
print(f'{safe}.label {label}')
|
||||
if warning:
|
||||
print(f'{safe}.warning {warning}')
|
||||
if derive:
|
||||
print(f'{safe}.type DERIVE')
|
||||
print(f'{safe}.min 0')
|
||||
|
||||
|
||||
def config(stats):
|
||||
"""Print plugin config."""
|
||||
if 'monitor' in stats:
|
||||
print('multigraph foomuuri_monitor_time')
|
||||
print('graph_title Foomuuri Monitor Ping Latency')
|
||||
print('graph_info Average network round trip time.')
|
||||
print('graph_category network')
|
||||
print('graph_vlabel ms')
|
||||
print_labels(stats['monitor'])
|
||||
|
||||
print('multigraph foomuuri_monitor_loss')
|
||||
print('graph_title Foomuuri Monitor Ping Packet Loss')
|
||||
print('graph_info Average ping packet loss.')
|
||||
print('graph_category network')
|
||||
print('graph_vlabel %')
|
||||
print('graph_args --lower-limit 0')
|
||||
print_labels(stats['monitor'], warning='5')
|
||||
|
||||
print('multigraph foomuuri_monitor_status')
|
||||
print('graph_title Foomuuri Monitor Target Status')
|
||||
print('graph_info Current status: 0=down, 1=up.')
|
||||
print('graph_category network')
|
||||
print('graph_vlabel status')
|
||||
print('graph_args --lower-limit 0 --upper-limit 1')
|
||||
print_labels(stats['monitor'], warning='1:')
|
||||
|
||||
if 'set' in stats:
|
||||
print('multigraph foomuuri_set_size')
|
||||
print('graph_title Foomuuri Set Size')
|
||||
print('graph_info Number of elements in set.')
|
||||
print('graph_category network')
|
||||
print('graph_vlabel elements')
|
||||
print_labels(stats['set'])
|
||||
|
||||
if 'counter' in stats:
|
||||
print('multigraph foomuuri_counter_bytes')
|
||||
print('graph_title Foomuuri Counter Bytes')
|
||||
print('graph_info Counter bytes value.')
|
||||
print('graph_category network')
|
||||
print('graph_vlabel bytes')
|
||||
print('graph_args --base 1024')
|
||||
print_labels(stats['counter'], derive=True)
|
||||
|
||||
print('multigraph foomuuri_counter_packets')
|
||||
print('graph_title Foomuuri Counter Packets')
|
||||
print('graph_info Counter packets value.')
|
||||
print('graph_category network')
|
||||
print('graph_vlabel packets')
|
||||
print_labels(stats['counter'], derive=True)
|
||||
|
||||
if os.environ.get('MUNIN_CAP_DIRTYCONFIG') == '1':
|
||||
fetch(stats)
|
||||
|
||||
|
||||
def fetch(stats):
|
||||
"""Print plugin values."""
|
||||
# pylint: disable=too-many-branches
|
||||
if 'monitor' in stats:
|
||||
print('multigraph foomuuri_monitor_time')
|
||||
for name, value in stats['monitor'].items():
|
||||
times = [item for item in value['time'] if item is not None]
|
||||
if not times: # No stats or 100% loss
|
||||
print(f'{safename(name)}.value U')
|
||||
else:
|
||||
print(f'{safename(name)}.value {sum(times) / len(times)}')
|
||||
|
||||
print('multigraph foomuuri_monitor_loss')
|
||||
for name, value in stats['monitor'].items():
|
||||
if not value['time']: # No stats
|
||||
print(f'{safename(name)}.value U')
|
||||
else:
|
||||
loss = sum(1 for item in value['time'] if item is None)
|
||||
print(f'{safename(name)}.value '
|
||||
f'{loss * 100 / len(value["time"])}')
|
||||
|
||||
print('multigraph foomuuri_monitor_status')
|
||||
for name, value in stats['monitor'].items():
|
||||
print(f'{safename(name)}.value {int(value["state"])}')
|
||||
|
||||
if 'set' in stats:
|
||||
print('multigraph foomuuri_set_size')
|
||||
for name, value in stats['set'].items():
|
||||
print(f'{safename(name)}.value {value}')
|
||||
|
||||
if 'counter' in stats:
|
||||
print('multigraph foomuuri_counter_bytes')
|
||||
for name, value in stats['counter'].items():
|
||||
print(f'{safename(name)}.value {value["bytes"]}')
|
||||
|
||||
print('multigraph foomuuri_counter_packets')
|
||||
for name, value in stats['counter'].items():
|
||||
print(f'{safename(name)}.value {value["packets"]}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'autoconf':
|
||||
print('yes' if read_stats() else 'no (Foomuuri is not running)')
|
||||
elif len(sys.argv) > 1 and sys.argv[1] == 'config':
|
||||
config(read_stats())
|
||||
else:
|
||||
fetch(read_stats())
|
Loading…
Add table
Add a link
Reference in a new issue