From 96b91b2a6997183eac424e5fde573ed52f62e2fa Mon Sep 17 00:00:00 2001 From: Peter van Arkel Date: Tue, 19 May 2026 18:52:31 +0200 Subject: [PATCH] (refactor) Quiet native installer output by default Add step-based installer logging that reports pobsync actions as OK, FAILED, or SKIPPED while suppressing noisy apt, pip, Django, and systemd output during successful runs. Show the captured output for the failed step when something breaks, and add a --verbose flag to restore full command output for debugging. Document the quieter installer behavior and verbose mode in the README and development notes. --- README.md | 3 +- docs/development.md | 4 +- scripts/install-systemd | 117 ++++++++++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 3c5bb58..340f058 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,8 @@ sudo scripts/install-systemd \ Use `--no-install-os-packages` if you want to manage system packages yourself. Use `--force-env` only when you want the installer to rewrite an existing `/etc/pobsync/pobsync.env`. -Use `--non-interactive` for scripted installs. +Use `--non-interactive` for scripted installs. Use `--verbose` when you want to see the underlying apt, pip, Django, and +systemd output. For MariaDB support, add: diff --git a/docs/development.md b/docs/development.md index 0916782..99e2069 100644 --- a/docs/development.md +++ b/docs/development.md @@ -72,11 +72,13 @@ Useful modes: ``` sudo scripts/install-systemd sudo scripts/install-systemd --non-interactive +sudo scripts/install-systemd --verbose sudo scripts/install-systemd --create-superuser --superuser-username admin ``` The installer should print a short completion summary with the control panel URL, Self Check reminder, and service log -commands. Keep that output user-facing rather than developer-facing. +commands. Keep normal output user-facing: pobsync step names with OK, FAILED, or SKIPPED. Full apt, pip, Django, and +systemd output belongs behind `--verbose` or in the failed step output. ## Migration Helpers diff --git a/scripts/install-systemd b/scripts/install-systemd index b932b91..ef844d2 100755 --- a/scripts/install-systemd +++ b/scripts/install-systemd @@ -16,6 +16,7 @@ WEB_BIND=${POBSYNC_WEB_BIND:-127.0.0.1:8010} FORCE_ENV=0 INSTALL_OS_PACKAGES=1 WITH_NGINX=0 +VERBOSE=0 INTERACTIVE=0 CREATE_SUPERUSER=ask SUPERUSER_USERNAME=${POBSYNC_SUPERUSER_USERNAME:-} @@ -72,6 +73,10 @@ while [ "$#" -gt 0 ]; do FORCE_ENV=1 shift ;; + --verbose) + VERBOSE=1 + shift + ;; --interactive) INTERACTIVE=1 shift @@ -128,6 +133,39 @@ if [ "$(id -u)" -ne 0 ]; then exit 1 fi +run_step() { + label=$1 + shift + + if [ "$VERBOSE" -eq 1 ]; then + echo "==> $label" + "$@" + echo "OK: $label" + return + fi + + printf '%-48s' "$label" + log_file=$(mktemp) + if "$@" >"$log_file" 2>&1; then + rm -f "$log_file" + echo "OK" + return + fi + + echo "FAILED" + echo + echo "Output from failed step '$label':" >&2 + cat "$log_file" >&2 + rm -f "$log_file" + exit 1 +} + +note_step() { + label=$1 + status=$2 + printf '%-48s%s\n' "$label" "$status" +} + prompt_value() { prompt=$1 default=$2 @@ -252,6 +290,7 @@ fi install_os_packages() { if [ "$INSTALL_OS_PACKAGES" -ne 1 ]; then + note_step "Install OS packages" "SKIPPED" return fi @@ -263,8 +302,7 @@ install_os_packages() { if [ "$INSTALL_EXTRAS" = "mariadb" ] || [ "$INSTALL_EXTRAS" = "[mariadb]" ] || [ "$INSTALL_EXTRAS" = ".[mariadb]" ]; then packages="$packages default-libmysqlclient-dev build-essential pkg-config" fi - apt-get update - apt-get install -y --no-install-recommends $packages + run_step "Install OS packages" sh -c "apt-get update && apt-get install -y --no-install-recommends $packages" return fi @@ -294,19 +332,23 @@ if [ ! -f "$SOURCE_DIR/manage.py" ]; then fi if ! getent group "$SERVICE_GROUP" >/dev/null 2>&1; then - groupadd --system "$SERVICE_GROUP" + run_step "Create service group" groupadd --system "$SERVICE_GROUP" +else + note_step "Create service group" "OK" fi if ! id "$SERVICE_USER" >/dev/null 2>&1; then - useradd --system --home /var/lib/pobsync --shell /usr/sbin/nologin --gid "$SERVICE_GROUP" "$SERVICE_USER" + run_step "Create service user" useradd --system --home /var/lib/pobsync --shell /usr/sbin/nologin --gid "$SERVICE_GROUP" "$SERVICE_USER" +else + note_step "Create service user" "OK" fi -mkdir -p /etc/pobsync /var/lib/pobsync /var/log/pobsync "$(dirname "$VENV_DIR")" "$APP_DIR" "$BACKUP_ROOT" -chown "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync -chmod 0750 /var/lib/pobsync /var/log/pobsync +run_step "Prepare directories" mkdir -p /etc/pobsync /var/lib/pobsync /var/log/pobsync "$(dirname "$VENV_DIR")" "$APP_DIR" "$BACKUP_ROOT" +run_step "Set state directory permissions" chown "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync +run_step "Set private directory modes" chmod 0750 /var/lib/pobsync /var/log/pobsync if [ "$SOURCE_DIR" != "$APP_DIR" ]; then - rsync -a --delete \ + run_step "Sync application files" rsync -a --delete \ --exclude .git \ --exclude .venv \ --exclude __pycache__ \ @@ -314,10 +356,12 @@ if [ "$SOURCE_DIR" != "$APP_DIR" ]; then --exclude .mypy_cache \ --exclude var \ "$SOURCE_DIR"/ "$APP_DIR"/ +else + note_step "Sync application files" "SKIPPED" fi -python3 -m venv "$VENV_DIR" -"$VENV_DIR/bin/python" -m pip install --upgrade pip +run_step "Create Python virtualenv" python3 -m venv "$VENV_DIR" +run_step "Upgrade pip" "$VENV_DIR/bin/python" -m pip install --upgrade pip case "$INSTALL_EXTRAS" in "") pip_target=$APP_DIR @@ -336,7 +380,7 @@ case "$INSTALL_EXTRAS" in exit 2 ;; esac -"$VENV_DIR/bin/python" -m pip install -e "$pip_target" +run_step "Install Python package" "$VENV_DIR/bin/python" -m pip install -e "$pip_target" if [ ! -f "$ENV_FILE" ] || [ "$FORCE_ENV" -eq 1 ]; then secret=$("$VENV_DIR/bin/python" -c "import secrets; print(secrets.token_urlsafe(48))") @@ -359,8 +403,9 @@ POBSYNC_SCHEDULER_INTERVAL=60 EOF chmod 0640 "$ENV_FILE" chown "root:$SERVICE_GROUP" "$ENV_FILE" - echo "Wrote $ENV_FILE." + note_step "Write environment file" "OK" else + note_step "Write environment file" "SKIPPED" echo "Keeping existing $ENV_FILE. Use --force-env to rewrite it." fi @@ -382,49 +427,63 @@ install_unit() { chmod 0644 "$dest" } -install_unit "$APP_DIR/deploy/systemd/pobsync-web.service" /etc/systemd/system/pobsync-web.service -install_unit "$APP_DIR/deploy/systemd/pobsync-worker.service" /etc/systemd/system/pobsync-worker.service -install_unit "$APP_DIR/deploy/systemd/pobsync-scheduler.service" /etc/systemd/system/pobsync-scheduler.service +install_units() { + install_unit "$APP_DIR/deploy/systemd/pobsync-web.service" /etc/systemd/system/pobsync-web.service + install_unit "$APP_DIR/deploy/systemd/pobsync-worker.service" /etc/systemd/system/pobsync-worker.service + install_unit "$APP_DIR/deploy/systemd/pobsync-scheduler.service" /etc/systemd/system/pobsync-scheduler.service +} -systemctl daemon-reload -"$VENV_DIR/bin/python" "$APP_DIR/manage.py" migrate --noinput -"$VENV_DIR/bin/python" "$APP_DIR/manage.py" collectstatic --noinput --clear -chown -R "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync +run_step "Install systemd units" install_units + +run_step "Reload systemd" systemctl daemon-reload +run_step "Run database migrations" "$VENV_DIR/bin/python" "$APP_DIR/manage.py" migrate --noinput +run_step "Collect static files" "$VENV_DIR/bin/python" "$APP_DIR/manage.py" collectstatic --noinput --clear +run_step "Finalize state permissions" chown -R "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync superuser_exists=$("$VENV_DIR/bin/python" -c "import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pobsync_server.settings'); import django; django.setup(); from django.contrib.auth import get_user_model; print('yes' if get_user_model().objects.filter(is_superuser=True).exists() else 'no')") if [ "$CREATE_SUPERUSER" -eq 1 ]; then if [ "$superuser_exists" = "yes" ]; then - echo "A Django superuser already exists; skipping superuser creation." + note_step "Create Django superuser" "SKIPPED" elif [ -n "$SUPERUSER_USERNAME" ] && [ -n "$SUPERUSER_PASSWORD" ]; then - DJANGO_SUPERUSER_USERNAME=$SUPERUSER_USERNAME \ - DJANGO_SUPERUSER_EMAIL=$SUPERUSER_EMAIL \ - DJANGO_SUPERUSER_PASSWORD=$SUPERUSER_PASSWORD \ + run_step "Create Django superuser" env \ + DJANGO_SUPERUSER_USERNAME="$SUPERUSER_USERNAME" \ + DJANGO_SUPERUSER_EMAIL="$SUPERUSER_EMAIL" \ + DJANGO_SUPERUSER_PASSWORD="$SUPERUSER_PASSWORD" \ "$VENV_DIR/bin/python" "$APP_DIR/manage.py" createsuperuser --noinput - echo "Created Django superuser '$SUPERUSER_USERNAME'." - chown -R "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync + run_step "Finalize superuser permissions" chown -R "$SERVICE_USER:$SERVICE_GROUP" /var/lib/pobsync /var/log/pobsync else + note_step "Create Django superuser" "SKIPPED" echo "No superuser password was provided; create one later with:" echo " sudo -u $SERVICE_USER $VENV_DIR/bin/python $APP_DIR/manage.py createsuperuser" fi elif [ "$superuser_exists" != "yes" ]; then + note_step "Create Django superuser" "SKIPPED" echo "No Django superuser exists yet. Create one with:" echo " sudo -u $SERVICE_USER $VENV_DIR/bin/python $APP_DIR/manage.py createsuperuser" +else + note_step "Create Django superuser" "SKIPPED" fi -systemctl enable --now pobsync-web.service pobsync-worker.service pobsync-scheduler.service +run_step "Enable and start services" systemctl enable --now pobsync-web.service pobsync-worker.service pobsync-scheduler.service if [ "$WITH_NGINX" -eq 1 ]; then if ! command -v nginx >/dev/null 2>&1; then + note_step "Install nginx config" "SKIPPED" echo "nginx is not installed; skipping nginx config." >&2 else sed "s|@POBSYNC_SERVER_NAME@|$SERVER_NAME|g" "$APP_DIR/deploy/nginx/pobsync.conf" > /etc/nginx/sites-available/pobsync.conf ln -sf /etc/nginx/sites-available/pobsync.conf /etc/nginx/sites-enabled/pobsync.conf - nginx -t - systemctl reload nginx + note_step "Install nginx config" "OK" + run_step "Validate nginx config" nginx -t + run_step "Reload nginx" systemctl reload nginx fi +else + note_step "Install nginx config" "SKIPPED" fi -systemctl --no-pager --full status pobsync-web.service pobsync-worker.service pobsync-scheduler.service || true +if [ "$VERBOSE" -eq 1 ]; then + systemctl --no-pager --full status pobsync-web.service pobsync-worker.service pobsync-scheduler.service || true +fi echo echo "pobsync installation complete."