Add elwig-backend.service to .deb package

This commit is contained in:
2025-04-30 16:56:35 +02:00
parent 60be49d31d
commit fbb1a62284
8 changed files with 98 additions and 16 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
*.sql *.sql
*.sqlite3 *.sqlite3
*.deb *.deb
*.ini
!*.sample.ini

9
backend.sample.ini Normal file
View File

@ -0,0 +1,9 @@
[general]
domain = wg.example.com
database = database.sqlite3
users = users.txt
#port = 8084
[jwt]
secret = key
#invalidate_before = 1970-01-01T00:00:00Z

View File

@ -8,6 +8,12 @@ mkdir -p build/
mkdir -p build/usr/bin/ mkdir -p build/usr/bin/
cp src/elwig-backend build/usr/bin cp src/elwig-backend build/usr/bin
mkdir -p build/lib/systemd/system/
cp pkg/elwig-backend.service build/lib/systemd/system
mkdir -p build/etc/elwig
cp backend.sample.ini build/etc/elwig/backend.ini
mkdir -p build/DEBIAN/ mkdir -p build/DEBIAN/
echo -n "\ echo -n "\
Package: elwig-backend Package: elwig-backend
@ -17,11 +23,15 @@ Priority: optional
Essential: no Essential: no
Architecture: all Architecture: all
Depends: python3 Depends: python3
Installed-Size: $(du -ks build/usr/bin/ | cut -f 1) Installed-Size: $(du -ks build/usr/bin/ build/etc/ build/lib/systemd/system/ | cut -f 1 | paste -sd+ | bc)
Maintainer: Lorenz Stechauner <lorenz.stechauner@necronda.net> Maintainer: Lorenz Stechauner <lorenz.stechauner@necronda.net>
Homepage: https://git.necronda.net/winzer/elwig-backend Homepage: https://git.necronda.net/winzer/elwig-backend
Description: Local backend for Elwig's REST API Description: Local backend for Elwig's REST API
" > build/DEBIAN/control " > build/DEBIAN/control
echo -n "\
/etc/elwig/backend.ini
" > build/DEBIAN/conffiles
cp pkg/postinst pkg/prerm pkg/postrm build/DEBIAN
chmod 0755 build/usr/bin/* chmod 0755 build/usr/bin/*
sudo chown root:root -R build/ sudo chown root:root -R build/

13
pkg/elwig-backend.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=Elwig backend
After=network.target
[Service]
RestartSec=5s
Type=simple
User=nobody
ExecStart=/usr/bin/elwig-backend /etc/elwig/backend.ini
Restart=on-failure
[Install]
WantedBy=multi-user.target

25
pkg/postinst Executable file
View File

@ -0,0 +1,25 @@
#!/bin/sh
set -e
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
# This will only remove masks created by d-s-h on package removal.
deb-systemd-helper unmask 'elwig-backend.service' >/dev/null || true
# was-enabled defaults to true, so new installations run enable.
if deb-systemd-helper --quiet was-enabled 'elwig-backend.service'; then
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable 'elwig-backend.service' >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state 'elwig-backend.service' >/dev/null || true
fi
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
if [ -n "$2" ]; then
_dh_action=restart
else
_dh_action=start
fi
deb-systemd-invoke $_dh_action 'elwig-backend.service' >/dev/null || true
fi
fi

16
pkg/postrm Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
set -e
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
fi
if [ "$1" = "remove" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper mask 'elwig-backend.service' >/dev/null || true
fi
fi
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge 'elwig-backend.service' >/dev/null || true
deb-systemd-helper unmask 'elwig-backend.service' >/dev/null || true
fi
fi

5
pkg/prerm Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
deb-systemd-invoke stop 'elwig-backend.service' >/dev/null || true
fi

View File

@ -4,6 +4,8 @@
from __future__ import annotations from __future__ import annotations
from typing import Callable, Optional from typing import Callable, Optional
from http.server import BaseHTTPRequestHandler, HTTPServer from http.server import BaseHTTPRequestHandler, HTTPServer
import configparser
import os.path
import argparse import argparse
import datetime import datetime
import time import time
@ -18,7 +20,7 @@ import hashlib
import hmac import hmac
VERSION: str = '0.0.4' VERSION: str = '0.0.6'
CNX: sqlite3.Cursor CNX: sqlite3.Cursor
USER_FILE: str USER_FILE: str
@ -488,29 +490,29 @@ def main() -> None:
sqlite3.register_adapter(datetime.time, lambda t: t.strftime('%H:%M:%S')) sqlite3.register_adapter(datetime.time, lambda t: t.strftime('%H:%M:%S'))
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('db', type=str, metavar='DB') parser.add_argument('config_file', type=str, metavar='CONFIG_FILE')
parser.add_argument('jwt_file', type=str, metavar='JWT-FILE') parser.add_argument('-p', '--port', type=int)
parser.add_argument('user_file', type=str, metavar='USER-FILE')
parser.add_argument('-p', '--port', type=int, default=8080)
args = parser.parse_args() args = parser.parse_args()
jwt_file = args.jwt_file config = configparser.ConfigParser()
with open(jwt_file, 'rb') as file: config.read(args.config_file)
iss, dt, JWT_SECRET = file.readline().strip().split(b':', 2) JWT_ISSUER = config['general']['domain']
JWT_ISSUER = iss.decode('utf-8') JWT_INVALIDATE_BEFORE = int(datetime.datetime.fromisoformat(config['jwt'].get('invalidate_before', '1970-01-01T00:00:00Z')).timestamp())
JWT_INVALIDATE_BEFORE = int(datetime.datetime.fromisoformat(dt.decode('ascii')).timestamp()) if dt else 0 JWT_SECRET = config['jwt']['secret'].encode('utf-8')
USER_FILE = args.user_file USER_FILE = os.path.join(os.path.dirname(os.path.abspath(args.config_file)), config['general']['users'])
with open(USER_FILE, 'r') as file: with open(USER_FILE, 'r') as file:
for line in file: for line in file:
(u, r, i, p) = line.strip().split(':', 3) (u, r, i, p) = line.strip().split(':', 3)
JWT_USER_INVALIDATE_BEFORE[u.strip()] = int(datetime.datetime.fromisoformat(i).timestamp()) if i else 0 JWT_USER_INVALIDATE_BEFORE[u.strip()] = int(datetime.datetime.fromisoformat(i).timestamp()) if i else 0
CNX = sqlite3.connect(f'file:{args.db}?mode=ro', uri=True) db_file = os.path.join(os.path.dirname(os.path.abspath(args.config_file)), config['general']['database'])
CNX = sqlite3.connect(f'file:{db_file}?mode=ro', uri=True)
CNX.create_function('REGEXP', 2, sqlite_regexp, deterministic=True) CNX.create_function('REGEXP', 2, sqlite_regexp, deterministic=True)
server = HTTPServer(('localhost', args.port), ElwigApi) port = args.port or int(config['general'].get('port', '8084'))
print(f'Listening on http://localhost:{args.port}') server = HTTPServer(('localhost', port), ElwigApi)
print(f'Listening on http://localhost:{port}')
try: try:
server.serve_forever() server.serve_forever()
except InterruptedError | KeyboardInterrupt: except InterruptedError | KeyboardInterrupt: