This repository has no description
3.3 kB
114 lines
1# Hourly speedtest from acheron, replacing Home Assistant's SpeedTest
2# integration: speedtest.net geolocates our Vodafone IP near Sicily, so HA
3# only offered servers in Italy/Tunisia/Algeria, and its single-threaded
4# Python client collapsed on their 500+ ms latency (42 Mbit/s on a 1000/50
5# line). speedtest-go runs parallel connections against a German server.
6#
7# Each run appends one JSON line to results.jsonl (also the history); the
8# Vector agent tails it into VictoriaMetrics. A run moves ~1.4 GB and
9# saturates the line for ~30 s, hence hourly and not more often.
10{
11 config,
12 lib,
13 pkgs,
14 ...
15}:
16let
17 dir = "/var/lib/speedtest";
18in
19{
20 # Static user: a DynamicUser's state lives under /var/lib/private (0700),
21 # where Vector (itself a DynamicUser) can't read it.
22 users.users.speedtest = {
23 isSystemUser = true;
24 group = "speedtest";
25 };
26 users.groups.speedtest = { };
27
28 systemd.services.speedtest = {
29 description = "Speedtest against a German speedtest.net server";
30 after = [ "network-online.target" ];
31 wants = [ "network-online.target" ];
32 serviceConfig = {
33 Type = "oneshot";
34 User = "speedtest";
35 Group = "speedtest";
36 StateDirectory = "speedtest";
37 StateDirectoryMode = "0755";
38 UMask = "0022";
39 TimeoutStartSec = "5min";
40 };
41 script = ''
42 ${lib.getExe pkgs.speedtest-go} --jsonl --filter-cc DE >> ${dir}/results.jsonl
43 '';
44 };
45
46 systemd.timers.speedtest = {
47 wantedBy = [ "timers.target" ];
48 timerConfig = {
49 OnCalendar = "hourly";
50 RandomizedDelaySec = "10min";
51 };
52 };
53
54 monitoring.extraMetrics = [ "speedtest_metrics" ];
55
56 services.vector.settings = {
57 sources.speedtest_raw = {
58 type = "file";
59 include = [ "${dir}/results.jsonl" ];
60 };
61 # speedtest-go: speeds in bytes/s, latencies in ns
62 transforms.speedtest = {
63 type = "remap";
64 inputs = [ "speedtest_raw" ];
65 source = ''
66 r = parse_json!(.message)
67 s = object!(r.server)
68 . = {
69 "download": to_float!(s.dl_speed) * 8,
70 "upload": to_float!(s.ul_speed) * 8,
71 "latency": to_float!(s.latency) / 1000000000,
72 "jitter": to_float!(s.jitter) / 1000000000,
73 "server": string!(s.sponsor) + " " + string!(s.name),
74 "server_id": string!(s.id),
75 }
76 '';
77 drop_on_error = true;
78 };
79 transforms.speedtest_metrics = {
80 type = "log_to_metric";
81 inputs = [ "speedtest" ];
82 metrics =
83 map
84 (m: {
85 type = "gauge";
86 field = m.field;
87 name = "speedtest_${m.name}";
88 tags = {
89 host = config.networking.hostName;
90 server = "{{server}}";
91 server_id = "{{server_id}}";
92 };
93 })
94 [
95 {
96 field = "download";
97 name = "download_bits_per_second";
98 }
99 {
100 field = "upload";
101 name = "upload_bits_per_second";
102 }
103 {
104 field = "latency";
105 name = "latency_seconds";
106 }
107 {
108 field = "jitter";
109 name = "jitter_seconds";
110 }
111 ];
112 };
113 };
114}