(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.
This commit is contained in:
@@ -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."
|
||||
|
||||
Reference in New Issue
Block a user