31 Commits

Author SHA1 Message Date
b18633281d Version aus EspoCRM selbst lesen statt aus den Vorgaben des Images
ESPO-03, ESPO-10, ESPO-12 und ESPO-20 lasen version aus
defaults/config.php, config.php und config-internal.php. EspoCRM 10 fuehrt
version aber als State-Parameter in data/state.php, und Config::load() liest
die Image-Vorgaben gar nicht. Gemeldet wurde also der Vorgabewert des Images:
nach einem gescheiterten migrate die neue Version, obwohl die Instanz auf der
alten steht.

Jetzt fragen die Skripte EspoCRM ueber "command.php version" - derselbe Wert,
gegen den auch Extensions ihre acceptableVersions pruefen. Aufruf als
www-data mit absolutem Pfad (bootstrap.php wechselt selbst ins
Installationsverzeichnis); akzeptiert wird nur eine Zeile der Form 1.2.3,
damit eine PHP-Warnung nie als Version in ein Custom Field geraet. Die
grep-Rueckfallwege auf config.php entfallen, sie lasen dieselbe falsche Quelle.

Probe gegen die Integrationsinstanz 10.0.8: Ausgabe "10.0.8".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:16:09 +02:00
815e197dea ESPO-02: apt-Ausgabe auffangen, Standmeldungen in die stumme Strecke
Der erste Lauf auf der Pilotkunden-VM endete Failed, sichtbar war nur
needrestarts Abschlussmeldung aus dem apt-Lauf - also die Stelle, an der die
Pakete fertig installiert waren. Zwischen apt-mark hold und docker --version
gibt das Skript nichts aus; aus dem Protokoll liess sich deshalb nicht lesen,
wo der Lauf stehen geblieben ist.

Zwei Aenderungen: Die lange Ausgabe des apt-Laufs wird aufgefangen und nur im
Fehlerfall gezeigt (letzte 30 Zeilen) - sie verdraengt sonst den Bericht am
Ende, dasselbe Problem wie der Pull-Fortschritt bei ESPO-03. Und die stumme
Strecke bekommt vier knappe Standmeldungen, sodass die letzte Zeile der
Ausgabe immer verraet, wie weit der Lauf gekommen ist.

Ausserdem tragen jetzt alle Abbrueche des Hauptskripts die Zeile
ESPO02_ERGEBNIS: FEHLER - der Script Monitor sucht danach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 10:17:22 +02:00
6623036011 ESPO-01: sshd -t scheitert auf einer VM ohne bisherige SSH-Verbindung
Gemeldet von der ersten Pilotkunden-VM: "Missing privilege separation
directory: /run/sshd". Ubuntu 24.04 startet sshd ueber ssh.socket erst bei
der ersten Verbindung; /run/sshd legt systemd dabei an (RuntimeDirectory).
Auf einer frisch installierten VM, an der bisher nur die Hyper-V-Konsole
benutzt wurde, existiert das Verzeichnis deshalb nicht - und sshd -t bricht
ab, obwohl die Konfiguration einwandfrei ist. Auf der Test-VM fiel das nicht
auf, weil dort per SSH gearbeitet wurde.

Das Skript legt /run/sshd jetzt selbst an (0755, wie die Unit), laedt sshd
nur neu, wenn er ueberhaupt als Dienst laeuft, und gibt die wirksamen Werte
aus sshd -T aus. Sind sie nicht auslesbar, ist die Haertung unbewiesen und
der Lauf ein Fehler.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-25 10:09:24 +02:00
f4d53a68d8 Hostname mit Praefix espo- statt crm-
Einheitlich zum Rest des Vorhabens: /srv/espo, espo-deploy, espo-fleet-ops,
ESPO-xx, espo_*-Felder. Das Praefix nennt ausserdem das Produkt statt einer
Kategorie - 'crm' steht ohnehin schon im FQDN.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 17:53:32 +02:00
df6c3c530d ESPO-01 nimmt die Company Unique Id statt des Firmennamens
Die Unique Id ist in den Stammdaten ein Pflichtfeld und laut Dialog eindeutig -
kurz, stabil und vom Firmennamen unabhaengig: glasfaktor statt
glasfaktor-ingenieure-gmbh. Der Task uebergibt kuenftig %companyuniqueid%.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 17:49:09 +02:00
5c15ac3f0b Drei Verbesserungen an den Update-Skripten
1. Gewartet wird jetzt auf ALLE vier Container, nicht nur auf espocrm.
   "health: starting" im Bericht war keine Aussage. Scheitert es, nennt die
   Fehlermeldung, welcher Container in welchem Zustand haengt. Gilt fuer
   ESPO-03, ESPO-10 und ESPO-12.

