feature: the web service creates its key and database itself and shows its starting phase.
Release / release (push) Successful in 29s
Release / release (push) Successful in 29s
This commit is contained in:
1 parent
4f1aa282f6
commit
2e2bacee7d
8 files changed
+245
-37
No files matched your search
@@ -17,11 +17,11 @@ import re
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
import vpnrouter
|
||||
import vpnrouter_auth
|
||||
import vpnrouter_ldap
|
||||
from vpnrouter import fail
|
||||
|
||||
@@ -30,6 +30,9 @@ UFW_DEFAULTS = pathlib.Path('/etc/default/ufw')
|
||||
WG_DIR = pathlib.Path('/etc/wireguard')
|
||||
WEB_STATE = pathlib.Path('/run/vpn-router/web.json')
|
||||
|
||||
#: The state, the current step and the failure of the last run, which the web service shows while it starts.
|
||||
SETUP_STATE = pathlib.Path('/run/vpn-router/setup.json')
|
||||
|
||||
#: The Router Manager, vpn-router-manager, when it is installed, and its settings.
|
||||
MANAGER = pathlib.Path('/usr/lib/vpn-router-manager/manager')
|
||||
MANAGER_CONFIG = pathlib.Path('/etc/vpn-router-manager/manager.json')
|
||||
@@ -359,16 +362,6 @@ def manage_directory():
|
||||
return ''
|
||||
|
||||
|
||||
def manage_tokens(cfg):
|
||||
"""Make the web service's signing key, and the database of its refresh tokens unless web.database names one; the problem, or ''."""
|
||||
try:
|
||||
vpnrouter_auth.ensure_key()
|
||||
vpnrouter_auth.provision(cfg)
|
||||
except Exception as exc:
|
||||
return f'the token database cannot be provisioned: {exc!r}'
|
||||
return ''
|
||||
|
||||
|
||||
def manage_openvpn(ctx, changed):
|
||||
"""Run the OpenVPN server when it is configured, and stop it when it is not."""
|
||||
unit = 'openvpn-server@vpn-router'
|
||||
@@ -444,25 +437,42 @@ def refresh_web(cfg, ctx):
|
||||
}) + '\n', encoding='utf-8')
|
||||
|
||||
|
||||
def progress(state, step, error=None):
|
||||
"""Record where setup is in SETUP_STATE: running, deferred, done or failed, the step, and the error of a failure."""
|
||||
SETUP_STATE.parent.mkdir(parents=True, exist_ok=True)
|
||||
SETUP_STATE.write_text(json.dumps({
|
||||
'state': state,
|
||||
'step': step,
|
||||
'error': error,
|
||||
'time': time.strftime('%Y-%m-%dT%H:%M:%S%z'),
|
||||
}) + '\n', encoding='utf-8')
|
||||
|
||||
|
||||
def main():
|
||||
progress('running', 'configuration')
|
||||
cfg = vpnrouter.load_config()
|
||||
ctx, changed = vpnrouter.configure(cfg)
|
||||
|
||||
if ctx is None:
|
||||
print('vpn-router: platform is none, configuration deferred; '
|
||||
f'set general.platform in {vpnrouter.CONFIG_FILE}')
|
||||
progress('deferred', 'configuration', f'general.platform is none; set it in {vpnrouter.CONFIG_FILE}')
|
||||
return 0
|
||||
|
||||
progress('running', 'routes')
|
||||
if vpnrouter.routing_ready(ctx):
|
||||
apply_routes(ctx)
|
||||
|
||||
if ctx['local_id_mode'] == 'public_ip' and ctx['local_fqdn']:
|
||||
progress('running', 'public address')
|
||||
address = resolve_public_ip(ctx['local_fqdn'])
|
||||
ctx, more = vpnrouter.configure(cfg, local_id_override=address)
|
||||
changed |= more
|
||||
|
||||
progress('running', 'WireGuard keys')
|
||||
setup_wireguard(ctx)
|
||||
|
||||
progress('running', 'firewall')
|
||||
rules_changed = setup_ufw(ctx)
|
||||
if is_configured(ctx):
|
||||
status = run(['ufw', 'status'], check=False)
|
||||
@@ -475,23 +485,52 @@ def main():
|
||||
elif rules_changed:
|
||||
run(['ufw', 'reload'], check=False)
|
||||
|
||||
progress('running', 'strongSwan')
|
||||
manage_strongswan(ctx, changed)
|
||||
progress('running', 'WireGuard')
|
||||
manage_wireguard(ctx, changed)
|
||||
|
||||
# The tunnels are up before the directory and the tokens, whose problems end setup only after every other step.
|
||||
problems = [problem for problem in (manage_directory(), manage_tokens(cfg)) if problem]
|
||||
# The tunnels are up before the directory, whose problem ends setup only after every other step.
|
||||
progress('running', 'user directory')
|
||||
problem = manage_directory()
|
||||
progress('running', 'OpenVPN')
|
||||
manage_openvpn(ctx, changed)
|
||||
|
||||
if 'resolved' in changed:
|
||||
progress('running', 'resolver')
|
||||
run(['systemctl', 'restart', 'systemd-resolved'], check=False)
|
||||
|
||||
progress('running', 'platform module')
|
||||
run_platform_setup(cfg, ctx)
|
||||
progress('running', 'Docker rules')
|
||||
refresh_docker_rules()
|
||||
progress('running', 'web service state')
|
||||
refresh_web(cfg, ctx)
|
||||
for problem in problems:
|
||||
if problem:
|
||||
progress('failed', 'user directory', problem)
|
||||
print(f'vpn-router: error: {problem}', file=sys.stderr)
|
||||
return 1 if problems else 0
|
||||
return 1
|
||||
progress('done', 'done')
|
||||
return 0
|
||||
|
||||
|
||||
def record_failure(error):
|
||||
"""Mark the run failed in the step SETUP_STATE holds."""
|
||||
try:
|
||||
step = json.loads(SETUP_STATE.read_text(encoding='utf-8')).get('step')
|
||||
except (OSError, ValueError):
|
||||
step = None
|
||||
progress('failed', step, error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
# A failing step ends with SystemExit carrying its message (vpnrouter.fail).
|
||||
try:
|
||||
code = main()
|
||||
except SystemExit as exc:
|
||||
record_failure(str(exc.code))
|
||||
raise
|
||||
except Exception as exc:
|
||||
record_failure(repr(exc))
|
||||
raise
|
||||
sys.exit(code)
|
||||
Reference in new issue
Block a user