feat(nexus): runtime provisioning for the decided stack (nexus-hub K-101)

- new install/nexus-runtime.sh (idempotent, re-runnable on an existing
  LXC): uv for the nexus user (manages Python 3.12), tesseract deu+eng,
  nexus-worker.service unit (ConditionPathExists guards the skeleton
  phase), sudoers extended to cover the worker service
- nexus-install.sh: RUNTIME section now invokes nexus-runtime.sh at the
  end of the install (after base sudoers/units, which it extends)
This commit is contained in:
2026-06-11 14:48:53 +02:00
parent 34ac5a05f6
commit 1dd89e25bc
2 changed files with 99 additions and 5 deletions
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
# nexus runtime provisioning — idempotent, runs inside the nexus LXC as root.
#
# Added by nexus-hub card K-101 (stack scaffold). Installs everything the
# decided stack (nexus-hub ADR-0002) needs at runtime ON TOP of the base
# nexus-install.sh provisioning:
# - uv for the `nexus` user (manages Python 3.12 per pyproject.toml)
# - tesseract OCR with deu+eng language packs (ingest cards K-107+)
# - nexus-worker.service systemd unit (analysis worker, queue with K-105)
# - sudoers extension so the Actions runner may also restart the worker
#
# Called by install/nexus-install.sh (RUNTIME section) during fresh installs.
# To retrofit an EXISTING LXC (documented K-101 follow-up step), run inside it:
#
# curl -fsSL https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/install/nexus-runtime.sh | bash
#
# Safe to re-run at any time.
set -euo pipefail
LIB_URL="${LIB_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/lib}"
source <(curl -fsSL "$LIB_URL/install.func")
[[ "$EUID" -eq 0 ]] || { msg_err "Must run as root"; exit 1; }
APP_USER="nexus"
APP_HOME="/opt/nexus"
CURRENT_DIR="$APP_HOME/current"
run_user() { runuser -u "$APP_USER" -- env HOME="$APP_HOME" PATH="$APP_HOME/.local/bin:/usr/local/bin:/usr/bin:/bin" "$@"; }
id "$APP_USER" >/dev/null 2>&1 || { msg_err "user $APP_USER missing — run nexus-install.sh first"; exit 1; }
# ── OCR stack (ING-3: tesseract deu+eng) ──────────────────────────────────────
msg_info "Installing tesseract (deu+eng)..."
apt-get install -y -qq tesseract-ocr tesseract-ocr-deu tesseract-ocr-eng >/dev/null
msg_ok "tesseract $(tesseract --version 2>/dev/null | head -n1 | awk '{print $2}')"
# ── uv for the nexus user (provides Python 3.12 via pyproject/uv.lock) ────────
if [[ ! -x "$APP_HOME/.local/bin/uv" ]]; then
msg_info "Installing uv for $APP_USER..."
run_user bash -c "curl -LsSf https://astral.sh/uv/install.sh | sh" >/dev/null
msg_ok "uv $(run_user "$APP_HOME/.local/bin/uv" --version | awk '{print $2}') installed"
else
msg_warn "uv already present ($(run_user "$APP_HOME/.local/bin/uv" --version | awk '{print $2}')), skipping"
fi
run_user "$APP_HOME/.local/bin/uv" python install 3.12 >/dev/null 2>&1 || true
msg_ok "Python 3.12 toolchain available via uv"
# ── nexus-worker.service ──────────────────────────────────────────────────────
cat >/etc/systemd/system/nexus-worker.service <<EOF
[Unit]
Description=nexus — analysis worker (job queue arrives with K-105)
After=network-online.target
Wants=network-online.target
# Skeleton-safe: only start once the deploy artifact provides the entrypoint.
ConditionPathExists=$CURRENT_DIR/start-worker.sh
[Service]
Type=simple
User=$APP_USER
Group=$APP_USER
WorkingDirectory=$CURRENT_DIR
EnvironmentFile=/etc/nexus/env
ExecStart=$CURRENT_DIR/start-worker.sh
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
# ── sudoers: extend the narrow rule to cover the worker service ───────────────
cat >/etc/sudoers.d/nexus-deploy <<EOF
$APP_USER ALL=(root) NOPASSWD: /usr/bin/systemctl restart nexus.service, /usr/bin/systemctl start nexus.service, /usr/bin/systemctl stop nexus.service, /usr/bin/systemctl status nexus.service, /usr/bin/systemctl restart nexus-worker.service, /usr/bin/systemctl start nexus-worker.service, /usr/bin/systemctl stop nexus-worker.service, /usr/bin/systemctl status nexus-worker.service
EOF
chmod 440 /etc/sudoers.d/nexus-deploy
visudo -cf /etc/sudoers.d/nexus-deploy >/dev/null
systemctl daemon-reload
systemctl enable nexus-worker.service >/dev/null 2>&1
msg_ok "nexus-worker.service installed + enabled (starts once a deploy ships start-worker.sh)"
msg_ok "nexus runtime provisioning finished (idempotent — safe to re-run)"