2. ESPO-10 raeumt alte Images weg: Es bleiben genau zwei je Anwendung, das
   laufende und das vorherige - fuer EspoCRM wie fuer MariaDB. Das vorherige
   muss bleiben, sonst zeigt die von ESPO-12 zurueckgerollte Compose auf einen
   Tag, der lokal nicht mehr liegt. Alles aeltere fuellte bisher nur das
   docker-lv; Docker raeumt von sich aus nichts weg.

3. ESPO-10 zeigt einen eigenen Abschnitt "Datenbank" mit Image, Version und
   Digest, analog zum Abschnitt "Instanz", sowie die Images auf der VM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 17:21:54 +02:00
e63d1b432b ESPO-12 belegt, dass der Snapshot verbraucht ist
Beim Zusammenfuehren verbraucht LVM den Snapshot; bleibt er stehen, wurde das
Zusammenfuehren auf die naechste Aktivierung verschoben und der Stand ist noch
nicht zurueckgenommen. Das Skript sagt jetzt welches von beidem eingetreten ist
und zeigt am Ende die freien Extents - wie ESPO-11 es tut.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 17:15:23 +02:00
42de4be4d6 ESPO-12 heisst jetzt Snapshot-wiederherstellen
Parallel zu ESPO-11-Snapshot-verwerfen; der Name sagt, was passiert, statt wohin
es fuehrt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 17:01:33 +02:00
580c02af36 ESPO-12-Rueckweg: Snapshot zusammenfuehren statt neu starten
Stack anhalten, /srv aushaengen, lvconvert --merge, wieder einhaengen, starten.
Das Aushaengen ist der Kern: Ist der Ursprung geoeffnet, verschiebt LVM das
Zusammenfuehren auf die naechste Aktivierung, also auf einen Neustart - hier
geschieht es sofort und nachpruefbar.

Scheitert etwas vor dem Zusammenfuehren, wird der Dienst wieder gestartet und
nichts zurueckgenommen: eine stehende Instanz ist das schlechteste Ergebnis.
Ein ungueltiger Snapshot fuehrt zum ehrlichen Abbruch statt zu einem Versuch.

Weil ganz /srv zurueckgenommen wird, kommt auch die gerenderte Compose mit dem
alten Image-Tag zurueck - die Instanz startet damit von selbst auf dem alten
Stand, ohne Migration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 16:56:04 +02:00
e79564445d ESPO-20: Diagnoseblock entfernt
Die Ursache ist bekannt - die Version steht in den Vorgabewerten des Images.
Das Geruest zur Fehlersuche kann damit weg.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 16:29:06 +02:00
f1701675ef Version tatsaechlich aus den Vorgabewerten lesen (Nachtrag zu 86bc5d9)
Der vorige Commit hat nur den Kommentar geaendert, der Ersetzungsausdruck griff
nicht. Jetzt lesen alle drei Skripte defaults, config und config-internal in
dieser Reihenfolge; der spaetere Wert gewinnt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 16:21:55 +02:00
86bc5d9204 Version aus den Vorgabewerten des Images lesen
Gemessen: Auf einer frisch installierten Instanz steht 'version' weder in
data/config.php noch in data/config-internal.php - EspoCRM schreibt nur, was
vom Vorgabewert abweicht. Beide Dateien luden einwandfrei, der Schluessel fehlt
schlicht.

Gelesen werden jetzt alle drei Dateien in der Reihenfolge, in der EspoCRM sie
selbst zusammenfuehrt: defaults, config, config-internal - der spaetere Wert
gewinnt. Nach einem Upgrade sticht damit data/config.php den Vorgabewert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 16:21:24 +02:00
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
e74669ef39 ESPO-20-Inventar: misst vier Werte einmal, legt sie unter /run/espo-inventar ab
Eine Messung fuer alle Werte - sie stammen aus demselben Augenblick, die teuren
Aufrufe passieren einmal, und die Wertzeilen im Task sind nur noch ein cat.

Laesst sich ein Wert nicht ermitteln, bricht der Schritt ab; die Folgezeilen
laufen dann nicht und kein Feld wird ueberschrieben. Eine stehende Instanz darf
die Werte nicht leeren, sonst sieht eine Stoerung aus wie eine leere Instanz.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 15:45:51 +02:00
c2b37dd8fa Nummernkreise: Update-Block beginnt bei ESPO-10
Aus ESPO-04 und ESPO-05 werden ESPO-10 und ESPO-11. Ein Zehnerkreis
kennzeichnet den Block und beginnt bei x0; 0x bleibt der Weg von der leeren VM
zur laufenden Instanz, 1x das Aktualisieren, 2x Betrieb und Ueberwachung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 14:42:04 +02:00
449627de30 Update-Weg: ESPO-04 mit Snapshot als Riegel, ESPO-05 zum Verwerfen
ESPO-04 legt zuerst den LVM-Snapshot an und bricht ab, wenn das nicht gelingt -
kein Update ohne Rueckweg. Es bricht ausserdem ab, wenn noch ein Snapshot aus
einem frueheren Lauf besteht: Das hiesse, dass das vorige Update nie bestaetigt
wurde, und zwei Snapshots uebereinander waeren kein Rueckweg mehr.

