feature: the status page shows the Router Manager's version.
Release / release (push) Successful in 12s

This commit is contained in:
slawek committed 2026-10-24 12:16:02 +02:00
1 parent af3127d1e8
commit 17331eea37
3 files changed
+35 -7

No files matched your search

+4 -2
View File
@@ -526,10 +526,12 @@ curl http://10.0.0.4:17081/
| `/users` | The users of OpenVPN and road-warrior access; needs a token | | `/users` | The users of OpenVPN and road-warrior access; needs a token |
| `/groups` | The groups of users; needs a token | | `/groups` | The groups of users; needs a token |
The status holds the state of `vpn-router-setup` and `slapd`, of `strongswan` when site-to-site or The status holds the state of `vpn-router-setup`, `slapd` and each PostgreSQL cluster unit
(`postgresql@<version>-<cluster>`, or `postgresql` as `no cluster` without one), of `strongswan` when site-to-site or
road-warrior access is configured, of `wg-quick@wg0` when WireGuard is, and of road-warrior access is configured, of `wg-quick@wg0` when WireGuard is, and of
`openvpn-server@vpn-router` when OpenVPN is; the number of connected `openvpn-server@vpn-router` when OpenVPN is; the number of connected
OpenVPN clients, from the server's status file, which OpenVPN rewrites every minute; the package version; whether OpenVPN clients, from the server's status file, which OpenVPN rewrites every minute; the package version and,
as `manager_version`, the installed version of `vpn-router-manager` (`null`, shown as not installed, without it); whether
Docker is installed, and when it is, the state of `docker.service` and of `vpn-router-docker` Docker is installed, and when it is, the state of `docker.service` and of `vpn-router-docker`
(the Docker rules), which do not change `status`; whether the (the Docker rules), which do not change `status`; whether the
site-to-site tunnel is established; the number of connected road-warrior (IPsec P2S) clients; and site-to-site tunnel is established; the number of connected road-warrior (IPsec P2S) clients; and
+11
View File
@@ -1,3 +1,14 @@
vpn-router (0.11.0-1) unstable; urgency=medium
feature: the status page shows the Router Manager's version.
* / and /status show the installed version of vpn-router-manager, as
manager_version in JSON, or that it is not installed.
* The services show the state of each PostgreSQL cluster, as
postgresql@<version>-<cluster>, or postgresql: no cluster without one.
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Sun, 25 Oct 2026 09:00:00 +0200
vpn-router (0.10.0-1) unstable; urgency=medium vpn-router (0.10.0-1) unstable; urgency=medium
feature: Manager-only accounts, and the Router Manager's first administrator. feature: Manager-only accounts, and the Router Manager's first administrator.
+20 -5
View File
@@ -26,7 +26,8 @@ served (404) while the key does not exist. /auth is limited to AUTH_LIMIT calls
address in AUTH_WINDOW seconds; the address of a call from one of web.trusted_proxies, by address in AUTH_WINDOW seconds; the address of a call from one of web.trusted_proxies, by
default the address the service listens on, is the last entry of its X-Forwarded-For header. default the address the service listens on, is the last entry of its X-Forwarded-For header.
/ and /status show only the status: whether the services run, the package version, whether / and /status show only the status: whether the services run, the package version and the
installed version of vpn-router-manager (manager_version, null when it is not installed), whether
Docker is installed, and the state of site-to-site, road-warrior (IPsec P2S), OpenVPN and Docker is installed, and the state of site-to-site, road-warrior (IPsec P2S), OpenVPN and
WireGuard. No configuration data, key or address is shown. WireGuard. No configuration data, key or address is shown.
@@ -143,9 +144,10 @@ def unit_state(unit):
return result.stdout.strip() if result and result.stdout.strip() else 'unknown' return result.stdout.strip() if result and result.stdout.strip() else 'unknown'
def package_version(): def package_version(package='vpn-router'):
result = run('dpkg-query', '-W', '-f=${Version}', 'vpn-router') """The installed version of the package, or None when it is not installed."""
return result.stdout.strip() if result and result.returncode == 0 else None result = run('dpkg-query', '-W', '-f=${Version}', package)
return (result.stdout.strip() or None) if result and result.returncode == 0 else None
def docker_status(): def docker_status():
@@ -239,9 +241,20 @@ def openvpn_clients():
return None return None
def postgresql_clusters():
"""The state of each PostgreSQL cluster unit (postgresql@<version>-<name>), or {'postgresql': 'no cluster'} without one.
postgresql.service, which only runs /bin/true, is not reported.
"""
lines = lines_of('systemctl', 'list-units', 'postgresql@*.service', '--all', '--plain', '--no-legend') or []
names = [line.split()[0].removesuffix('.service') for line in lines if line.strip()]
return {name: unit_state(f'{name}.service') for name in names} or {'postgresql': 'no cluster'}
def collect(state): def collect(state):
"""The status document. state says which features the router has.""" """The status document. state says which features the router has."""
units = {'vpn-router-setup': unit_state('vpn-router-setup.service'), 'slapd': unit_state('slapd.service')} units = {'vpn-router-setup': unit_state('vpn-router-setup.service'), 'slapd': unit_state('slapd.service'),
**postgresql_clusters()}
if state.get('site_to_site') or state.get('p2s'): if state.get('site_to_site') or state.get('p2s'):
units['strongswan'] = unit_state('strongswan.service') units['strongswan'] = unit_state('strongswan.service')
if state.get('wireguard'): if state.get('wireguard'):
@@ -252,6 +265,7 @@ def collect(state):
status = { status = {
'status': 'ok' if all(value == 'active' for value in units.values()) else 'degraded', 'status': 'ok' if all(value == 'active' for value in units.values()) else 'degraded',
'version': package_version(), 'version': package_version(),
'manager_version': package_version('vpn-router-manager'),
'time': time.strftime('%Y-%m-%dT%H:%M:%S%z'), 'time': time.strftime('%Y-%m-%dT%H:%M:%S%z'),
'units': units, 'units': units,
'docker': docker_status(), 'docker': docker_status(),
@@ -327,6 +341,7 @@ def details(state):
def text_of(status): def text_of(status):
"""The status for people, as plain text.""" """The status for people, as plain text."""
lines = ['VPN Router', f'Status: {status["status"]}', f'Version: {status["version"] or "unknown"}', ''] lines = ['VPN Router', f'Status: {status["status"]}', f'Version: {status["version"] or "unknown"}', '']
lines.append(f'Router Manager: {status["manager_version"] or "not installed"}')
lines += [f'{name}: {value}' for name, value in status['units'].items()] lines += [f'{name}: {value}' for name, value in status['units'].items()]
docker = status['docker'] docker = status['docker']
lines.append('Docker: not installed' if not docker['installed'] lines.append('Docker: not installed' if not docker['installed']