Add error reporting over email and improve logging

This commit is contained in:
Timotej Lazar 2023-07-03 15:55:49 +02:00
parent b55ae4d305
commit 5e65755ec0
2 changed files with 47 additions and 25 deletions

View file

@ -1,4 +1,5 @@
import os import os
import syslog
import secrets import secrets
import flask import flask
@ -7,6 +8,7 @@ import flask_login
def create_app(test_config=None): def create_app(test_config=None):
app = flask.Flask(__name__) app = flask.Flask(__name__)
syslog.openlog('friwall')
# Ensure all required keys exist. # Ensure all required keys exist.
settings = { settings = {
@ -19,6 +21,7 @@ def create_app(test_config=None):
'ldap_base_dn': '', 'ldap_base_dn': '',
'ldap_user_dn': '', 'ldap_user_dn': '',
'ldap_login_attr': 'userPrincipalName', 'ldap_login_attr': 'userPrincipalName',
'admin_mail': '',
'wg_endpoint': '', 'wg_endpoint': '',
'wg_port': '51820', 'wg_port': '51820',
'wg_key': '', 'wg_key': '',

View file

@ -1,11 +1,16 @@
#!/usr/bin/python3 #!/usr/bin/python3
import collections import collections
import email.message
import getpass
import multiprocessing import multiprocessing
import os import os
import pathlib import pathlib
import shutil import shutil
import smtplib
import socket
import subprocess import subprocess
import sys
import syslog import syslog
import click import click
@ -15,6 +20,15 @@ import ldap3
from . import db from . import db
def mail(rcpt, subject, body):
msg = email.message.EmailMessage()
msg['Subject'] = f'friwall: {subject}'
msg['From'] = f'{getpass.getuser()}@{socket.getfqdn()}'
msg['To'] = rcpt
msg.set_content(body)
with smtplib.SMTP('localhost') as server:
server.send_message(msg)
def init_app(app): def init_app(app):
app.cli.add_command(generate) app.cli.add_command(generate)
app.cli.add_command(push) app.cli.add_command(push)
@ -147,11 +161,15 @@ AllowedIPs = {ip}
return True return True
except Exception as e: except Exception as e:
syslog.syslog(f'exception while generating config: {e}')
import traceback import traceback
with open('/tmp/wtflog', 'a+') as f: e.add_note(f'exception while generating config: {e}')
traceback.print_exc(file=f) msg = traceback.format_exc()
if rcpt := settings.get('admin_mail'):
mail(rcpt, 'error generating config', msg)
# TODO this doesn’t seem to work
#syslog.syslog(msg)
return False return False
finally: finally:
# Remove temporary directory. # Remove temporary directory.
if output: if output:
@ -174,30 +192,31 @@ def push(version=None):
nodes = db.read('nodes') nodes = db.read('nodes')
tar_file = pathlib.Path.home() / 'config' / f'{version}.tar.gz' tar_file = pathlib.Path.home() / 'config' / f'{version}.tar.gz'
done = True errors = []
for node, node_version in nodes.items(): for node, node_version in nodes.items():
if node_version != version: if node_version != version:
if not os.path.exists(tar_file): try:
syslog.syslog(f'wanted to push version {version} but {version}.tar.gz doesn’t exist')
return
# Push config tarfile to node. There sshd runs a forced command that # Push config tarfile to node. There sshd runs a forced command that
# reads in a tarball, copies files to /etc and reloads services. # reads in a tarball, copies files to /etc and reloads services.
syslog.syslog(f'updating config for {node} from v{node_version} to v{version}') syslog.syslog(f'updating config for {node} from v{node_version} to v{version}')
result = subprocess.run([f'ssh -T -o ConnectTimeout=10 root@{node}'], result = subprocess.run(['/usr/bin/ssh', '-T', '-o', 'ConnectTimeout=10', f'root@{node}'],
stdin=open(tar_file), shell=True, capture_output=True) stdin=open(tar_file), capture_output=True, text=True)
if result.returncode == 0: if result.returncode == 0:
nodes[node] = version nodes[node] = version
db.write('nodes', nodes) db.write('nodes', nodes)
syslog.syslog(f'successfully updated config for {node} to v{version}') syslog.syslog(f'successfully updated config for {node} to v{version}')
else: else:
done = False raise RuntimeError(f'error updating config to v{version}: {result.stderr}')
syslog.syslog(f'error updating config for node {node} to v{version}: {result.stderr}') except (FileNotFoundError, RuntimeError) as e:
# TODO notify by mail e.add_note(f'error while updating node {node}')
return done errors.append(e)
if errors:
raise ExceptionGroup('errors while updating nodes', errors)
except Exception as e: except Exception as e:
import traceback import traceback
with open('/tmp/wtflog', 'a+') as f: msg = traceback.format_exc()
traceback.print_exc(file=f) if rcpt := db.load('settings').get('admin_mail'):
return False mail(rcpt, 'error updating nodes', msg)
syslog.syslog(msg)