feature: site_to_site holds any number of named site-to-site connections, which /site-to-site lists, adds, changes and removes.
Release / release (push) Successful in 12s
Release / release (push) Successful in 12s
This commit is contained in:
1 parent
a79510a02f
commit
4a5b15a559
22 files changed
+843
-351
No files matched your search
@@ -8,9 +8,10 @@ Every SAMPLE_SECONDS, on the minute, a sample is taken with psutil: the CPU util
|
||||
previous sample, the memory used and in total, the free and the total space of /, the bytes
|
||||
received and sent per second on the external and the internal interface, and the load averages;
|
||||
and the VPN clients of each enabled VPN system (vpnrouter_status): road-warrior (p2s) and
|
||||
OpenVPN clients, WireGuard peers with a recent handshake, and the site-to-site tunnel, 1 while it
|
||||
is up. The interfaces and the enabled systems are those vpn-router-setup resolved, read from
|
||||
/run/vpn-router/web.json.
|
||||
OpenVPN clients and WireGuard peers with a recent handshake; and of each site-to-site connection
|
||||
that is set up, whether it is up, the bytes and packets per second through its child SAs since
|
||||
the previous sample, and how long its IKE SA has been up. The interfaces, the enabled systems and
|
||||
the connections are those vpn-router-setup resolved, read from /run/vpn-router/web.json.
|
||||
|
||||
The sample is written to the detail tables of vpnrouter_metrics. When the clock has passed into
|
||||
a new hour, day, month or year, the complete periods are summarized, and once a day, after the
|
||||
@@ -105,9 +106,6 @@ def clients(state):
|
||||
counts['openvpn'] = vpnrouter_status.openvpn_clients()
|
||||
if state.get('wireguard'):
|
||||
counts['wireguard'] = vpnrouter_status.wireguard_connected()
|
||||
if state.get('site_to_site'):
|
||||
count = vpnrouter_status.established('remote-site')
|
||||
counts['site_to_site'] = None if count is None else int(count > 0)
|
||||
return counts
|
||||
|
||||
|
||||
@@ -121,6 +119,8 @@ def sample(previous):
|
||||
memory = psutil.virtual_memory()
|
||||
disk = psutil.disk_usage(MOUNTPOINT)
|
||||
load1, load5, load15 = os.getloadavg()
|
||||
connections = state.get('site_to_site')
|
||||
tunnels = vpnrouter_status.site_to_site_tunnels(connections) if isinstance(connections, list) and connections else {}
|
||||
now = time.time()
|
||||
current = {
|
||||
'time': now,
|
||||
@@ -138,13 +138,26 @@ def sample(previous):
|
||||
'counters': {name: (counters[name].bytes_recv, counters[name].bytes_sent) for name in names if name in counters},
|
||||
'clients': clients(state),
|
||||
'rates': {},
|
||||
'tunnels': tunnels or {},
|
||||
'site_to_site': {},
|
||||
}
|
||||
if previous is not None:
|
||||
elapsed = current['monotonic'] - previous['monotonic']
|
||||
elapsed = current['monotonic'] - previous['monotonic'] if previous is not None else 0
|
||||
if elapsed > 0:
|
||||
for name, (received, sent) in current['counters'].items():
|
||||
if name in previous['counters'] and elapsed > 0:
|
||||
if name in previous['counters']:
|
||||
before_received, before_sent = previous['counters'][name]
|
||||
current['rates'][name] = (max(received - before_received, 0) / elapsed, max(sent - before_sent, 0) / elapsed)
|
||||
# A connection's rates need its counters of the previous sample; a counter that went down was rekeyed and counts from zero.
|
||||
for name, tunnel in current['tunnels'].items():
|
||||
before = previous['tunnels'].get(name) if elapsed > 0 else None
|
||||
values = {'up': tunnel['up'], 'uptime': tunnel['uptime']}
|
||||
for value, counter in (('rx', 'bytes_in'), ('tx', 'bytes_out'), ('packets_rx', 'packets_in'), ('packets_tx', 'packets_out')):
|
||||
if before is None:
|
||||
values[value] = None
|
||||
else:
|
||||
count = tunnel[counter]
|
||||
values[value] = (count - before[counter] if count >= before[counter] else count) / elapsed
|
||||
current['site_to_site'][name] = values
|
||||
return current
|
||||
|
||||
|
||||
@@ -162,7 +175,7 @@ def store(cfg, current, done):
|
||||
"""
|
||||
now = periods(datetime.datetime.now(datetime.timezone.utc))
|
||||
with vpnrouter_metrics.database(cfg) as connection:
|
||||
vpnrouter_metrics.write(connection, current['system'], current['rates'], current['clients'])
|
||||
vpnrouter_metrics.write(connection, current['system'], current['rates'], current['clients'], current['site_to_site'])
|
||||
for level, _, _ in vpnrouter_metrics.LEVELS:
|
||||
if done.get(level) != now[level]:
|
||||
vpnrouter_metrics.summarize(connection, level)
|
||||
@@ -200,6 +213,17 @@ def otlp_request(current, started):
|
||||
gauge('system.cpu.load_average.5m', '{thread}', [(system['load5'], {})]),
|
||||
gauge('system.cpu.load_average.15m', '{thread}', [(system['load15'], {})]),
|
||||
gauge('vpn_router.clients', '{client}', [(count, {'kind': kind}) for kind, count in current['clients'].items()]),
|
||||
gauge('vpn_router.site_to_site.up', '1', [(values['up'], {'connection': name})
|
||||
for name, values in current['site_to_site'].items()]),
|
||||
gauge('vpn_router.site_to_site.uptime', 's', [(values['uptime'], {'connection': name})
|
||||
for name, values in current['site_to_site'].items()]),
|
||||
gauge('vpn_router.site_to_site.io', 'By/s', [(values[value], {'connection': name, 'direction': direction})
|
||||
for name, values in current['site_to_site'].items()
|
||||
for value, direction in (('rx', 'receive'), ('tx', 'transmit'))]),
|
||||
gauge('vpn_router.site_to_site.packets', '{packet}/s',
|
||||
[(values[value], {'connection': name, 'direction': direction})
|
||||
for name, values in current['site_to_site'].items()
|
||||
for value, direction in (('packets_rx', 'receive'), ('packets_tx', 'transmit'))]),
|
||||
{'name': 'system.network.io', 'unit': 'By', 'sum': {
|
||||
'aggregationTemporality': 2, 'isMonotonic': True, 'dataPoints': [
|
||||
{'startTimeUnixNano': start, 'timeUnixNano': stamp, 'asInt': str(value),
|
||||
@@ -295,12 +319,30 @@ class Sample:
|
||||
network.add_metric([name, 'receive'], received)
|
||||
network.add_metric([name, 'transmit'], sent)
|
||||
yield network
|
||||
vpn = GaugeMetricFamily('vpn_router_clients', 'Connected VPN clients; site_to_site is 1 while the tunnel is up',
|
||||
labels=['kind'])
|
||||
vpn = GaugeMetricFamily('vpn_router_clients', 'Connected VPN clients', labels=['kind'])
|
||||
for kind, count in self.current['clients'].items():
|
||||
if count is not None:
|
||||
vpn.add_metric([kind], count)
|
||||
yield vpn
|
||||
tunnels = self.current['site_to_site']
|
||||
up = GaugeMetricFamily('vpn_router_site_to_site_up', 'Whether the site-to-site connection is established, 1 or 0',
|
||||
labels=['connection'])
|
||||
uptime = GaugeMetricFamily('vpn_router_site_to_site_uptime_seconds', 'Seconds the IKE SA of the site-to-site connection has been up',
|
||||
labels=['connection'])
|
||||
io = GaugeMetricFamily('vpn_router_site_to_site_io_bytes_per_second',
|
||||
'Bytes per second received and sent through the site-to-site connection', labels=['connection', 'direction'])
|
||||
packets = GaugeMetricFamily('vpn_router_site_to_site_packets_per_second',
|
||||
'Packets per second received and sent through the site-to-site connection',
|
||||
labels=['connection', 'direction'])
|
||||
for name, values in tunnels.items():
|
||||
up.add_metric([name], values['up'])
|
||||
if values['uptime'] is not None:
|
||||
uptime.add_metric([name], values['uptime'])
|
||||
for family, received, sent in ((io, 'rx', 'tx'), (packets, 'packets_rx', 'packets_tx')):
|
||||
for value, direction in ((received, 'receive'), (sent, 'transmit')):
|
||||
if values[value] is not None:
|
||||
family.add_metric([name, direction], values[value])
|
||||
yield from (up, uptime, io, packets)
|
||||
|
||||
|
||||
def authorized(header, account):
|
||||
|
||||
Reference in new issue
Block a user