Remove offline sample targets; load containers from appsettings KnownContainers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-24 12:20:26 +02:00
co-authored by Cursor
parent d1b95bcb9d
commit ade63d0e43
11 changed files with 956 additions and 131 deletions
@@ -0,0 +1,530 @@
# Komplette Erklärung: ESB Certificate Manager
Was passiert **einzeln, von oben nach unten**.
Zertifikat prüfen · Ziele laden · Sonic-API · Container-Neustart.
Diese Datei ist zum Erklären (Präsentation, Kollegen, Übergabe).
Technischer Fokus: aktueller Stand mit **MfApi-Neustart** und **lokaler Zertifikatserkennung**.
---
# Teil A Was die Anwendung ist
## A1. Zweck in einem Satz
Die WinForms-App hilft dabei,
1. ein **Zertifikat als Datei zu erkennen und lokal zu prüfen**, und
2. einen **Sonic-/ESB-Container remote neu zu starten** so ähnlich wie der Restart-Button in der **Sonic Management Console (SMC)**.
## A2. Was sie bewusst *nicht* macht (aktuell)
| Nicht aktiv | Erklärung |
|-------------|-----------|
| Zertifikat auf den Server **kopieren** | Deploy-Button ist ausgeblendet |
| Nach dem Deploy **TLS gegen den Endpoint prüfen** | früher TLS-Probe entfernt/deaktiviert |
| **XApi** importieren | nicht mehr im Pfad |
| Neustart per **`stopcontainer.bat`** | oft in SMC-only-Installationen nicht vorhanden |
| Neustart per **WinRM / Windows-Login** | SMC-User ≠ Windows-User |
| Eigene **HTTP-REST-API** der App | die App *ist* kein Server; sie *ruft* Sonic auf |
## A3. Die wichtigsten Namen in eurer Umgebung
| Name | Typ | Beispiel |
|------|-----|----------|
| Verbindungs-Alias | Eintrag in `appsettings` | `DE-Test` |
| Domain | Sonic-Domain | `proalpha-test` |
| Container (kurz) | Laufzeit-Container | `ct-ZADBService` |
| ObjectName (JMX) | vollständige Agent-Adresse | `proalpha-test.ct-ZADBService:ID=AGENT` |
| ConnectionUrl | Domain-Manager wie in SMC | `tcp://dekun-painwbdet:13070` |
| Login | SMC-Credentials | `Administrator` / `Administrator` |
| Sonic-Libs | Client-JARs | `C:\DEV\MQ10.0\lib` |
| Java | Runtime für das Hilfstool | JRE 1.8+ |
**Merksatz:**
`DE-Test` = Verbindung. `ct-ZADBService` = Container. Nicht vertauschen.
---
# Teil B Programmstart (was zuerst passiert)
## B1. Start der App
1. `Program.cs` startet `Form1`.
2. `AppSettingsLoader` liest `appsettings.json` (aus dem Output-Ordner der App).
3. Es werden gebaut:
- `DeploymentOrchestrator` (Neustart-Orchestrierung)
- `SonicContainerDiscovery` (Container-Liste optional laden)
4. Die UI (Dark-Design) wird aufgebaut.
5. Beim ersten Anzeigen (`Shown`) werden Ziele geladen.
## B2. Ziele laden
1. Ziele kommen aus `appsettings.json``SonicConnections[].KnownContainers` (kein Offline-JSON).
2. Jede Zeile hat u. a.:
- Anzeigename (`DE-Test / ct-ZADBService`)
- Umgebung = Domain
- **ContainerName** (z. B. `ct-ZADBService`)
- **SonicConnectionName** (z. B. `DE-Test`)
- Status-Spalte
Optional: Button **„Container laden“** fragt Sonic live per API und merged mit `KnownContainers`.
---
# Teil C Zertifikat: Erkennen & Verifizieren (Schritt für Schritt)
Hier geht es **nur um die lokale Datei**. Es wird nichts auf den ESB geschrieben und kein TLS zum Server aufgebaut.
## C1. Benutzer wählt Datei
1. Klick auf Dateiauswahl in der UI.
2. `OpenFileDialog` filtert: `.cer`, `.crt`, `.pem`, `.pfx`.
3. Abbruch → nichts ändert sich.
4. Dateiendung wird geprüft (`IsSupportedCertificateFile`).
5. Unbekanntes Format → Warnung, Ende.
## C2. Datei lesen
1. Aufruf `TryReadSelectedCertificate(pfad)`.
2. Intern: `X509Certificate2` laden.
3. **PFX-Sonderfall:**
- Zuerst Versuch *ohne* Passwort.
- Bei `CryptographicException` → Passwort-Dialog.
- Falsches Passwort → Fehlermeldung, kein Zertifikat geladen.
4. Andere Fehler (Datei kaputt, kein X.509) → Fehlermeldung.
## C3. Was aus dem Zertifikat extrahiert wird
| Feld | Quelle | Anzeige |
|------|--------|---------|
| Subject | `GetNameInfo(SimpleName)` bzw. `Subject` | „Ausgestellt für“ |
| Issuer | Issuer-SimpleName bzw. `Issuer` | „Ausgestellt von“ |
| Gültig von / bis | `NotBefore` / `NotAfter` | Datum |
| Fingerprint | SHA-256 Hash, mit `:` formatiert | z. B. `AB:CD:…` |
| Gültigkeitsstatus | `now` zwischen NotBefore und NotAfter? | grün GÜLTIG / rot UNGÜLTIG |
## C4. Was „Verifizierung“ hier genau heißt
| Prüfung | Passiert? | Bedeutung |
|---------|-----------|-----------|
| Datei lesbar als X.509 | ja | Format/Inhalt ok |
| Zeitlich gültig | ja | nicht abgelaufen / noch nicht gültig |
| Fingerprint anzeigen | ja | manueller Abgleich möglich |
| Signaturkette gegen Windows-CA | **nein** | nicht implementiert |
| Datei auf ESB kopieren | **nein** | Deploy aus |
| TLS-Handshake zum Live-System + Fingerprint vergleichen | **nein** | TLS-Probe aus |
**Erklärsatz:**
> Wir verifizieren das Zertifikat **als Datei auf dem PC** (lesbar + Gültigkeitszeitraum + Fingerprint).
> Wir verifizieren **nicht**, dass genau dieses Zertifikat schon am laufenden ESB hängt.
> Der Neustart ist davon getrennt.
## C5. UI nach erfolgreichem Laden
1. Pfad steht im Textfeld.
2. Metadaten-Karte wird gefüllt.
3. Statuszeile: „Zertifikat ausgewählt: …“.
4. Sidebar-Schritt kann auf „Ziele“ springen.
5. Neustart braucht das Zertifikat **nicht zwingend** der Neustart hängt am Container, nicht an der Datei.
---
# Teil D Vor dem Neustart (Preflight)
## D1. Benutzer hakt Ziel(e) an
Im Grid: Checkbox „Selected“ setzen.
## D2. Button „ESB neu starten“
1. `GetSelectedTargets()` sammelt alle angehakten Zeilen.
2. `ValidateRestartOnly` prüft für jedes Ziel:
- `ContainerName` nicht leer
- `SonicConnectionName` nicht leer
3. Fehler → Dialog „Neustart blockiert“ mit Liste der Probleme.
4. OK → Bestätigungsdialog (Containername, Hinweis auf Management API).
5. Nein → Abbruch. Ja → Neustart startet.
---
# Teil E Neustart Gesamtablauf (C#-Seite)
Alles von hier läuft **ohne** Zertifikatskopieren.
```text
Form1.RunRestartOnlyAsync
→ DeploymentOrchestrator.RestartOnlyAsync
→ für jedes Ziel:
RestartExecutor.ExecuteAsync
→ SonicManagementClient.RestartContainerAsync
→ SonicMfApiExecutor.RestartAsync
→ java SonicMfContainerTool restart …
```
## E1. Orchestrator
Pro Ziel:
1. Status im Grid: „Neustart…“
2. `RestartExecutor.ExecuteAsync(target)`
3. Ergebnis + Detail in Logdatei unter `Logs\`
4. Status im Grid aktualisieren
5. Am Ende: Erfolgs-/Fehlerdialog mit Tool-Ausgabe
## E2. RestartExecutor
1. Liest `target.ContainerName` (z. B. `ct-ZADBService`).
2. Sucht in `appsettings` die `SonicConnection` mit `Name == SonicConnectionName` (`DE-Test`).
3. Fehlt die Verbindung → Fehler „Sonic-Verbindung nicht gefunden“.
4. Sonst: `new SonicManagementClient(connection)` und `RestartContainerAsync(containerName)`.
## E3. SonicManagementClient
Schlanke Fassade, nur MfApi:
1. Ruft `_mfApi.RestartAsync(containerName)` auf.
2. Bei Erfolg: wartet `PostRestartDelaySeconds` (z. B. 20 s), damit der Container Zeit zum Hochfahren hat.
3. Liefert Status-Text + komplette Java-Ausgabe zurück.
4. Bei Fehler: Fehlermeldung + Output für den Dialog.
---
# Teil F SonicMfApiExecutor: Java vorbereiten und starten
Das ist die Brücke von .NET zu Sonic.
## F1. Java finden
Reihenfolge grob:
1. `JavaPath` aus appsettings (bevorzugt)
2. `JavaHome`
3. Umgebungsvariablen / PATH / Registry / unter SonicHome
Bedingung: Runtime muss **Java 8+** können (Class-File major ≥ 52).
Zu alte Sonic-JREs (6/7) werden übersprungen.
## F2. Classpath bauen (Sonic-JARs)
1. `MfClientLibPath` (z. B. `C:\DEV\MQ10.0\lib`) oder Suche unter `SonicHome`.
2. Es müssen echte Client-JARs da sein, u. a.:
- `mgmt_client.jar`
- `mfcontext.jar`
- `sonic_Client.jar`
3. **Alle** `*.jar` im Lib-Ordner werden explizit in den Classpath geschrieben (kein fragiles `lib\*` mit kaputten Quotes).
4. Das Tool-Verzeichnis `Tools\` kommt **vorne** in den Classpath, damit die richtige `SonicMfContainerTool.class` geladen wird.
## F3. Java-Tool laden
1. Bevorzugt vorcompilierte `Tools\SonicMfContainerTool.class` (Java 8, major 52).
2. Alte/zu kleine Class-Dateien werden verworfen.
3. Temp-Cache alter Compilate wird gelöscht.
4. Falls nötig: aus `.java` mit `javac --release 8` neu bauen.
## F4. Prozess starten
Ungefähr:
```text
"C:\...\java.exe"
-cp "C:\...\Tools;C:\DEV\MQ10.0\lib\mgmt_client.jar;...;C:\DEV\MQ10.0\lib\mfcontext.jar;..."
SonicMfContainerTool
restart
--domain proalpha-test
--url tcp://dekun-painwbdet:13070
--user Administrator
--container ct-ZADBService
--timeout 120
```
Wichtig:
- Argumente über `ProcessStartInfo.ArgumentList` (keine doppelten Anführungszeichen).
- Passwort über Umgebung `ESB_SONIC_PASSWORD`, nicht in der sichtbaren Kommandozeile.
- stdout/stderr werden gelesen und an die UI zurückgegeben.
## F5. Erfolgsauswertung in C#
Neustart gilt nur als Erfolg, wenn die Ausgabe enthält:
```text
OK:RestartInvoked
```
Sonst: Fehlerdialog mit kompletter Tool-Ausgabe.
---
# Teil G Die Sonic Management Application API (Java-Tool)
Hier passiert der eigentliche „API-Call“ **nicht REST**, sondern **JMS/JMX Management Framework**.
Offizielle Produktwelt (Aurea CX Messenger / Sonic):
- Index: `doc-10.0.10/CXMessenger_2017_R3.htm`
- Eintrag: **Management Application API Reference** (`Docs2017/api/mgmt_api/`)
Das ist dieselbe API-Familie, die die SMC für Restart nutzt.
## G1. Warum „API“ hier kompliziert klingt
Die Sonic-Produkt-API enthält **sehr viele** Bereiche:
- Broker / Queues / Topics
- ESB-Services
- Metrics / Notifications
- Directory / Config
- Agent Lifecycle
**Für unseren Neustart brauchen wir nur einen schmalen Teil:**
1. Verbinden zum Domain Manager
2. Agent-ObjectName ansprechen
3. Lifecycle: stop/restart
Der Rest der JARs ist Produktumfang nicht „unsere App-API mit 100 Features“.
## G2. Schritt 1 Tool startet
Ausgabe:
```text
INFO:ToolVersion=2026-07-24c-mbean-stop
```
Wenn diese Zeile fehlt → oft noch eine **alte** `.class` im Einsatz.
## G3. Schritt 2 Argumente parsen
Pflicht:
- Befehl: `ping` | `list` | `restart`
- `--domain`
- `--url`
- `--user`
- bei `restart`: `--container`
- Passwort: `--password` oder `ESB_SONIC_PASSWORD`
## G4. Schritt 3 Connect (der eigentliche API-Login)
Java (vereinfacht, per Reflection):
```text
Hashtable env:
ConnectionURLs = tcp://dekun-painwbdet:13070
DefaultUser = Administrator
DefaultPassword = ***
JMSConnectorAddress address = new JMSConnectorAddress(env)
JMSConnectorClient connector = new JMSConnectorClient()
connector.connect(address, timeout)
```
Klassen kommen aus den Sonic-JARs:
- `com.sonicsw.mf.jmx.client.JMSConnectorAddress`
- `com.sonicsw.mf.jmx.client.JMSConnectorClient`
Ausgabe bei Erfolg:
```text
INFO:Connected url=tcp://dekun-painwbdet:13070 user=Administrator
```
Das entspricht dem SMC-Login gegen denselben Domain Manager.
## G5. Schritt 4 Ziel-Agent bestimmen
ObjectName:
```text
proalpha-test.ct-ZADBService:ID=AGENT
```
Muster:
```text
{DomainName}.{ContainerName}:ID=AGENT
```
Optional: per `queryNames` nach vorhandenen Agenten suchen; wenn das scheitert, Preferred-Name verwenden.
## G6. Schritt 5 Lifecycle (Neustart) drei Wege nacheinander
### Weg 1 MBean invoke (bevorzugt remote)
```text
connector.invoke(objectName, "stop", [], [])
// oder "restart", "shutdown"
```
Warum zuerst `stop`?
- Remote-Clients sind oft **„unbounded“**.
- `IAgentProxy.restart()` wirft dann häufig:
`Operation unsupported for unbounded client connector`
- SMC-Restart wirkt für den Operator oft wie: **Stop + automatischer Relaunch** durch Launch Daemon / Host Manager.
Erfolg:
```text
OK:RestartInvoked method=MBean.stop container=ct-ZADBService domain=proalpha-test
```
### Weg 2 Typisierter Proxy
```text
IAgentProxy agent = MFProxyFactory.createAgentProxy(connector, objectName)
agent.stop() / agent.restart() / agent.shutdown()
```
Schön dokumentiert, remote oft eingeschränkt (unbounded).
### Weg 3 DomainManager / Manager-MBeans
Suche nach Operationen wie:
- `restartContainer(containerName)`
- `stopContainer(containerName)`
Fallback, falls Agent-direkt nicht klappt.
## G7. Schritt 6 Disconnect
`connector.disconnect()` im `finally`.
## G8. Befehle des Tools im Überblick
| Befehl | Zweck |
|--------|--------|
| `ping` | Verbindungstest + Agenten zählen |
| `list` | Containernamen der Domain ausgeben |
| `restart` | Lifecycle auf einem Container |
---
# Teil H Komplette Kette als nummerierte Liste
So kannst du es jemandem erzählen:
### Zertifikat
1. App starten
2. Zertifikatsdatei wählen
3. Datei als X.509 lesen (PFX ggf. mit Passwort)
4. Subject, Issuer, Fingerprint, Gültigkeit anzeigen
5. Lokal „verifiziert“ = lesbar + im Gültigkeitszeitraum
### Neustart
6. Ziel im Grid anhaken (`ct-ZADBService` / Verbindung `DE-Test`)
7. „ESB neu starten“ → Preflight → Bestätigung
8. C# findet Sonic-Verbindung in appsettings
9. C# findet Java 8+ und baut Classpath aus `C:\DEV\MQ10.0\lib`
10. C# startet `SonicMfContainerTool restart …`
11. Java verbindet per Management API an `tcp://…:13070`
12. Java adressiert `proalpha-test.ct-ZADBService:ID=AGENT`
13. Java ruft Stop/Restart per MBean (Fallback Proxy/Manager)
14. Java schreibt `OK:RestartInvoked`
15. C# wartet `PostRestartDelaySeconds`
16. UI zeigt Erfolg/Fehler + Logausgabe
17. Optional in SMC prüfen: Uptime/Status des Containers
---
# Teil I Konfiguration im Detail
## I1. `appsettings.json` (Sonic-Block)
| Feld | Rolle |
|------|--------|
| `Name` | Alias, von Zielen referenziert (`DE-Test`) |
| `DomainName` | Sonic-Domain |
| `ConnectionUrl` | Domain-Manager-URL (wie SMC) |
| `Username` / `Password` | SMC-Login |
| `SonicHome` | Installationsroot |
| `MfClientLibPath` | Ordner mit Client-JARs |
| `JavaPath` / `JavaHome` | Java 8+ |
| `KnownContainers` | Fallback-Liste, z. B. `ct-ZADBService` |
| `TimeoutSeconds` | Timeout Java/API |
| `PostRestartDelaySeconds` | Wartezeit nach erfolgreichem Invoke |
Felder wie `WinRm*`, `Container*Path`, `ManagementHttpPort` können noch in der JSON stehen, werden vom schlanken MfApi-Client **nicht mehr genutzt**.
## I2. Container-Liste
Kein separates Sample-JSON. Container stehen in:
```json
"KnownContainers": [ "ct-ZADBService" ]
```
Live-Erweiterung über UI-Button „Container laden“.
---
# Teil J Dateien und Verantwortlichkeiten
| Datei | Verantwortung |
|-------|----------------|
| `Form1.cs` | UI, Zertifikat lesen, Neustart-Button, Dialoge |
| `DeploymentOrchestrator.cs` | Neustart über alle gewählten Ziele |
| `PreflightValidator.cs` | Pflichtfelder prüfen |
| `RestartExecutor.cs` | Ziel → SonicConnection |
| `SonicManagementClient.cs` | Fassade MfApi |
| `SonicMfApiExecutor.cs` | Java/Classpath/Prozess |
| `Tools/SonicMfContainerTool.java` | Connect + Lifecycle über Sonic-API |
| `appsettings.json` | Laufzeitkonfiguration inkl. KnownContainers |
| `Logs\` | Laufprotokolle |
---
# Teil K Erfolgs- und Fehlerbilder
## K1. Gesunde Ausgabe (Auszug)
```text
INFO:ToolVersion=2026-07-24c-mbean-stop
INFO:Connected url=tcp://dekun-painwbdet:13070 user=Administrator
INFO:PreferredObjectName=proalpha-test.ct-ZADBService:ID=AGENT
INFO:Trying MBean.invoke(stop) on …
OK:RestartInvoked method=MBean.stop container=ct-ZADBService domain=proalpha-test
```
## K2. Häufige Fehler
| Meldung | Bedeutung | Typische Lösung |
|---------|-----------|-----------------|
| `ClassNotFoundException: JMSConnectorAddress` | JARs fehlen / Classpath kaputt | `MfClientLibPath`, neuer Build |
| `UnsupportedClassVersionError` | Java-Version mismatch | Tool als Java 8 + Runtime Java 8+ |
| `Operation unsupported for unbounded…` | Proxy-Restart remote gesperrt | MBean-stop-Pfad / aktuelles Tool |
| Kein `ToolVersion=` | Alte Class-Datei | Neu bauen, richtigen bin-Ordner starten |
| Container `DE-Test` | Alias statt Kurzname | `ct-ZADBService` |
| `stopcontainer.bat` fehlt | SMC-only | normal MfApi nutzen |
---
# Teil L Wie man es jemandem erklärt (Kurzskript)
1. **UI:** Zertifikat laden → wir sehen Subject/Fingerprint/Gültigkeit. Das ist lokale Dateiprüfung.
2. **Neustart:** Wir starten denselben Management-Weg wie die SMC, nicht per Batch-Datei und nicht per FTP.
3. **Technik:** C# orchestriert; ein kleines Java-Tool + Sonic-Client-JARs sprechen mit dem Domain Manager.
4. **API:** Sonic Management Application API (JMS/JMX). Sehr große Produkt-API, wir nutzen nur Connect + Agent-Stop/Restart.
5. **Haken:** Remote heißt „unbounded“ deshalb oft `stop` per MBean statt `IAgentProxy.restart()`.
6. **Ergebnis:** Container `ct-ZADBService` in Domain `proalpha-test` wird neu gestartet; danach in der SMC Status/Uptime prüfen.
---
# Teil M Abgrenzung: Was ist „unsere API“ vs. Sonic-API?
| Ebene | Beschreibung |
|-------|--------------|
| **Unsere App** | WinForms + C#-Services. Kein öffentlicher REST-Endpoint. |
| **Unser Java-Tool** | Dünner Adapter (`ping`/`list`/`restart`) mit Fallbacks. |
| **Sonic Management Application API** | Produkt-API in den JARs; offiziell dokumentiert; SMC nutzt dieselbe Familie. |
| **Unnötig für den Use-Case** | MQ Messaging API, ESB API, Metrics, XApi, WinRM, Bat-Scripts, TLS-Probe solange nur „Datei prüfen + Neustart“ gefragt ist. |
---
*Ende der kompletten Erklärung. Bei Abweichungen gilt der Code im Projekt (Branch mit MfApi-Neustart).*