check_bandwidth: add regex ignore and better timing
check_opnsense: restrict to internet, better timing
This commit is contained in:
parent
cf2a48ca6e
commit
6fdc67eb43
|
@ -1,6 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import argparse
|
import argparse
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
@ -13,10 +15,49 @@ parser.add_argument('--bandwidth', type=float, required=True, help='Bandwidth sp
|
||||||
parser.add_argument('--critical', type=int, default=75, help='Critical if percent of bandwidth usage is greater than or equal to this.')
|
parser.add_argument('--critical', type=int, default=75, help='Critical if percent of bandwidth usage is greater than or equal to this.')
|
||||||
parser.add_argument('--warn', type=int, default=50, help='Warning if percent of bandwidth usage is greater than or equal to this.')
|
parser.add_argument('--warn', type=int, default=50, help='Warning if percent of bandwidth usage is greater than or equal to this.')
|
||||||
parser.add_argument('--max', type=int, default=None, help='Set the max value the bandwidth can be. Useful for graphs and whatever.')
|
parser.add_argument('--max', type=int, default=None, help='Set the max value the bandwidth can be. Useful for graphs and whatever.')
|
||||||
parser.add_argument('--ignore', default=None, help='Interface names to ignore.')
|
parser.add_argument('--ignore', nargs='*', default=[], help='Interface names to ignore, separated by a space.')
|
||||||
|
parser.add_argument('--ignore-re', default=None, help='Regex matching interface names to ignore.')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
ignore_interfaces = args.ignore.split(',') if args.ignore else []
|
if args.ignore_re:
|
||||||
|
ignore_re = re.compile(args.ignore_re)
|
||||||
|
else:
|
||||||
|
ignore_re = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_traffic(interface):
|
||||||
|
net_io = psutil.net_io_counters(pernic=True)
|
||||||
|
if interface in net_io:
|
||||||
|
return net_io[interface]
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Interface '{interface}' not found")
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_network_traffic(interface, interval=1):
|
||||||
|
initial_traffic = get_network_traffic(interface)
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
|
||||||
|
# Should be more accurate that time.sleep()
|
||||||
|
while True:
|
||||||
|
current_time = time.perf_counter()
|
||||||
|
elapsed_time = current_time - start_time
|
||||||
|
if elapsed_time >= interval:
|
||||||
|
break
|
||||||
|
|
||||||
|
final_traffic = get_network_traffic(interface)
|
||||||
|
|
||||||
|
sent_bytes = final_traffic.bytes_sent - initial_traffic.bytes_sent
|
||||||
|
recv_bytes = final_traffic.bytes_recv - initial_traffic.bytes_recv
|
||||||
|
|
||||||
|
sent_speed = sent_bytes / elapsed_time
|
||||||
|
recv_speed = recv_bytes / elapsed_time
|
||||||
|
|
||||||
|
# Convert bytes per second to megabits per second
|
||||||
|
sent_speed_mbps = sent_speed * 8 / (1024 * 1024)
|
||||||
|
recv_speed_mbps = recv_speed * 8 / (1024 * 1024)
|
||||||
|
|
||||||
|
return sent_speed_mbps, recv_speed_mbps
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
data = []
|
data = []
|
||||||
|
@ -28,23 +69,11 @@ def main():
|
||||||
|
|
||||||
# Calculate bandwidth utilization for each interface
|
# Calculate bandwidth utilization for each interface
|
||||||
for interface, stats in net_io_counters.items():
|
for interface, stats in net_io_counters.items():
|
||||||
if interface in ignore_interfaces:
|
if interface in args.ignore or (ignore_re and ignore_re.search(interface)):
|
||||||
continue
|
continue
|
||||||
# Get the number of bytes sent and received
|
sent_speed, recv_speed = calculate_network_traffic(interface)
|
||||||
bytes_sent = stats.bytes_sent
|
bandwidth_utilization = sent_speed + recv_speed
|
||||||
bytes_recv = stats.bytes_recv
|
data.append([interface, sent_speed, recv_speed, bandwidth_utilization, 'none'])
|
||||||
|
|
||||||
# Wait for 1 second
|
|
||||||
psutil.cpu_percent(interval=1)
|
|
||||||
|
|
||||||
# Get the number of bytes sent and received after 1 second
|
|
||||||
new_stats = psutil.net_io_counters(pernic=True)[interface]
|
|
||||||
new_bytes_sent = new_stats.bytes_sent
|
|
||||||
new_bytes_recv = new_stats.bytes_recv
|
|
||||||
|
|
||||||
# Calculate the bandwidth utilization in bits per second
|
|
||||||
bandwidth_utilization = (8 * (new_bytes_sent - bytes_sent + new_bytes_recv - bytes_recv)) / (1 * 1000 * 1000)
|
|
||||||
data.append([interface, bandwidth_utilization, 'none'])
|
|
||||||
|
|
||||||
exit_code = nagios.OK
|
exit_code = nagios.OK
|
||||||
critical = []
|
critical = []
|
||||||
|
@ -53,7 +82,7 @@ def main():
|
||||||
perf_data = []
|
perf_data = []
|
||||||
for i in range(len(data)):
|
for i in range(len(data)):
|
||||||
interface = data[i][0]
|
interface = data[i][0]
|
||||||
bandwidth_utilization = data[i][1]
|
bandwidth_utilization = data[i][3]
|
||||||
if bandwidth_utilization >= crit_value:
|
if bandwidth_utilization >= crit_value:
|
||||||
critical.append(interface)
|
critical.append(interface)
|
||||||
state = 'critical'
|
state = 'critical'
|
||||||
|
@ -67,7 +96,7 @@ def main():
|
||||||
ok.append(interface)
|
ok.append(interface)
|
||||||
state = 'ok'
|
state = 'ok'
|
||||||
data[i][2] = f'[{state.upper()}]'
|
data[i][2] = f'[{state.upper()}]'
|
||||||
perf_data.append(f'{interface}={round(bandwidth_utilization, 2)}MB;{warn_value};{crit_value};{f"0;{args.max};" if args.max else ""} ')
|
perf_data.append(f'{interface}={round(bandwidth_utilization, 2)}Mbps;{warn_value};{crit_value};{f"0;{args.max};" if args.max else ""} ')
|
||||||
|
|
||||||
if len(ok):
|
if len(ok):
|
||||||
print(f'OK: {", ".join(ok)}')
|
print(f'OK: {", ".join(ok)}')
|
||||||
|
|
|
@ -3,6 +3,7 @@ import argparse
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
from ipaddress import ip_address, ip_network
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import requests
|
import requests
|
||||||
|
@ -13,6 +14,25 @@ from checker.markdown import list_to_markdown_table
|
||||||
from checker.units import filesize
|
from checker.units import filesize
|
||||||
|
|
||||||
|
|
||||||
|
def is_internet_traffic(ip):
|
||||||
|
private_networks = [
|
||||||
|
ip_network("10.0.0.0/8"),
|
||||||
|
ip_network("172.16.0.0/12"),
|
||||||
|
ip_network("192.168.0.0/16"),
|
||||||
|
]
|
||||||
|
return not any(ip in network for network in private_networks)
|
||||||
|
|
||||||
|
|
||||||
|
def get_traffic_top(args, interface):
|
||||||
|
response = requests.get(f'https://{args.opnsense}/api/diagnostics/traffic/top/{interface}',
|
||||||
|
headers={'Accept': 'application/json'}, auth=(args.key, args.secret), verify=False,
|
||||||
|
timeout=10)
|
||||||
|
if response.status_code != 200:
|
||||||
|
print(f'UNKNOWN: unable to query OPNsense API for {interface}: {response.status_code}\n{response.text}')
|
||||||
|
sys.exit(nagios.UNKNOWN)
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='Check OPNsense network traffic for a host.')
|
parser = argparse.ArgumentParser(description='Check OPNsense network traffic for a host.')
|
||||||
parser.add_argument('--opnsense', required=True, help='OPNsense hostname or IP address.')
|
parser.add_argument('--opnsense', required=True, help='OPNsense hostname or IP address.')
|
||||||
|
@ -55,19 +75,24 @@ def main():
|
||||||
|
|
||||||
for name, interface in interface_names.items():
|
for name, interface in interface_names.items():
|
||||||
# Fetch the data
|
# Fetch the data
|
||||||
# TODO: account for network delays for the check duration
|
|
||||||
traffic_data = []
|
traffic_data = []
|
||||||
for _ in range(args.duration):
|
for _ in range(args.duration):
|
||||||
|
start_time = time.time()
|
||||||
response = requests.get(f'https://{args.opnsense}/api/diagnostics/traffic/top/{interface}',
|
response = requests.get(f'https://{args.opnsense}/api/diagnostics/traffic/top/{interface}',
|
||||||
headers={'Accept': 'application/json'}, auth=(args.key, args.secret), verify=False,
|
headers={'Accept': 'application/json'}, auth=(args.key, args.secret), verify=False,
|
||||||
timeout=10)
|
timeout=10)
|
||||||
|
end_time = time.time()
|
||||||
|
api_request_time = end_time - start_time
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'UNKNOWN: unable to query OPNsense API for {interface}: {response.status_code}\n{response.text}')
|
print(f'UNKNOWN: unable to query OPNsense API for {interface}: {response.status_code}\n{response.text}')
|
||||||
sys.exit(nagios.UNKNOWN)
|
sys.exit(nagios.UNKNOWN)
|
||||||
for item in response.json().get(interface, {}).get('records', False):
|
for item in response.json().get(interface, {}).get('records', False):
|
||||||
if item['address'] == args.host:
|
if item['address'] == args.host:
|
||||||
traffic_data.append(item)
|
traffic_data.append(item)
|
||||||
time.sleep(1)
|
|
||||||
|
adjusted_sleep_duration = max(1 - api_request_time, 0)
|
||||||
|
time.sleep(adjusted_sleep_duration)
|
||||||
|
|
||||||
if not len(traffic_data) and args.fail_empty:
|
if not len(traffic_data) and args.fail_empty:
|
||||||
print('UNKNOWN: Interface or host not found in OPNsense API response. Raw response:')
|
print('UNKNOWN: Interface or host not found in OPNsense API response. Raw response:')
|
||||||
|
@ -154,7 +179,9 @@ def main():
|
||||||
perf_data.append(f'\'{name}_cumulative_out\'={int(data["cumulative_out"])}B;{warn_b_value};{crit_b_value};0;')
|
perf_data.append(f'\'{name}_cumulative_out\'={int(data["cumulative_out"])}B;{warn_b_value};{crit_b_value};0;')
|
||||||
perf_data.append(f'\'{name}_connections\'={int(data["connections"])}B;{warn_b_value};{crit_b_value};0;')
|
perf_data.append(f'\'{name}_connections\'={int(data["connections"])}B;{warn_b_value};{crit_b_value};0;')
|
||||||
|
|
||||||
output_table.append((args.host, name, filesize(data['rate_in']), filesize(data['rate_out']), filesize(data['cumulative_in']), filesize(data['cumulative_out']), data['connections'], status))
|
output_table.append((args.host, name, filesize(data['rate_in']), filesize(data['rate_out']),
|
||||||
|
filesize(data['cumulative_in']), filesize(data['cumulative_out']), data['connections'],
|
||||||
|
status))
|
||||||
|
|
||||||
if len(critical):
|
if len(critical):
|
||||||
x = ['CRITICAL: ']
|
x = ['CRITICAL: ']
|
||||||
|
|
Loading…
Reference in New Issue