espo-deploy/rmm-tasks/ESPO-03-First-Deploy.sh
Gordon Zimm 4232e059a0 Versionsermittlung mit absoluten Pfaden, Rueckfall und Diagnose
ESPO-20 meldete 'EspoCRM-Version nicht ermittelbar'. Ursache ist vermutlich der
relative Pfad: docker exec startet im Arbeitsverzeichnis des Images, data/...
ohne fuehrenden Schraegstrich geht dann ins Leere.

Jetzt absolute Pfade, beide Konfigurationsdateien (config-internal zuerst), als
Rueckfall ein grep ueber den Bind-Mount. Bleibt es leer, zeigt ESPO-20 welche
Dateien es gibt und welche Schluessel sie tragen - dann ist die Ursache nach
einem Lauf bekannt statt nach dreien.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 16:18:31 +02:00

99 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
# ESPO-03-First-Deploy - richtet EspoCRM auf einer vorbereiteten VM zum ersten Mal ein.
# Aufruf: ESPO-03-First-Deploy.sh <fqdn> <ring>
# Ob der Lauf erlaubt ist, entscheidet der Task selbst per If/Then auf espo_zustand.
# Fuer Aktualisierungen ist der Update-Weg zustaendig. Dass dieser Lauf nur an einer neuen Instanz
# stattfindet, stellt der Task sicher (If/Then auf espo_zustand), nicht das Skript.
set -u
# Standzeile: zeigt im Protokoll, welche Fassung tatsaechlich gelaufen ist.
echo "ESPO-03-First-Deploy, Skriptstand 2026-09-24"
BASIS_URL=https://gitea.subcura.net/EspoCRM_Public/espo-deploy/raw/branch/main
WARTE_MAX=900
FQDN="${1:-}"
RING="${2:-}"
fehler() { echo "FEHLER: $*"; echo "ESPO03_ERGEBNIS: FEHLER"; exit 1; }
# 1. Vorbedingungen - lieber hier abbrechen als auf halbem Weg.
[ "$(id -u)" -eq 0 ] || fehler "nicht als root gestartet"
command -v docker >/dev/null || fehler "Docker fehlt - erst ESPO-02 ausfuehren"
docker info >/dev/null 2>&1 || fehler "Docker laeuft nicht - erst ESPO-02 pruefen"
[ -n "$FQDN" ] || fehler "kein FQDN uebergeben"
[ -n "$RING" ] || fehler "kein Ring uebergeben"
# 2. Verzeichnisse anlegen. Die Eigentuemer setzen die Images beim ersten Start selbst.
install -d -m 0755 /srv/espo /srv/espo/bin /srv/espo/mariadb /srv/espo/data /srv/espo/custom /srv/espo/client-custom
install -d -m 0700 /srv/espo/secrets
# 3. Geheimnisse auf der VM erzeugen - sie stehen in keinem Skript, keiner Ausgabe und keinem Repository.
# Ohne abschliessenden Zeilenumbruch, damit die _FILE-Auswertung der Images genau diesen Wert sieht.
umask 077
for G in db_root_password db_password; do
[ -s "/srv/espo/secrets/$G" ] && continue
printf '%s' "$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32)" > "/srv/espo/secrets/$G"
chmod 0600 "/srv/espo/secrets/$G"
done
umask 022
# 4. Grundeinstellungen bereitlegen, bevor EspoCRM zum ersten Mal startet.
# Sie gehoeren zum Stand des Rings, liegen also im selben Ordner wie die Compose.
# Dieselbe Zuordnung steht in bin/espo-compose-rendern - beide zusammen halten.
case "$RING" in
0) RINGORDNER="0%20-%20intern" ;;
1) RINGORDNER="1%20-%20Pilotkunde" ;;
2) RINGORDNER="2%20-%20Produktivkunde" ;;
*) fehler "unbekannter Ring '$RING' (erwartet 0, 1 oder 2)" ;;
esac
curl -fsSL "$BASIS_URL/docker/$RINGORDNER/config-override.php" -o /srv/espo/data/config-override.php \
|| fehler "config-override.php fuer Ring '$RING' nicht abrufbar"
# 5. Compose aus dem Stand des Rings schreiben.
curl -fsSL "$BASIS_URL/bin/espo-compose-rendern" -o /srv/espo/bin/espo-compose-rendern || fehler "Render-Skript nicht abrufbar"
chmod 0755 /srv/espo/bin/espo-compose-rendern
/srv/espo/bin/espo-compose-rendern "$FQDN" "$RING" || fehler "Compose konnte nicht geschrieben werden"
# 6. Starten. Die Images werden dabei zum ersten Mal geholt.
# --quiet-pull unterdrueckt die Fortschrittszeilen je Schicht; die Ausgabe wird aufgefangen und
# nur im Fehlerfall gezeigt. Sonst ersaeuft der Bericht in tausenden Zeilen (gemessen am 24.09.2026).
START_AUSGABE="$(docker compose -f /srv/espo/docker-compose.yml up -d --quiet-pull 2>&1)" || {
echo "$START_AUSGABE" | tail -n 20
fehler "Start fehlgeschlagen"
}
# 7. Auf die Anwendung warten. Der erste Lauf installiert und baut das Schema auf, das dauert.
ENDE=$(( SECONDS + WARTE_MAX ))
while [ "$SECONDS" -lt "$ENDE" ]; do
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] && break
sleep 10
done
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] \
|| fehler "espocrm nach ${WARTE_MAX}s nicht gesund - 'docker logs espocrm' ansehen"
# 8. Ergebnis zeigen. Die Datenbankabfragen laufen im Container und lesen das Passwort dort aus der Secret-Datei,
# damit es weder im Skript noch in der Prozessliste der VM auftaucht.
echo "--- Container"
docker compose -f /srv/espo/docker-compose.yml ps --format 'table {{.Name}}\t{{.Status}}'
echo "--- Instanz"
echo "FQDN: $FQDN (Ring $RING)"
# Die Version steht je nach Stand in config.php oder in config-internal.php - EspoCRM selbst
# fragen ist verlaesslicher als eine der beiden Dateien zu raten.
VERSION="$(docker exec espocrm php -r 'foreach (["/var/www/html/data/config-internal.php","/var/www/html/data/config.php"] as $f) { $a = @include $f; if (is_array($a) && !empty($a["version"])) { echo $a["version"]; exit; } }' 2>/dev/null)"
[ -n "$VERSION" ] || VERSION="$(grep -hoP "['\"]version['\"]\s*=>\s*['\"]\K[^'\"]+" /srv/espo/data/config.php /srv/espo/data/config-internal.php 2>/dev/null | head -1)"
echo "Version: ${VERSION:-unbekannt}"
IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm 2>/dev/null)"
echo "Image: $IMAGE"
echo "Digest: $(docker image inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{else}}{{.Id}}{{end}}' "$IMAGE" 2>/dev/null)"
DB_ABFRAGE='mariadb -u root -p"$(cat /run/secrets/db_root_password)" -N -B -D espocrm -e'
echo "MariaDB: $(docker exec espocrm-db sh -c "$DB_ABFRAGE \"select version()\"" 2>/dev/null)"
echo "Zeichensatz: $(docker exec espocrm-db sh -c "$DB_ABFRAGE \"select @@character_set_server, @@collation_server\"" 2>/dev/null)"
ID_LAENGE="$(docker exec espocrm-db sh -c "$DB_ABFRAGE \"select length(id) from user limit 1\"" 2>/dev/null)"
echo "ID-Laenge: ${ID_LAENGE:-unbekannt} (36 = UUIDv4 aktiv)"
[ "$ID_LAENGE" = "36" ] || { echo "FEHLER: Record-IDs sind nicht 36 Zeichen lang - recordId.json hat nicht gegriffen"; echo "ESPO03_ERGEBNIS: FEHLER"; exit 1; }
echo "--- Naechster Schritt von Hand"
echo "Admin-Passwort ('admin') in der Instanz aendern, im Passwort-Safe ablegen,"
echo "erst danach DNS-Eintrag und Portfreigabe an der OPNsense setzen."
echo "ESPO03_ERGEBNIS: OK"