Monitor AP Wi-Fi Status

CheckMK plugin to monitor APs
Closes #12
This commit is contained in:
Albert Stefanov 2023-10-25 11:19:28 +03:00
parent 0ec63d56dd
commit ad746e3fea
8 changed files with 235 additions and 0 deletions

View File

@ -0,0 +1,5 @@
*.mkp
.coverage
__pycache__
*.log
dist/*

View File

@ -0,0 +1,29 @@
# CheckMK extension for monitoring the Wi-Fi interface status @openfest.org
## Description
Monitors several 802.11 interface parameters:
- Associated station count
- Noise Floor
- Channel Usage (channel busy time / total channel time)
## Building
We use a simple library to pack the extension into a `.mkp` file without setting up a full CheckMK development server.
```bash
pip install -r requirements.txt
./build.py
```
The build artifacts are at `dist/`.
## Deployment
Copy the `mkp` file to the monitoring server and execute:
```bash
mkp install [output_file].mkp
mkp enable [plugin_name] [version]
```

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
from .agent_based_api.v1 import *
def check_wifi_status(item, section):
print(item)
print(section)
for interface in section:
if interface['name'] == item:
usage = interface['delta_ch_time_busy'] / interface['delta_ch_time'] * 100
yield Metric("delta_ch_time", interface['delta_ch_time_busy'])
yield Metric("delta_ch_time_busy", interface['delta_ch_time_busy'])
yield Metric("channel_usage", usage, levels=(0,100))
yield Metric("noise_floor", interface['noise'], levels=(-120,0))
yield Metric("client_count", interface['client_count'], levels=(0,None))
if usage < 30:
yield Result(state = State.OK, summary = f"Clients: {interface['client_count']}, Channel usage: {usage:.02f}%")
elif usage < 60:
yield Result(state = State.WARN, summary = f"Clients: {interface['client_count']}, Channel usage: {usage:.02f}%")
else:
yield Result(state = State.CRIT, summary = f"Clients: {interface['client_count']}, Channel usage: {usage:.02f}%")
def discover_wifi_status(section):
print(section)
for interface in section:
yield Service(item=interface['name'])
def parse_wifi_interfaces(string_table):
# format: "$interface;$ch_time;$ch_time_busy;$noise;$delta_ch_time;$delta_ch_time_busy,$client_count"
return [{
'name': row[0],
'ch_time' : int(row[1]),
'ch_time_busy' : int(row[2]),
'noise' : int(row[3]),
'delta_ch_time' : int(row[4]),
'delta_ch_time_busy' : int(row[5]),
'client_count' : int(row[6]),
} for row in string_table]
register.agent_section(
name = "wifi_interfaces",
parse_function = parse_wifi_interfaces,
)
register.check_plugin(
name="wifi_interface_status",
service_name="Wi-Fi Interface %s",
discovery_function=discover_wifi_status,
sections=['wifi_interfaces'],
check_function=check_wifi_status
)

View File

@ -0,0 +1,37 @@
#!/bin/sh
CACHE_FILE=/usr/lib/check_mk_agent/plugins/wifi_interfaces.cache
echo "<<<wifi_interfaces:sep(59)>>>" # 59 = ascii semi-colon (;)
interfaces=$(ls /sys/class/net | grep -iE 'phy.+')
# Create empty file if it does not exist
# First plugin run may produce garbage data or not run at all, which is OK
# Cache file format: $interface,$time,$busy
touch $CACHE_FILE
cached_output="$(cat "$CACHE_FILE")"
echo -n "" > "$CACHE_FILE"
for interface in $interfaces
do
ch_time_old="$(echo "$cached_output" | awk -v interface="$interface" -F';' '$1 ~ interface { print $2 }')"
ch_time_busy_old="$(echo "$cached_output" | awk -v interface="$interface" -F';' '$1 ~ interface { print $3 }')"
output="$(ethtool -S "$interface")"
ch_time="$(echo "$output" | awk -F ': ' '/ch_time:/{ print $2 }')"
ch_time_busy="$(echo "$output" | awk -F ': ' '/ch_time_busy:/{ print $2 }')"
echo "$interface;$ch_time;$ch_time_busy" >> "$CACHE_FILE"
# The noise is represented as an unsigned byte, we need a signed one. Thus, we subtract 2**7.
noise="$(expr $(echo "$output" | awk -F ': ' '/noise:/{ print $2 }') - 256)"
client_count="$(iw dev $interface station dump | wc -l)"
# We calculate the deltas to use for alarms locally; fields are u64
delta_ch_time=$(expr $(expr $ch_time - $ch_time_old) % 18446744073709551616)
delta_ch_time_busy=$(expr $(expr $ch_time_busy - $ch_time_busy_old) % 18446744073709551616)
echo "$interface;$ch_time;$ch_time_busy;$noise;$delta_ch_time;$delta_ch_time_busy;$client_count"
done

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python3
import mkp
mkp.dist({'author': 'Albert Stefanov <aastefanov@outlook.com>',
'description': 'Agent-based plugin for checking OpenWRT Wi-Fi interfaces status, for use @openfest.org',
'name': 'wifi_interfaces',
'title': 'OpenWRT Wi-Fi Interfaces',
'download_url': 'https://github.com/openfest/openfest-network-2023',
'version': '0.0.1',
'version.min_required': '2.0.0',
},
path='.')

View File

@ -0,0 +1 @@
mkp @ git+https://github.com/inettgmbh/python-mkp@directories

View File

@ -0,0 +1,75 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cmk.utils.render
from cmk.gui.i18n import _
from cmk.gui.plugins.metrics.utils import (
graph_info,
indexed_color,
metric_info,
parse_color_into_hexrgb,
)
metric_info["channel_usage"] = {
"title": _("Channel Usage"),
"unit": "%",
"color": "11/a",
}
metric_info["noise_floor"] = {
"title": _("Noise Floor"),
"unit": "db",
"color": "11/b",
}
metric_info["delta_ch_time"] = {
"title": _("Channel Time delta"),
"unit": "",
"color": "33/a",
}
metric_info["delta_ch_time_busy"] = {
"title": _("Channel Busy Time delta"),
"unit": "",
"color": "13/a",
}
metric_info["client_count"] = {
"title": _("Client Count"),
"unit": "count",
"color": "13/b",
}
graph_info["channel_usage"] = {
"title": _("Channel Usage"),
"metrics": [
("channel_usage", "line")
],
"range": (0, 100),
}
graph_info["client_count"] = {
"title": _("Client Count"),
"metrics": [
("client_count", "line")
],
}
graph_info["noise_floor"] = {
"title": _("Noise Floor"),
"metrics": [
("noise_floor", "line")
],
"range": (-120, 0),
}
graph_info["channel_times"] = {
"title": _("Channel Times"),
"metrics": [
("delta_ch_time", "stack"),
("delta_ch_time_busy", "stack")
],
}

View File

@ -0,0 +1,22 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from cmk.gui.plugins.metrics import (
perfometer_info
)
perfometer_info.append({
'type': 'dual',
'perfometers': [
{
'type': 'linear',
'segments': ['client_count'],
'total': 1000,
},
{
'type': 'linear',
'segments': ['channel_usage'],
'total': 100,
},
],
})