Add error reporting over email and improve logging
This commit is contained in:
parent
b55ae4d305
commit
5e65755ec0
|
@ -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': '',
|
||||||
|
|
|
@ -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')
|
# Push config tarfile to node. There sshd runs a forced command that
|
||||||
return
|
# 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}')
|
||||||
# Push config tarfile to node. There sshd runs a forced command that
|
result = subprocess.run(['/usr/bin/ssh', '-T', '-o', 'ConnectTimeout=10', f'root@{node}'],
|
||||||
# reads in a tarball, copies files to /etc and reloads services.
|
stdin=open(tar_file), capture_output=True, text=True)
|
||||||
syslog.syslog(f'updating config for {node} from v{node_version} to v{version}')
|
if result.returncode == 0:
|
||||||
result = subprocess.run([f'ssh -T -o ConnectTimeout=10 root@{node}'],
|
nodes[node] = version
|
||||||
stdin=open(tar_file), shell=True, capture_output=True)
|
db.write('nodes', nodes)
|
||||||
if result.returncode == 0:
|
syslog.syslog(f'successfully updated config for {node} to v{version}')
|
||||||
nodes[node] = version
|
else:
|
||||||
db.write('nodes', nodes)
|
raise RuntimeError(f'error updating config to v{version}: {result.stderr}')
|
||||||
syslog.syslog(f'successfully updated config for {node} to v{version}')
|
except (FileNotFoundError, RuntimeError) as e:
|
||||||
else:
|
e.add_note(f'error while updating node {node}')
|
||||||
done = False
|
errors.append(e)
|
||||||
syslog.syslog(f'error updating config for node {node} to v{version}: {result.stderr}')
|
if errors:
|
||||||
# TODO notify by mail
|
raise ExceptionGroup('errors while updating nodes', errors)
|
||||||
return done
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue