Setup pyhton3-django-etesync-journal using uWSGI with Nginx. Signed-off-by: Peter Stadler <peter.stadler@student.uibk.ac.at>lilik-openwrt-22.03
@ -0,0 +1,107 @@ | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=etesync-server | |||||
PKG_VERSION:=0.3.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=etesync-server-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://github.com/etesync/server/archive/v$(PKG_VERSION) | |||||
PKG_HASH:=d0728effa898a8b7afb4ce7439e0d0fd46bc819008925f21788d7e113435b579 | |||||
PKG_LICENSE:=AGPL-3.0-only | |||||
PKG_LICENSE_FILES:=LICENSE | |||||
PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at> | |||||
PKG_UNPACK=$(HOST_TAR) -C $(PKG_BUILD_DIR) --strip-components=1 -xzf $(DL_DIR)/$(PKG_SOURCE) | |||||
include $(INCLUDE_DIR)/package.mk | |||||
include ../../lang/python/python3-package.mk | |||||
# this allows using python3-package.mk with a non-package app (etesync-server): | |||||
define Py3Build/Compile | |||||
$(INSTALL_DIR) $(PKG_INSTALL_DIR)/$(PYTHON3_PKG_DIR) | |||||
endef | |||||
define Package/etesync-server | |||||
SECTION:=net | |||||
CATEGORY:=Network | |||||
SUBMENU:=Web Servers/Proxies | |||||
TITLE:=End-to-End Encrypted Secure Data Sync | |||||
URL:=https://www.etesync.com/ | |||||
DEPENDS:=+nginx-ssl +python3-light +python3-django \ | |||||
+python3-django-restframework +python3-drf-nested-routers \ | |||||
+python3-django-cors-headers +python3-django-etesync-journal \ | |||||
+uwsgi +uwsgi-python3-plugin +uwsgi-syslog-plugin | |||||
USERID:=etesync=44312 | |||||
VARIANT:=python3 | |||||
PROVIDES:=etesync-server | |||||
endef | |||||
define Package/etesync-server/description | |||||
End-to-End Encrypted Secure Data Sync | |||||
endef | |||||
define Py3Package/etesync-server/install | |||||
$(INSTALL_DIR) $(1)/www/etesync/static/ | |||||
$(INSTALL_DIR) $(1)/etc/uci-defaults/ | |||||
$(CP) ./files/81_setup-etesync-server $(1)/etc/uci-defaults/ | |||||
$(INSTALL_DIR) $(1)/etc/nginx/conf.d/ | |||||
$(INSTALL_CONF) ./files/etesync.locations $(1)/etc/nginx/conf.d/ | |||||
$(INSTALL_DIR) $(1)/etc/config/ | |||||
$(INSTALL_CONF) ./files/uci.cfg $(1)/etc/config/etesync_server | |||||
$(INSTALL_DIR) $(1)/usr/share/etesync-server/templates/ | |||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/templates/* \ | |||||
$(1)/usr/share/etesync-server/templates/ | |||||
$(INSTALL_DIR) $(1)/usr/share/etesync-server/etesync_server/ | |||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/manage.py \ | |||||
$(1)/usr/share/etesync-server/ | |||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/etesync_server/* \ | |||||
$(1)/usr/share/etesync-server/etesync_server/ | |||||
$(LN) /var/etc/etesync-server/etesync-server.ini \ | |||||
$(1)/usr/share/etesync-server/ | |||||
#init creates /var/etc/etesync-server/etesync-server.ini from uci.cfg | |||||
$(INSTALL_DIR) $(1)/etc/uwsgi/vassals/ | |||||
$(INSTALL_CONF) ./files/uwsgi.ini \ | |||||
$(1)/etc/uwsgi/vassals/etesync-server.available | |||||
$(LN) /var/etc/etesync-server/uwsgi.ini \ | |||||
$(1)/etc/uwsgi/vassals/etesync-server.ini | |||||
#init links etesync-server.available /var/etc/etesync-server/uwsgi.ini | |||||
$(INSTALL_DIR) $(1)/etc/init.d/ | |||||
$(INSTALL_BIN) ./files/uwsgi.init $(1)/etc/init.d/etesync-server | |||||
endef | |||||
define Package/etesync-server/postrm | |||||
#!/bin/sh | |||||
[ -n "$${IPKG_INSTROOT}" ] && exit 0 | |||||
rmdir /usr/share/etesync-server/etesync_server | |||||
[ "$${PKG_UPGRADE}" = "1" ] && exit 0 | |||||
rm -r /www/etesync/static | |||||
rmdir /www/etesync | |||||
exit 0 | |||||
endef | |||||
define Package/etesync-server/conffiles | |||||
/etc/config/etesync_server | |||||
/etc/nginx/conf.d/etesync.locations | |||||
/etc/uwsgi/vassals/etesync-server.available | |||||
endef | |||||
$(eval $(call Py3Package,etesync-server)) | |||||
$(eval $(call BuildPackage,etesync-server)) | |||||
$(eval $(call BuildPackage,etesync-server-src)) |
@ -0,0 +1,56 @@ | |||||
#!/bin/sh | |||||
[ "${PKG_UPGRADE}" = "1" ] && /etc/init.d/etesync-server stop | |||||
cd /usr/share/etesync-server || exit 1 | |||||
python3 manage.pyc migrate --noinput || exit 1 | |||||
# setup minimal ini for collectstatic: | |||||
mkdir -p /var/etc/etesync-server/ || exit 1 | |||||
printf "[global]\nSTATIC_ROOT=/www/etesync/static" >etesync-server.ini || exit 1 | |||||
python3 manage.pyc collectstatic --noinput || exit 1 | |||||
ETESYNC_HAS_USER_PY3CMD="import sqlite3 | |||||
c = sqlite3.connect('db.sqlite3').cursor() | |||||
c.execute('select * from auth_user') | |||||
if c.fetchone()==None: print('0') | |||||
else: print('1')" | |||||
echo | |||||
if [ "$(python3 -c "$ETESYNC_HAS_USER_PY3CMD" || exit 1)" = "0" ] | |||||
then | |||||
echo "===== First, create a superuser of the Webinterface by =====" | |||||
[ -t 0 ] && python3 manage.pyc createsuperuser || | |||||
echo "===== python3 $(pwd)/manage.pyc createsuperuser =====" | |||||
fi | |||||
chown -Rh etesync:nogroup . /www/etesync/ || exit 1 | |||||
[ -x /etc/init.d/nginx ] || exit 1 | |||||
/etc/init.d/nginx running && /etc/init.d/nginx reload || /etc/init.d/nginx start | |||||
router_ip() { | |||||
local ifstat="$(ifstatus "lan")" | |||||
for ip in $(echo "${ifstat}" | jsonfilter -e '@["ipv4-address"].*.address') | |||||
do echo "${ip}" && return | |||||
done | |||||
for ip in $(echo "${ifstat}" | jsonfilter -e '@["ipv6-address"].*.address') | |||||
do echo "[${ip}]" && return | |||||
done | |||||
for ip in $(echo "${ifstat}" | \ | |||||
jsonfilter -e '@["ipv6-prefix-assignment"].*["local-address"].address') | |||||
do echo "[${ip}]" && return | |||||
done | |||||
echo '$ROUTER' | |||||
} | |||||
echo "===== You can add users by https://$(router_ip)/etesync/admin/login =====" | |||||
exit 0 |
@ -0,0 +1,13 @@ | |||||
location /etesync/static { | |||||
access_log off; | |||||
error_log /dev/null; | |||||
expires 1y; | |||||
try_files $uri $uri/ =404; | |||||
} | |||||
location /etesync { | |||||
access_log off; | |||||
error_log /dev/null; | |||||
include uwsgi_params; | |||||
uwsgi_pass unix:///var/run/etesync-server.socket; | |||||
} |
@ -0,0 +1,13 @@ | |||||
config django 'global' | |||||
option static_url '/etesync/static/' # TODO for django 3.1: "static/" | |||||
option debug 'false' | |||||
config django 'allowed_hosts' | |||||
list uci_allow_all_ips_of 'loopback' | |||||
list uci_allow_all_ips_of 'lan' | |||||
# list allowed_host "example.com" | |||||
config django 'database' | |||||
option engine 'django.db.backends.sqlite3' | |||||
option name 'db.sqlite3' |
@ -0,0 +1,48 @@ | |||||
; The script /etc/init.d/etesync-server creates the second symlink in the | |||||
; following chain when starting (and deletes it when stopping the service): | |||||
; /etc/uwsgi/vassals/etesync-server.ini (letting the emperor load it on-demand) | |||||
; -> /var/etc/etesync-server/uwsgi.ini (in RAM) | |||||
; -> /etc/uwsgi/vassals/etesync-server.available (this file) | |||||
[uwsgi] | |||||
strict = true | |||||
plugin = python | |||||
manage-script-name = true | |||||
chdir = /usr/share/etesync-server | |||||
mount = /etesync=etesync_server.wsgi:application | |||||
pidfile = /var/etc/etesync-server/master.pid | |||||
enable-threads = true | |||||
thunder-lock = true | |||||
post-buffering = 8192 | |||||
harakiri = 60 | |||||
lazy-apps = true | |||||
master = true | |||||
idle = 600 | |||||
plugin = syslog | |||||
; disable-logging only affects req-logger: | |||||
disable-logging = true | |||||
log-format=%(method) %(uri) => return %(status) (%(rsize) bytes in %(msecs) ms) | |||||
req-logger = syslog:etesync-server_req | |||||
logger = etesync syslog:etesync-server_main | |||||
ignore-sigpipe = true | |||||
ignore-write-errors = true | |||||
if-env = UWSGI_EMPEROR_FD | |||||
; the regular expression leaves for successful de/activation only one line each: | |||||
log-route = etesync ^(?!... Starting uWSGI |compiled with version: |os: Linux|nodename: |machine: |clock source: |pcre jit |detected number of CPU cores: |current working directory: |writing pidfile to |detected binary path: |chdir.. to |your processes number limit is |your memory page size is |detected max file descriptor number: |lock engine: |thunder lock: |uwsgi socket |setgid.. to |setuid.. to |Python version: |Python main interpreter initialized at |python threads support |your server socket listen backlog is limited to |your mercy for graceful operations on workers is |mapped |... Operational MODE: |... uWSGI is running in multiple interpreter mode ...|spawned uWSGI worker |mounting |WSGI app |announcing my loyalty to the Emperor...|workers have been inactive for more than |SIGINT/SIGQUIT received...killing workers...|worker |goodbye to uWSGI.) | |||||
end-if = | |||||
if-not-env = UWSGI_EMPEROR_FD | |||||
log-route = etesync .* | |||||
vacuum = true | |||||
socket = /var/run/etesync-server.socket | |||||
end-if = | |||||
chmod-socket = 660 | |||||
chown-socket = etesync:nogroup | |||||
uid = etesync | |||||
gid = nogroup |
@ -0,0 +1,136 @@ | |||||
#!/bin/sh /etc/rc.common | |||||
START=82 | |||||
USE_PROCD=1 | |||||
ETESYNC_INI="/var/etc/etesync-server/etesync-server.ini" | |||||
etesync_print_uci_allow_all_ips_of() { | |||||
local ifstat="$(ifstatus "$1")" | |||||
for ip in $(echo "${ifstat}" | jsonfilter -e '@["ipv4-address"].*.address') | |||||
do echo "allowed_host_${ip//[^0-9]/_} = ${ip}" | |||||
done | |||||
for ip in $(echo "${ifstat}" | jsonfilter -e '@["ipv6-address"].*.address') | |||||
do echo "allowed_host_${ip//[^0-9A-Fa-f]/_} = [${ip}]" | |||||
done | |||||
for ip in $(echo "${ifstat}" | \ | |||||
jsonfilter -e '@["ipv6-prefix-assignment"].*["local-address"].address') | |||||
do echo "allowed_host_${ip//[^0-9A-Fa-f]/_} = [${ip}]" | |||||
done | |||||
} | |||||
etesync_validate_global() { | |||||
cd /usr/share/etesync-server/ >/dev/null || return | |||||
uci_load_validate etesync_server django "global" "$1" \ | |||||
'secret_file:file:secret.txt' \ | |||||
'static_url:string:/etesync/static' \ | |||||
'language_code:string:en-us' \ | |||||
'time_zone:string:UTC' \ | |||||
'debug:bool:false' \ | |||||
; | |||||
} | |||||
etesync_print_global() { | |||||
printf "\n[global]\n" | |||||
echo "secret_file = ${secret_file}" | |||||
echo "static_root = /www/etesync/static" #sic! | |||||
echo "static_url = ${static_url}" | |||||
echo "language_code = ${language_code}" | |||||
echo "time_zone = ${time_zone}" | |||||
echo "debug = ${debug}" | |||||
} | |||||
etesync_validate_allowed_hosts() { | |||||
uci_load_validate etesync_server django "allowed_hosts" "$1" \ | |||||
'uci_allow_all_ips_of:network' \ | |||||
'allowed_host:host' \ | |||||
; | |||||
} | |||||
etesync_print_allowed_hosts() { | |||||
printf "\n[allowed_hosts]\n" | |||||
local iface | |||||
for iface in ${uci_allow_all_ips_of} | |||||
do etesync_print_uci_allow_all_ips_of "${iface}" | |||||
done | |||||
local host | |||||
for host in ${allowed_host} | |||||
do echo "allowed_host_${host//[^0-9A-Za-z]/_} = ${host}" | |||||
done | |||||
} | |||||
etesync_validate_database() { | |||||
cd /usr/share/etesync-server/ >/dev/null || return | |||||
uci_load_validate etesync_server django "database" "$1" \ | |||||
'engine:hostname:django.db.backends.sqlite3' \ | |||||
'name:file:db.sqlite3' \ | |||||
; | |||||
} | |||||
etesync_print_database() { | |||||
printf "\n[database]\n" | |||||
echo "engine = ${engine}" | |||||
echo "name = ${name}" | |||||
} | |||||
etesync_init() { # This must print ONLY configuration lines: | |||||
echo "; This file is re-created from /etc/config/etesync_server " | |||||
etesync_validate_global etesync_print_global | |||||
etesync_validate_allowed_hosts etesync_print_allowed_hosts | |||||
etesync_validate_database etesync_print_database | |||||
} >"${ETESYNC_INI}" | |||||
start_service() { | |||||
mkdir -p /var/etc/etesync-server/ | |||||
etesync_init | |||||
logger -p 'daemon.info' -t 'etesync-server_init' 'starting ...' | |||||
ln -sf /etc/uwsgi/vassals/etesync-server.available \ | |||||
/var/etc/etesync-server/uwsgi.ini | |||||
} | |||||
stop_service() { | |||||
rm -f /var/etc/etesync-server/uwsgi.ini "${ETESYNC_INI}" | |||||
} | |||||
reload_service() { | |||||
etesync_init | |||||
logger -p 'daemon.info' -t 'etesync-server_init' 'reloading ...' | |||||
kill -SIGHUP "$(cat "/var/etc/etesync-server/master.pid")" 2>/dev/null | |||||
#if the server is in on-demand mode, the ini files are reloaded then, too. | |||||
} | |||||
service_triggers() { | |||||
procd_open_validate | |||||
etesync_validate_global "$@" | |||||
etesync_validate_allowed_hosts "$@" | |||||
etesync_validate_database "$@" | |||||
procd_close_validate | |||||
config_load etesync_server | |||||
config_list_foreach "allowed_hosts" "uci_allow_all_ips_of" \ | |||||
procd_add_reload_interface_trigger | |||||
procd_add_reload_trigger etesync_server | |||||
} |