feat: clusev host CLI wrapper for short stack commands
parent
503f4d7fdf
commit
580c72a59d
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env bash
|
||||
# Clusev host CLI — short wrappers around the production stack.
|
||||
# Generated by install.sh (it substitutes __CLUSEV_DIR__ with the install directory) and
|
||||
# installed to /usr/local/bin/clusev. Operators run `clusev <command>` from anywhere instead
|
||||
# of long `docker compose -f docker-compose.prod.yml ...` invocations. The compose filename is
|
||||
# referenced internally only — it is never printed to the operator.
|
||||
set -euo pipefail
|
||||
|
||||
CLUSEV_DIR="__CLUSEV_DIR__"
|
||||
COMPOSE_FILE="${CLUSEV_DIR}/docker-compose.prod.yml"
|
||||
|
||||
compose() { docker compose -f "$COMPOSE_FILE" "$@"; }
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
clusev — Fleet-Control Verwaltung (Host)
|
||||
|
||||
sudo clusev update Update holen, Image neu bauen, Migrationen anwenden (root)
|
||||
clusev reset-admin Admin-Zugang zuruecksetzen (2FA entfernen, Passwort neu setzen)
|
||||
clusev restart Stack neu starten
|
||||
clusev logs [dienst] Logs folgen (Strg-C beendet)
|
||||
clusev ps Dienst-Status (Alias: status)
|
||||
clusev migrate Datenbank-Migrationen anwenden
|
||||
clusev artisan <...> beliebiges artisan-Kommando im app-Container
|
||||
clusev version installierte Version anzeigen
|
||||
clusev help diese Uebersicht
|
||||
|
||||
Was im Hintergrund laeuft:
|
||||
update -> update.sh (git pull + Image-Rebuild + migrate)
|
||||
reset-admin -> docker compose exec app php artisan clusev:reset-admin
|
||||
migrate -> docker compose exec app php artisan migrate --force
|
||||
EOF
|
||||
}
|
||||
|
||||
cmd="${1:-help}"; shift 2>/dev/null || true
|
||||
case "$cmd" in
|
||||
update) exec "${CLUSEV_DIR}/update.sh" "$@" ;;
|
||||
reset-admin) compose exec app php artisan clusev:reset-admin "$@" ;;
|
||||
restart) compose up -d "$@" ;;
|
||||
logs) compose logs -f "$@" ;;
|
||||
ps|status) compose ps "$@" ;;
|
||||
migrate) compose exec app php artisan migrate --force "$@" ;;
|
||||
artisan) compose exec app php artisan "$@" ;;
|
||||
version) grep -oE "'version' => '[^']+'" "${CLUSEV_DIR}/config/clusev.php" \
|
||||
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true ;;
|
||||
help|-h|--help) usage ;;
|
||||
*) printf 'Unbekannter Befehl: %s\n\n' "$cmd" >&2; usage; exit 64 ;;
|
||||
esac
|
||||
15
install.sh
15
install.sh
|
|
@ -312,8 +312,19 @@ ADMIN_PW="$(printf '%s\n' "$INSTALL_OUT" | sed -n 's/^CLUSEV_ADMIN_PASSWORD=//
|
|||
ADMIN_MAIL="$(printf '%s\n' "$INSTALL_OUT" | sed -n 's/^CLUSEV_ADMIN_EMAIL=//p' | head -n1)"
|
||||
[ -n "$ADMIN_MAIL" ] || ADMIN_MAIL="$ADMIN_EMAIL"
|
||||
|
||||
# ── [9/9] MOTD (themed, shown at host login) ─────────────────────────
|
||||
phase 9/9 "MOTD installieren"
|
||||
# ── [9/9] Host-CLI + MOTD ────────────────────────────────────────────
|
||||
phase 9/9 "Host-CLI + MOTD installieren"
|
||||
|
||||
# clusev host command: bake the install dir into the template, drop it in PATH. Literal
|
||||
# (not sed) substitution so any path is safe; best-effort with the whole group's stderr muted
|
||||
# so a read-only /usr/local/bin never fails the installer (no stray "Permission denied").
|
||||
cli_template="$(cat docker/clusev/clusev)"
|
||||
cli_rendered="${cli_template//__CLUSEV_DIR__/$(pwd)}"
|
||||
if { printf '%s\n' "$cli_rendered" > /usr/local/bin/clusev && chmod 0755 /usr/local/bin/clusev; } 2>/dev/null; then
|
||||
info "Host-Befehl installiert: clusev (z. B. 'clusev ps', 'sudo clusev update')"
|
||||
else
|
||||
info "Host-Befehl uebersprungen (/usr/local/bin nicht beschreibbar)"
|
||||
fi
|
||||
if [ -n "$DOMAIN" ] && [ "$DOMAIN_OK" = 1 ]; then
|
||||
ACCESS_URL="https://${DOMAIN}"
|
||||
elif [ -n "$DOMAIN" ]; then
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env bash
|
||||
# Verifies the clusev host CLI template renders and behaves. No docker needed — only the
|
||||
# help / version / unknown-command paths are exercised. Run from the repo root:
|
||||
# bash tests/scripts/test-clusev-cli.sh
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/../.."
|
||||
REPO="$(pwd)"
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
fail() { printf 'FAIL: %s\n' "$1" >&2; exit 1; }
|
||||
|
||||
# Render the template the way install.sh does.
|
||||
sed "s|__CLUSEV_DIR__|${REPO}|g" docker/clusev/clusev > "${TMP}/clusev"
|
||||
chmod +x "${TMP}/clusev"
|
||||
CLI="${TMP}/clusev"
|
||||
|
||||
# 1. Valid bash syntax.
|
||||
bash -n "$CLI" || fail "syntax error in rendered clusev"
|
||||
|
||||
# 2. help lists the key subcommands.
|
||||
out="$("$CLI" help)"
|
||||
for needle in "clusev update" "clusev reset-admin" "clusev logs" "clusev ps" "clusev migrate"; do
|
||||
printf '%s' "$out" | grep -qF "$needle" || fail "help missing: $needle"
|
||||
done
|
||||
|
||||
# 3. bare invocation and --help also show usage.
|
||||
"$CLI" | grep -qF "clusev reset-admin" || fail "bare invocation did not show usage"
|
||||
"$CLI" --help | grep -qF "clusev reset-admin" || fail "--help did not show usage"
|
||||
|
||||
# 4. unknown command exits 64 and warns on stderr.
|
||||
set +e
|
||||
"$CLI" definitely-not-a-command >/dev/null 2>"${TMP}/err"; rc=$?
|
||||
set -e
|
||||
[ "$rc" -eq 64 ] || fail "unknown command exit = $rc (want 64)"
|
||||
grep -qF "Unbekannter Befehl" "${TMP}/err" || fail "unknown command did not warn"
|
||||
|
||||
# 5. version reads config/clusev.php (no docker).
|
||||
want="$(grep -oE "'version' => '[^']+'" config/clusev.php | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)"
|
||||
got="$("$CLI" version)"
|
||||
[ "$got" = "$want" ] || fail "version = '$got' (want '$want')"
|
||||
|
||||
# 6. install.sh wires the CLI into PATH.
|
||||
grep -qF "/usr/local/bin/clusev" install.sh || fail "install.sh does not install /usr/local/bin/clusev"
|
||||
|
||||
# 7. usage text must NOT leak the long compose filename.
|
||||
printf '%s' "$out" | grep -qF "docker-compose.prod.yml" && fail "usage leaks docker-compose.prod.yml"
|
||||
|
||||
printf 'ok — clusev CLI checks passed\n'
|
||||
Loading…
Reference in New Issue