#!/bin/sh # warp-aio: runs the homeserver, the admin panel and the web client (and, # with WARP_AIO_EMBEDDED_POSTGRES=true, PostgreSQL) in one container. # # If any of them exits, the others are stopped and the container exits, so # the restart policy brings the whole set back. SIGTERM stops the clients # first, then the homeserver, then PostgreSQL. # # With arguments, runs them instead: `docker run warp-aio warp version`. # # WARP_AIO_ADMIN=false no admin panel # WARP_AIO_WEB=false no web client # WARP_AIO_EMBEDDED_POSTGRES=true PostgreSQL in the container, data in # $PGDATA (/data/postgres); the default # in warp-aio-postgresql, the only image # that has PostgreSQL set -eu if [ "$#" -gt 0 ]; then exec "$@" fi log() { echo "warp-aio: $*" >&2; } pg_pid="" warp_pid="" admin_pid="" web_pid="" # stop PID...: SIGTERM, then wait for each to exit. stop() { for pid in "$@"; do [ -n "$pid" ] && kill -TERM "$pid" 2>/dev/null || true done for pid in "$@"; do [ -n "$pid" ] && wait "$pid" 2>/dev/null || true done } shutdown() { trap '' TERM INT stop "$web_pid" "$admin_pid" stop "$warp_pid" if [ -n "$pg_pid" ]; then # SIGINT is PostgreSQL's fast shutdown: it does not wait for # clients, and the homeserver is gone by now anyway. kill -INT "$pg_pid" 2>/dev/null || true wait "$pg_pid" 2>/dev/null || true fi exit "${1:-0}" } trap 'log "stopping"; shutdown 0' TERM INT if [ "$WARP_AIO_EMBEDDED_POSTGRES" = true ]; then if ! command -v postgres >/dev/null; then log "WARP_AIO_EMBEDDED_POSTGRES=true, but this image has no PostgreSQL; use warp-aio-postgresql" exit 1 fi export PGDATA="${PGDATA:-/data/postgres}" if [ ! -s "$PGDATA/PG_VERSION" ]; then log "initialising PostgreSQL in $PGDATA" # Trust is safe here: PostgreSQL listens on no TCP address, only on # a socket inside this container. initdb -D "$PGDATA" -U warp --auth=trust --encoding=UTF8 --locale=C >/dev/null fi postgres -D "$PGDATA" -c listen_addresses='' -c unix_socket_directories=/run/postgresql & pg_pid=$! until pg_isready -q -h /run/postgresql -U warp; do kill -0 "$pg_pid" 2>/dev/null || { log "PostgreSQL failed to start"; exit 1; } sleep 1 done if [ "$(psql -h /run/postgresql -U warp -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = 'warp'")" != 1 ]; then createdb -h /run/postgresql -U warp warp fi fi # The signing key is created on first start and kept in the volume: losing # it means other servers no longer recognise this one. if [ ! -f "$WARP_PRIVATE_KEY" ]; then warp generate-keys --output "$WARP_PRIVATE_KEY" fi warp serve & warp_pid=$! if [ "$WARP_AIO_ADMIN" = true ]; then warp-admin & admin_pid=$! fi if [ "$WARP_AIO_WEB" = true ]; then warp-web & web_pid=$! fi # Busybox sh has no `wait -n`, so check on the processes every second. The # sleep runs in the background so a signal is handled at once. while :; do for entry in "postgres:$pg_pid" "warp:$warp_pid" "warp-admin:$admin_pid" "warp-web:$web_pid"; do pid="${entry#*:}" if [ -n "$pid" ] && ! kill -0 "$pid" 2>/dev/null; then log "${entry%%:*} exited; stopping the rest" shutdown 1 fi done sleep 1 & wait $! || true done