Skip to content

Commit

Permalink
ffh.mesh_wireguard: add statistics export
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeFetch committed Jan 31, 2021
1 parent b2e3309 commit 5d22e24
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
91 changes: 91 additions & 0 deletions roles/ffh.mesh_wireguard/files/bin/ffh_wg_stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python3
from datetime import datetime, timedelta
from json import dumps as json_dumps
from pyroute2 import WireGuard
import argparse, os

TIMEOUT = timedelta(minutes=3)

def get_stats(format, interface):
clients = WireGuard().info(interface)[0].WGDEVICE_A_PEERS.value

peers = []
established_peers_count = 0
for client in clients:
public_key = client.WGPEER_A_PUBLIC_KEY["value"].decode("utf-8")

# ignore dummy key
if public_key == (43 * "0" + "="):
continue

established = False
latest_handshake = client.WGPEER_A_LAST_HANDSHAKE_TIME["tv_sec"]
if datetime.now() - datetime.fromtimestamp(latest_handshake) < TIMEOUT:
established = True
established_peers_count += 1

peers.append({
"public_key" : public_key,
"latest_handshake" : latest_handshake,
"is_established" : established,
"rx_bytes" : int(client.WGPEER_A_RX_BYTES['value']),
"tx_bytes" : int(client.WGPEER_A_TX_BYTES['value']),
})

return {
"interface" : interface,
"peers" : peers,
"established_peers_count" : established_peers_count
}

def print_influx_format(stats):
timestamp = str(round(datetime.now().timestamp())) + "0" * 9

print("wireguard_device" +
",name=" + stats['interface'] +
",type=linux_kernel " +
"established_peers=" + str(stats['established_peers_count']) +
"i " + timestamp)
for peer in stats['peers']:
print("wireguard_peer,device=" + stats['interface'] +
",public_key=" + peer['public_key'] +
" last_handshake=" + str(peer['latest_handshake']) +
"i,rx_bytes=" + str(peer['rx_bytes']) +
"i,tx_bytes=" + str(peer['tx_bytes']) +
"i " + timestamp)

def check_iface_type(iface, type):
if not os.path.exists(f'/sys/class/net/{iface}'):
print(f'Iface {iface} does not exist! Exiting...')
exit(1)

with open(f'/sys/class/net/{iface}/uevent', 'r') as f:
for line in f.readlines():
l = line.replace('\n', '').split('=')
if l[0] == 'DEVTYPE' and l[1] != type:
print(f'Iface {iface} is wrong type! Should be {type}, but is {l[1]}. Exiting...')
exit(1)

if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Dump statistics of WireGuard interfaces')
parser.add_argument('-f', '--format', metavar='FORMAT', type=str,
help='allowed formats are: "json", "influx"')
parser.add_argument('-i', '--interface', metavar='IFACE', type=str, nargs='+',
help='the WireGuard interfaces', default=[])
args = parser.parse_args()

if len(args.interface) == 0:
print('Error: You need to specify at least one WireGuard interface.')
exit(1)

iface_stats = []
for i in range(len(args.interface)):
check_iface_type(args.interface[i], 'wireguard')
iface_stats.append(get_stats(args.format, args.interface[i]))

if args.format == "influx":
for stats in iface_stats:
print_influx_format(stats);
else:
print(json_dumps(iface_stats))

3 changes: 3 additions & 0 deletions roles/ffh.mesh_wireguard/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@

- name: Establish netlink worker
include_tasks: netlink.yml

- name: Setup statistics export
include_tasks: stats.yml
25 changes: 25 additions & 0 deletions roles/ffh.mesh_wireguard/tasks/stats.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---

- name: Install ffh_wg_stats.py files
copy:
src: "bin/ffh_wg_stats.py"
dest: "/usr/bin/"
owner: "root"
mode: 0755

- name: Check telegraf path
stat:
path: /etc/telegraf/telegraf.d/
register: telegraf_path

- name: Ensure telegraf path exists
shell: mkdir -p /etc/telegraf/telegraf.d/
when: telegraf_path is defined and telegraf_path.stat.exists==false

# We do not care whether telegraf is really installed. So it could be installed
# later (or also never).
- name: Set /etc/telegraf/telegraf.d/mesh_wg_stats.conf
notify: Maybe restart telegraf # handler from ffh.routingnode
template:
src: telegraf_mesh_wg_stats.conf.j2
dest: /etc/telegraf/telegraf.d/mesh_wg_stats.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[inputs.exec]]
commands = ["/usr/bin/ffh_wg_stats.py -f influx -i{% for domain in domains | default( [] ) %} wg-{{ domain.id }}{% endfor %}"]
data_format = "influx"

0 comments on commit 5d22e24

Please sign in to comment.