ESPO-05 verwirft den Snapshot, nachdem jemand die Instanz geprueft hat, und
haelt vorher Fuellgrad und Gueltigkeit fest - war er bereits vollgelaufen, hat
der Rueckweg schon vorher nicht mehr getragen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 14:37:45 +02:00
0d8aeccff8 config-override.php je Ring statt einmal fuer alle
Die Grundeinstellungen gehoeren zum Stand eines Rings wie die Compose: Eine
Aenderung daran soll denselben Freigabeweg nehmen. Die Datei liegt jetzt in
allen drei Ringordnern, die gemeinsame Fassung ist entfallen.

ESPO-03 holt sie aus dem Ordner des jeweiligen Rings; die Zuordnung Ring zu
Ordner steht damit an zwei Stellen und ist in beiden vermerkt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 12:14:49 +02:00
c0e62788c0 ESPO-03 liest die Version aus EspoCRM selbst
Der Abnahmelauf meldete 'Version: unbekannt' - das grep auf data/config.php
griff nicht. Jetzt fragt das Skript EspoCRM im Container (config.php und
config-internal.php zusammengefuehrt) und faellt nur ersatzweise auf grep
ueber beide Dateien zurueck.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 11:33:46 +02:00
f33d2d5131 ESPO-03: Compose-Ausgabe auffangen, nur im Fehlerfall zeigen
Der erste Lauf hat die Instanz erfolgreich gestartet (db und espocrm healthy,
daemon und websocket gestartet), der Task galt aber als Failed: Die tausenden
Fortschrittszeilen des Image-Pulls haben den Abschlussbericht verdraengt.

up -d laeuft jetzt mit --quiet-pull, die Ausgabe wird aufgefangen und nur bei
Fehlschlag mit den letzten 20 Zeilen gezeigt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 11:08:47 +02:00
f90a142462 ESPO-03 ohne eigene Instanzpruefung: der Riegel liegt im Task
Die Pruefung auf vorhandene Container, docker-compose.yml und data/config.php
entfaellt. Dass der Lauf nur an einer neuen Instanz stattfindet, stellt der Task
ueber If/Then auf espo_zustand sicher.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 10:19:21 +02:00
995ef4b461 ScreenConnect-Block und apt-Diagnose wieder entfernt
Der haengende ScreenConnect-Client wird ueber die Default-Policies geloest, damit
er gar nicht erst installiert wird - nicht im Skript. ESPO-01 ist damit wieder
auf seine neun Schritte zurueck, ESPO-02 auf die knappe Fehlerzeile.

Aus der offiziellen Docker-Doku bleibt, was dorthin gehoert: das Entfernen
konkurrierender Pakete vor der Installation und ca-certificates/curl vor dem
Schluessel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 10:02:54 +02:00
d4e0294bfd ESPO-01 entfernt ScreenConnect und prueft apt - Ursache der ESPO-02-Fehler
Auf der Test-VM liegt der ScreenConnect-Client des Agenten im Zustand iU
(entpackt, nie konfiguriert), weil ihm java5-runtime fehlt. In diesem Zustand
blockiert er jede apt-Operation; ESPO-02 scheiterte daran, nicht an den
Docker-Pins.

ESPO-01 entfernt den Client jetzt als erstes (Paketname traegt je Geraet ein
anderes Suffix, daher Mustersuche), raeumt mit --fix-broken auf und bricht ab,
wenn apt danach immer noch gebrochene Abhaengigkeiten meldet. Damit ist O-20
im Skript erledigt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 09:47:49 +02:00
9663fcb753 Standzeile in allen drei Skripten: zeigt im Protokoll, welche Fassung lief
Zwei apt-Fehler ohne eine einzige Zeile aus dem Skript liessen offen, ob
ueberhaupt die Repo-Fassung gelaufen ist. Die Standzeile beantwortet das
kuenftig in der ersten Ausgabezeile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 09:44:00 +02:00
76962b9cf2 ESPO-02 folgt der offiziellen Doku: konkurrierende Pakete zuerst entfernen
Der Abgleich mit docs.docker.com/engine/install/ubuntu zeigte eine fehlende
Vorstufe: Die Doku verlangt, docker.io, docker-compose, docker-doc,
docker-buildx, podman-docker sowie containerd und runc zu entfernen, bevor
installiert wird - containerd.io buendelt containerd und runc und steht mit
beiden in Conflicts. Genau das passt zum Symptom "unerfuellte Abhaengigkeiten".

Ausserdem wie in der Doku ca-certificates und curl vor dem Schluessel. Die
deb822-Quelle entspricht bereits woertlich der Doku; beim Pinning bleiben wir
strenger als sie (sie pinnt nur docker-ce und docker-ce-cli).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 09:22:39 +02:00
2cc7896715 ESPO-02 sagt bei gescheiterter Installation, woran es liegt
Die vier gepinnten Versionen existieren im Docker-Repo fuer noble (geprueft
gegen den Packages-Index), die Ursache liegt also woanders. Statt zu raten
gibt das Skript jetzt im Fehlerfall die Simulation von apt (mit der konkreten
unerfuellten Abhaengigkeit), die verfuegbaren Versionen inklusive iptables und
nftables, die bereits installierten Docker-Pakete und haengende Installationen
aus. Ausserdem -q statt -qq, damit apt ueberhaupt etwas sagt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 09:07:30 +02:00
4b5440968b Zustandspruefung wandert in den Task: Skripte ohne ZUSTAND-Argument
Der Task entscheidet per If/Then auf espo_zustand, ob er laufen darf; die
Skripte brauchen den Wert dann nicht mehr. ESPO-01 nimmt nur noch den
Kundennamen, ESPO-02 kein Argument, ESPO-03 fqdn und ring.

In ESPO-03 bleibt die Pruefung auf eine vorhandene Instanz - sie beruht auf
Tatsachen auf der VM, nicht auf einem Feldwert, und verhindert eine Migration
ohne geprueftes Backup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 17:43:48 +02:00
dcd99c3ba9 Zustandsriegel: die drei Einrichtungsskripte laufen nur bei espo_zustand = NEU
Statt lokaler Merkmale steuert das Custom Field espo_zustand zentral, was laufen
darf. Jedes der drei Skripte nimmt den Wert als Argument und bricht ohne
Aenderung ab, wenn er nicht NEU ist.

In ESPO-03 bleibt die Pruefung auf eine vorhandene Instanz als Rueckfall
erhalten: Der Zustand im RMM ist von Hand aenderbar, eine laufende Instanz ist
es nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 15:10:15 +02:00
25b2603856 ESPO-03-First-Deploy: Erstinbetriebnahme von EspoCRM
Richtet EspoCRM auf einer vorbereiteten VM zum ersten Mal ein: Verzeichnisse,
Geheimnisse auf der VM erzeugt, config-override.php bereitgelegt, Compose aus
dem Stand des Rings gerendert, up -d, Warten auf app-check, Abschlusspruefung.

Bricht ab, sobald eine Instanz vorhanden ist (Container, Compose-Datei oder
data/config.php). Damit kann dieses Skript keine Migration ohne geprueftes
Backup ausloesen - Aktualisierungen bekommen einen eigenen Weg.

Die Abschlusspruefung misst zugleich die in ADR 0008 offenen Punkte:
Zeichensatz des Servers und Laenge der Record-IDs (36 = UUIDv4 aktiv, sonst
Abbruch). Die Datenbankabfragen laufen im Container und lesen das Passwort dort
aus der Secret-Datei.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 14:47:27 +02:00
996490075a Compose-Vorlage, EspoCRM-Grundeinstellungen und Render-Skript
Die Vorlage ist fuer alle Kunden identisch und traegt genau einen Platzhalter
(__FQDN__); bin/espo-compose-rendern setzt ihn ein und schreibt
/srv/espo/docker-compose.yml. Keine .env mehr: alles ausser den Geheimnissen
steht in der Compose selbst.

Inhalt der Vorlage: Bind-Mounts unter /srv/espo, Datei-Secrets fuer die beiden
MariaDB-Passwoerter, Record-IDs als uuid4/36 ueber configs (in allen drei
EspoCRM-Diensten, weil configs nicht ueber volumes_from vererbt werden),
adminUpgradeDisabled, WebSocket ueber wss://<fqdn>/wss, Healthchecks mit
Startfenstern fuer den Migrationslauf.

ESPO-02 setzt keine abweichende Bindeadresse mehr - die Ports muessen fuer den
Reverse Proxy erreichbar sein. Stattdessen beschraenkt eine DOCKER-USER-Regel
den Zugang auf das eigene Subnetz, das die VM selbst ermittelt; eine
systemd-Unit setzt sie nach jedem Docker-Start neu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 14:22:59 +02:00
81d86ba363 ESPO-01 nimmt den Kundennamen als Argument (duenner Ausloeser im RMM)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 10:18:37 +02:00
9c812fcac5 ESPO-01 (Grundeinrichtung) und ESPO-02 (Docker) als versionierte Task-Skripte
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 10:16:44 +02:00