diff --git a/Dokumentation.md b/Dokumentation.md index f6ff9c1..5f0cb37 100644 --- a/Dokumentation.md +++ b/Dokumentation.md @@ -414,8 +414,8 @@ dem echten Collector-Konto und erzwingt einen vollständigen Endpoint- Katalogabgleich. Der Installer wartet begrenzt auf `LastTaskResult=0` und lässt anschließend die installierte Produkt-EXE Snapshot und Katalog mit den normalen Produktparsern validieren. Der Snapshot muss aus diesem Lauf stammen, die -erwartete Identität und alle neun eindeutigen Services ohne `UNKNOWN` -enthalten. Erst dann wird der normale Minutentask registriert und das Backup +erwartete Identität und alle neun eindeutigen Services enthalten. Erst dann +wird der normale Minutentask registriert und das Backup gelöscht. Bei Fehler oder Timeout wird die alte Version wiederhergestellt und ein frischer Lauf des alten Tasks abgewartet. @@ -435,6 +435,17 @@ Abnahmefehler und das Rollback-Ergebnis. Das Collector-Kennwort wird der Logging-Komponente nie übergeben. Ein frisch abgeschlossener Task mit Fehlercode wird sofort erkannt; der Fehler erscheint dezimal und hexadezimal. +Version 2.2.6 behandelt einen fachlichen UNKNOWN-Zustand der Endpoint-Prüfung +nicht mehr als Installationsdefekt. Sind Providerlauf, Snapshot, Identität, +neun Services und der erzwungen aktualisierte Katalog technisch valide, darf +`BizTalk Endpoint Reachability` als einziger Service `UNKNOWN` bleiben. Die +vollständige Local-Check-Zeile wird als Abnahmewarnung ausgegeben und bleibt +unverändert für Checkmk erhalten. Damit wird eine unvollständige +Endpoint-Auflösung nicht grüngefärbt und zugleich kein funktionsfähiges Update +zurückgerollt. UNKNOWN in Platform, SQL Access, Suspensions, Host Instances, +Receive Locations, Send Ports, Orchestrations oder Event Log bleibt +blockierend, weil dort die Kern-Datenerhebung nicht zuverlässig belegt ist. + Der installierte Task selbst läuft mit `RunLevel Limited`. Der Installer übergibt das Kennwort direkt an die Windows-Task-Scheduler-COM-Schnittstelle; es wird weder in einer Prozesskommandozeile noch in Config oder Log @@ -634,8 +645,9 @@ Automatisiert: - erzwungener Installations-Katalogabgleich wird unabhängig vom Katalogalter ausgeführt, - Runtime-Abnahme weist alten/manipulierten Snapshot, falsche Identität, - fehlenden Service, `UNKNOWN`, alten/ungültigen Katalog und fehlerhaften oder - nicht rechtzeitig beendeten Tasklauf zurück, + fehlenden Service, Kernservice-`UNKNOWN`, alten/ungültigen Katalog und + fehlerhaften oder nicht rechtzeitig beendeten Tasklauf zurück; ein isoliertes + Endpoint-Reachability-`UNKNOWN` wird mit vollständigem Detail akzeptiert, - Snapshot-Roundtrip und Ersatz, - SHA-256-Manipulation wird verworfen, - Stale-Snapshot wird verworfen, diff --git a/README.md b/README.md index ce69357..18e6206 100644 --- a/README.md +++ b/README.md @@ -267,7 +267,7 @@ als `UNKNOWN`. Ein gMSA kann über die Checkbox ohne Kennworteingabe installiert werden; die produktive Standardbeschreibung geht vom normalen Servicekonto aus. -Der Installer (ab Version 2.2.5): +Der Installer (ab Version 2.2.6): 1. prüft Paket und Staging zwingend auf neun Self-Test-Zeilen, bevor der bestehende Task angehalten wird. Der Servicevertrag der installierten @@ -285,8 +285,12 @@ Der Installer (ab Version 2.2.5): 6. wartet höchstens vier Minuten auf `LastTaskResult=0`, bricht bei einem bereits abgeschlossenen Fehlerlauf sofort mit Dezimal-/Hexcode ab und validiert danach mit der Produkt-EXE einen erst nach Installationsbeginn erzeugten Snapshot, - die Collector-Identität, alle neun eindeutigen Services ohne `UNKNOWN` - sowie den frischen, maschinen- und umgebungsgebundenen Endpoint-Katalog, + die Collector-Identität, alle neun eindeutigen Services sowie den frischen, + maschinen- und umgebungsgebundenen Endpoint-Katalog. `UNKNOWN` in einem + Kernservice bleibt ein Abnahmefehler. Ein ausschließlich bei + `BizTalk Endpoint Reachability` auftretendes `UNKNOWN` wird als sichtbare + Betriebswarnung übernommen, weil es eine unvollständige Prüfabdeckung und + keinen defekten Installationslauf beschreibt, 7. registriert erst nach dieser Abnahme den normalen Minutentask; andernfalls werden vorherige Version, Wrapper und Task samt frischem Altsnapshot wiederhergestellt, @@ -323,6 +327,12 @@ Die Analyse des in Version 2.2.4 beobachteten Abbruchs mit [docs/Installer-Self-Test-Analyse-2026-08-11.md](docs/Installer-Self-Test-Analyse-2026-08-11.md) dokumentiert. +Der nachfolgende ACC-Abbruch mit einem technisch validen Snapshot und +`UNKNOWN=[BizTalk Endpoint Reachability]` ist in +[docs/Installer-Runtime-Unknown-Analyse-2026-08-11.md](docs/Installer-Runtime-Unknown-Analyse-2026-08-11.md) +analysiert. Der Zustand wird nicht grüngefärbt: Setup 2.2.6 schließt ab und +gibt die vollständige UNKNOWN-Zeile als Warnung aus; Checkmk behält Status 3. + Snapshot und Consumer: ```cmd diff --git a/deployment/INSTALLATION.md b/deployment/INSTALLATION.md index bf13d42..70ce1e9 100644 --- a/deployment/INSTALLATION.md +++ b/deployment/INSTALLATION.md @@ -45,6 +45,17 @@ Version mit acht Services auf die Version mit dem zusätzlichen Service `BizTalk Endpoint Reachability` aktualisiert werden. Der frühere Abbruch `Exitcode=0, Zeilen=8` betraf die Altversion und war kein Fehler im neuen Paket. +Version 2.2.6 trennt technische Installationsabnahme und fachlichen +Endpoint-Zustand. Ein frischer, integritäts- und identitätsgeprüfter Snapshot +mit allen neun Services und ein frisch synchronisierter Endpoint-Katalog +belegen eine funktionsfähige Installation. Meldet ausschließlich +`BizTalk Endpoint Reachability` weiterhin `UNKNOWN`, wird die Installation +abgeschlossen und die vollständige Checkmk-Zeile als Warnung im Setup sowie +im Setup-Log ausgegeben. Der Status bleibt im Snapshot und in Checkmk +unverändert `UNKNOWN`, bis Auflösungslücken, Katalog-/Probeprobleme oder +fehlende manuelle Overrides betrieblich geklärt sind. `UNKNOWN` in Platform, +SQL oder einem anderen Kernservice bleibt ein blockierender Abnahmefehler. + Version 2.2.4 nimmt die umgeschaltete Installation zusätzlich vollständig ab: - einmaliger, triggerloser Providerlauf unter dem angegebenen Collector-Konto, @@ -54,7 +65,9 @@ Version 2.2.4 nimmt die umgeschaltete Installation zusätzlich vollständig ab: - Snapshot muss nach Beginn des Abnahmelaufs erzeugt, SHA-256-valid, für die aktuelle Maschine und vom erwarteten Collector-Konto geschrieben sein, - alle neun stabilen Services müssen eindeutig vorhanden sein; `WARN` und - `CRIT` sind reale Betriebszustände, `UNKNOWN` blockiert die Installation, + `CRIT` sind reale Betriebszustände. `UNKNOWN` in Kernservices blockiert die + Installation; ausschließlich `BizTalk Endpoint Reachability = UNKNOWN` + wird ab 2.2.6 als nicht blockierende Betriebswarnung übernommen, - bei aktivierter Endpoint-Prüfung muss auch der Katalog nach Beginn des Abnahmelaufs atomar synchronisiert worden sein. diff --git a/docs/ACC-Endpoint-Reachability-Analyse-2026-08-10.md b/docs/ACC-Endpoint-Reachability-Analyse-2026-08-10.md index 9d5ebb8..8b1aad4 100644 --- a/docs/ACC-Endpoint-Reachability-Analyse-2026-08-10.md +++ b/docs/ACC-Endpoint-Reachability-Analyse-2026-08-10.md @@ -139,7 +139,7 @@ Endpoint-/Namensfix bewusst nicht grüngefärbt. ## ACC-Abnahme nach Installation -1. Setup 2.2.5 als Update ausführen; Umgebung `ACC` kann bestehen bleiben. +1. Setup 2.2.6 als Update ausführen; Umgebung `ACC` kann bestehen bleiben. Beim Wechsel von der fehlerhaften 2.2.1-Ausgabe `BizTalk ACC ...` auf die stabilen Namen die Rename-/Discovery-Checkbox bewusst aktivieren. 2. In der installierten Config bestätigen: diff --git a/docs/BizTalk_Checkmk_Pulse_Architekturueberblick.docx b/docs/BizTalk_Checkmk_Pulse_Architekturueberblick.docx index f3849de..a027098 100644 Binary files a/docs/BizTalk_Checkmk_Pulse_Architekturueberblick.docx and b/docs/BizTalk_Checkmk_Pulse_Architekturueberblick.docx differ diff --git a/docs/EndpointCatalog.md b/docs/EndpointCatalog.md index 1cf2109..2ebcdc6 100644 --- a/docs/EndpointCatalog.md +++ b/docs/EndpointCatalog.md @@ -21,6 +21,13 @@ Installer akzeptiert den Release erst, wenn der neue Synchronisationszeitpunkt nach dem Start dieses Laufs liegt. Gültige manuelle Overrides werden dabei erhalten; der Katalog wird nicht blind gelöscht. +Ab Setup 2.2.6 blockiert ein technisch gültiger Abnahmelauf nicht mehr allein +deshalb, weil `BizTalk Endpoint Reachability` fachlich `UNKNOWN` meldet. Die +Installation wird mit einer sichtbaren Warnung abgeschlossen; Status, Metriken +und Detailtext bleiben im Snapshot erhalten. Ein fehlender, ungültiger oder +nicht in diesem Abnahmelauf synchronisierter Katalog bleibt dagegen ein harter +Installationsfehler. + Unabhängig vom Wochenabgleich wird bei jedem Minutenlauf gegen den aktuellen BizTalk-Runtimezustand gefiltert: diff --git a/docs/Installer-Runtime-Unknown-Analyse-2026-08-11.md b/docs/Installer-Runtime-Unknown-Analyse-2026-08-11.md new file mode 100644 index 0000000..d3e559a --- /dev/null +++ b/docs/Installer-Runtime-Unknown-Analyse-2026-08-11.md @@ -0,0 +1,67 @@ +# Analyse: Runtime-Abnahme mit Endpoint-Reachability `UNKNOWN` + +## Beobachtung + +Setup 2.2.5 schaltete die neue Version um, startete den Provider erfolgreich +und validierte danach die Runtime-Artefakte. Die Abnahme endete trotzdem mit: + +```text +Runtime validation failed: Snapshot enthaelt unzuverlaessige UNKNOWN-Zustaende +in stabilen Services. UNKNOWN=[BizTalk Endpoint Reachability]. +``` + +Anschließend stellte der Installer die vorherige Version samt Task und frischem +Snapshot erfolgreich wieder her. + +## Einordnung + +`LastTaskResult=0` belegt, dass der Providerlauf technisch abgeschlossen und +ein Snapshot geschrieben wurde. Zusätzlich waren Snapshot-Zeitpunkt, +SHA-256, Maschine, Collector-Identität, alle neun Servicenamen und der im +Abnahmelauf synchronisierte Endpoint-Katalog valide. Das verbleibende +`UNKNOWN` war daher kein Installations- oder Transaktionsfehler, sondern der +fachliche Zustand der Endpoint-Prüfung. + +Der Endpoint-Service verwendet `UNKNOWN`, wenn die Prüfabdeckung nicht +vollständig verlässlich ist, zum Beispiel bei einer nicht sicher auf +Host/Port reduzierbaren aktiven Adresse, einem Katalog-/Probehinweis oder +fehlendem manuellem Override. Diesen Zustand auf `OK` zu ändern würde die +Monitoringlücke verbergen. + +## Korrektur in Version 2.2.6 + +- Snapshot, Erzeugungszeit, Integrität, Maschine und Collector-Identität + werden unverändert strikt geprüft. +- Alle neun stabilen Services müssen eindeutig vorhanden sein. +- Bei aktivierter Endpoint-Prüfung muss der Katalog weiterhin im gestarteten + Abnahmelauf erfolgreich synchronisiert worden sein. +- `UNKNOWN` in einem Kernservice bleibt ein Abnahmefehler. +- Ausschließlich `BizTalk Endpoint Reachability = UNKNOWN` wird als + nicht blockierende Betriebswarnung akzeptiert. +- Die vollständige UNKNOWN-Zeile erscheint in Setup-Ausgabe und Setup-Log und + bleibt unverändert im Snapshot für Checkmk erhalten. + +Damit wird die Installation abgeschlossen, ohne einen ungeklärten +Monitoringzustand grünzufärben. Der normale Minutentask läuft weiter und die +Endpoint-Ursache kann anhand von `unresolved_endpoints`, +`catalog_or_probe_error`, `biztalk_endpoints_unresolved`, Katalog und +Provider-Log gezielt bearbeitet werden. + +## Weiteres Vorgehen in ACC + +1. Setup 2.2.6 als Update ausführen und die ausgegebene + `RUNTIME_VALIDATION_WARNING` sichern. +2. Im Snapshot die vollständige Zeile `BizTalk Endpoint Reachability` prüfen. +3. Bei `unresolved_endpoints` Adapter, Artefakt und Grund auswerten und nur + bei einem tatsächlich externen Ziel einen geheimnisfreien manuellen + Override in `endpoints.xml` ergänzen. +4. Bei `catalog_or_probe_error` zuerst Provider-Log und Katalog-XML prüfen. +5. Nach der Bereinigung zwei Minutenläufe und den Checkmk-Agent-Dump prüfen. + +## Regressionstests + +- Ein isoliertes Endpoint-Reachability-`UNKNOWN` wird als Warnung akzeptiert + und sein vollständiger Detailtext bleibt erhalten. +- `BizTalk Platform = UNKNOWN` bleibt blockierend. +- Fehlender Service, alter Snapshot, falsche Identität und alter Katalog + bleiben blockierend. diff --git a/docs/Integration.md b/docs/Integration.md index f8c97fb..5f80433 100644 --- a/docs/Integration.md +++ b/docs/Integration.md @@ -56,7 +56,11 @@ Verbindlicher Agent-Dump: Das Setup ab 2.2.4 schließt erst erfolgreich ab, nachdem der erste Providerlauf unter dem echten Collector-Konto einen frischen Snapshot und – bei aktivierter Endpoint-Prüfung – einen frisch synchronisierten Katalog erzeugt hat. Die neun -stabilen Services müssen vollständig und ohne `UNKNOWN` vorliegen. Diese lokale +stabilen Services müssen vollständig vorliegen. `UNKNOWN` in einem Kernservice +bleibt blockierend. Ab Version 2.2.6 wird ein isoliertes +`BizTalk Endpoint Reachability = UNKNOWN` als fachliche Betriebswarnung +akzeptiert, sofern Snapshot, Identität und frisch synchronisierter Katalog +valide sind. Die UNKNOWN-Zeile bleibt in Checkmk sichtbar. Diese lokale Runtime-Abnahme ersetzt nicht die zentrale Checkmk Service Discovery. `EnvironmentName` kennzeichnet Snapshot und Katalog, ändert die neun diff --git a/scripts/generate-architecture-overview.py b/scripts/generate-architecture-overview.py index 3adc066..5c1925b 100644 --- a/scripts/generate-architecture-overview.py +++ b/scripts/generate-architecture-overview.py @@ -306,7 +306,7 @@ def configure_document(document): p = footer.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_after = Pt(0) - format_run(p.add_run("Version 2.2.5 | Stand 11.08.2026 | Seite "), size=7.5, color=MUTED) + format_run(p.add_run("Version 2.2.6 | Stand 11.08.2026 | Seite "), size=7.5, color=MUTED) add_page_field(p) @@ -320,7 +320,7 @@ def build_document(): core.title = "BizTalk Checkmk Pulse – Architektur- und Lösungsüberblick" core.subject = "Gesamtarchitektur, Funktionsumfang und Datenaustausch" core.author = "BEW" - core.comments = "Externe Lösungsübersicht zum implementierten Stand 2.2.5" + core.comments = "Externe Lösungsübersicht zum implementierten Stand 2.2.6" # Cover banner = document.add_table(rows=1, cols=1) @@ -377,7 +377,7 @@ def build_document(): document, ("Dokumentmerkmal", "Angabe"), ( - ("Lösungsstand", "BizTalk Checkmk Pulse 2.2.5"), + ("Lösungsstand", "BizTalk Checkmk Pulse 2.2.6"), ("Zielplattform", "Microsoft BizTalk Server 2020 · Windows Server 2019 · Checkmk 2.4"), ("Dokumentstand", "11. August 2026"), ("Dokumentzweck", "Architektur- und Leistungsüberblick für technische Stakeholder"), @@ -545,7 +545,7 @@ def build_document(): add_bullet(document, "Endpoint-Prüfung standardmäßig mit maximal 100 Zielen, 16 parallelen Probes und 3 Sekunden Timeout je Ziel.") add_bullet(document, "Der Installer validiert neue Versionen auf exakt neun Services, akzeptiert vollständige Legacy-Verträge mit weniger Services und stoppt entfernte oder umbenannte Servicenamen vor jeder Umschaltung.") add_bullet(document, "Ein laufbezogenes Setup-Log protokolliert Phase, Binary-Version, Self-Test-Ausgabe, Taskcodes, Exception-Kette und Rollback ohne Kennwort.") - add_bullet(document, "Nach der Umschaltung erzwingt das Setup einen frischen Katalogabgleich und akzeptiert die Installation erst nach einem erfolgreichen, identitäts- und integritätsgeprüften Providerlauf ohne UNKNOWN in den neun stabilen Services.") + add_bullet(document, "Nach der Umschaltung erzwingt das Setup einen frischen Katalogabgleich. Kernservice-UNKNOWN bleibt blockierend; ein isoliertes Endpoint-Reachability-UNKNOWN bleibt als sichtbare Betriebswarnung erhalten und löst keinen Rollback aus.") add_heading(document, "Sicherheitsmodell", level=2) add_table( @@ -574,7 +574,7 @@ def build_document(): add_callout(document, "Kernaussage: ", "Ein privilegierter Read-only-Collector sammelt, ein unprivilegierter Consumer validiert und übergibt – Checkmk erhält neun stabile Services statt direkten Zugriff auf BizTalk oder SQL.", fill=LIGHT_GREEN, border=GREEN) add_rich_paragraph( document, - (("Dokumentbasis: Implementierung und Projektdokumentation von BizTalk Checkmk Pulse 2.2.5 sowie Checkmk User Guide „Local checks“, abgerufen am 10. August 2026.", {"size": 7.8, "color": MUTED}),), + (("Dokumentbasis: Implementierung und Projektdokumentation von BizTalk Checkmk Pulse 2.2.6 sowie Checkmk User Guide „Local checks“, abgerufen am 10. August 2026.", {"size": 7.8, "color": MUTED}),), before=8, after=0, ) diff --git a/src/BizTalkCheckmkPulse.Setup/Properties/AssemblyInfo.cs b/src/BizTalkCheckmkPulse.Setup/Properties/AssemblyInfo.cs index be9fa57..d9b8ed6 100644 --- a/src/BizTalkCheckmkPulse.Setup/Properties/AssemblyInfo.cs +++ b/src/BizTalkCheckmkPulse.Setup/Properties/AssemblyInfo.cs @@ -6,5 +6,5 @@ using System.Runtime.CompilerServices; [assembly: AssemblyDescription("PowerShell-free installer and updater for BizTalk Checkmk Pulse")] [assembly: AssemblyCompany("BEW")] [assembly: AssemblyProduct("BizTalk Checkmk Pulse")] -[assembly: AssemblyVersion("2.2.5.0")] -[assembly: AssemblyFileVersion("2.2.5.0")] +[assembly: AssemblyVersion("2.2.6.0")] +[assembly: AssemblyFileVersion("2.2.6.0")] diff --git a/src/BizTalkCheckmkPulse/Program.cs b/src/BizTalkCheckmkPulse/Program.cs index b1877d4..3a71b8a 100644 --- a/src/BizTalkCheckmkPulse/Program.cs +++ b/src/BizTalkCheckmkPulse/Program.cs @@ -164,7 +164,14 @@ namespace BizTalkCheckmkPulse + " catalogUtc=" + (validation.CatalogSynchronizedUtc.HasValue ? validation.CatalogSynchronizedUtc.Value.ToString("o") : "disabled") - + " stableServices=" + validation.StableServiceCount); + + " stableServices=" + validation.StableServiceCount + + " acceptedUnknown=" + validation.AcceptedUnknownLines.Count); + foreach (var line in validation.AcceptedUnknownLines) + { + Console.WriteLine( + "RUNTIME_VALIDATION_WARNING: Installation technisch valide; Monitoringzustand bleibt sichtbar: " + + line); + } return 0; } diff --git a/src/BizTalkCheckmkPulse/Properties/AssemblyInfo.cs b/src/BizTalkCheckmkPulse/Properties/AssemblyInfo.cs index 4971c3e..5f17c6f 100644 --- a/src/BizTalkCheckmkPulse/Properties/AssemblyInfo.cs +++ b/src/BizTalkCheckmkPulse/Properties/AssemblyInfo.cs @@ -6,5 +6,5 @@ using System.Reflection; [assembly: AssemblyDescription("Privileged BizTalk data provider and validated Checkmk snapshot consumer")] [assembly: AssemblyCompany("BEW")] [assembly: AssemblyProduct("BizTalk Checkmk Pulse")] -[assembly: AssemblyVersion("2.2.5.0")] -[assembly: AssemblyFileVersion("2.2.5.0")] +[assembly: AssemblyVersion("2.2.6.0")] +[assembly: AssemblyFileVersion("2.2.6.0")] diff --git a/src/BizTalkCheckmkPulse/RuntimeValidator.cs b/src/BizTalkCheckmkPulse/RuntimeValidator.cs index ab666ed..98e8094 100644 --- a/src/BizTalkCheckmkPulse/RuntimeValidator.cs +++ b/src/BizTalkCheckmkPulse/RuntimeValidator.cs @@ -43,12 +43,34 @@ namespace BizTalkCheckmkPulse } string serviceError; + string[] unknownServiceLines; var expectedServices = formatter.FormatSelfTest().Select(ExtractServiceName).ToArray(); - if (!ContainsExactStableContract(snapshot.Lines, expectedServices, out serviceError)) + if (!ContainsExactStableContract( + snapshot.Lines, + expectedServices, + out unknownServiceLines, + out serviceError)) { return RuntimeValidationResult.Failed(serviceError); } + var acceptedEndpointUnknownName = options.ServiceName("Endpoint Reachability"); + var blockingUnknown = unknownServiceLines + .Where(x => !options.ProbeEndpointConnectivity + || !string.Equals( + ExtractServiceName(x), + acceptedEndpointUnknownName, + StringComparison.Ordinal)) + .Select(ExtractServiceName) + .OrderBy(x => x, StringComparer.Ordinal) + .ToArray(); + if (blockingUnknown.Length != 0) + { + return RuntimeValidationResult.Failed( + "Snapshot enthaelt blockierende UNKNOWN-Zustaende in Kernservices. UNKNOWN=[" + + string.Join(", ", blockingUnknown) + "]."); + } + DateTime? catalogUtc = null; if (options.ProbeEndpointConnectivity) { @@ -85,14 +107,17 @@ namespace BizTalkCheckmkPulse return RuntimeValidationResult.Success( snapshot.GeneratedUtc, catalogUtc, - expectedServices.Length); + expectedServices.Length, + unknownServiceLines); } internal static bool ContainsExactStableContract( IEnumerable lines, IEnumerable expectedServices, + out string[] unknownServiceLines, out string error) { + unknownServiceLines = new string[0]; string[] actual; try { @@ -123,18 +148,11 @@ namespace BizTalkCheckmkPulse return false; } - var unknown = (lines ?? Enumerable.Empty()) + unknownServiceLines = (lines ?? Enumerable.Empty()) .Where(x => x != null && x.StartsWith("3 ", StringComparison.Ordinal)) - .Select(ExtractServiceName) - .Where(x => expected.Contains(x, StringComparer.Ordinal)) - .OrderBy(x => x, StringComparer.Ordinal) + .Where(x => expected.Contains(ExtractServiceName(x), StringComparer.Ordinal)) + .OrderBy(ExtractServiceName, StringComparer.Ordinal) .ToArray(); - if (unknown.Length != 0) - { - error = "Snapshot enthaelt unzuverlaessige UNKNOWN-Zustaende in stabilen Services. UNKNOWN=[" - + string.Join(", ", unknown) + "]."; - return false; - } error = string.Empty; return true; @@ -159,21 +177,31 @@ namespace BizTalkCheckmkPulse public DateTime GeneratedUtc { get; private set; } public DateTime? CatalogSynchronizedUtc { get; private set; } public int StableServiceCount { get; private set; } + public IReadOnlyList AcceptedUnknownLines { get; private set; } - public static RuntimeValidationResult Success(DateTime generatedUtc, DateTime? catalogUtc, int serviceCount) + public static RuntimeValidationResult Success( + DateTime generatedUtc, + DateTime? catalogUtc, + int serviceCount, + IEnumerable acceptedUnknownLines) { return new RuntimeValidationResult { IsSuccess = true, GeneratedUtc = generatedUtc, CatalogSynchronizedUtc = catalogUtc, - StableServiceCount = serviceCount + StableServiceCount = serviceCount, + AcceptedUnknownLines = (acceptedUnknownLines ?? Enumerable.Empty()).ToArray() }; } public static RuntimeValidationResult Failed(string error) { - return new RuntimeValidationResult { Error = error }; + return new RuntimeValidationResult + { + Error = error, + AcceptedUnknownLines = new string[0] + }; } } } diff --git a/tests/BizTalkCheckmkPulse.Tests/Program.cs b/tests/BizTalkCheckmkPulse.Tests/Program.cs index 55575ad..092b4ce 100644 --- a/tests/BizTalkCheckmkPulse.Tests/Program.cs +++ b/tests/BizTalkCheckmkPulse.Tests/Program.cs @@ -52,6 +52,8 @@ namespace BizTalkCheckmkPulse.Tests Run("RuntimeValidationRejectsStaleCatalog", RuntimeValidationRejectsStaleCatalog); Run("RuntimeValidationRejectsChangedServiceContract", RuntimeValidationRejectsChangedServiceContract); Run("RuntimeValidationRejectsUnknownStableService", RuntimeValidationRejectsUnknownStableService); + Run("RuntimeValidationAllowsEndpointUnknownAsWarning", RuntimeValidationAllowsEndpointUnknownAsWarning); + Run("RuntimeValidationRejectsEndpointUnknownWhenProbeDisabled", RuntimeValidationRejectsEndpointUnknownWhenProbeDisabled); Run("RuntimeValidationAllowsDisabledEndpointProbeWithoutCatalog", RuntimeValidationAllowsDisabledEndpointProbeWithoutCatalog); Run("ForceEndpointRefreshRequiresProviderMode", ForceEndpointRefreshRequiresProviderMode); Run("RuntimeValidationArgumentsAreParsedStrictly", RuntimeValidationArgumentsAreParsedStrictly); @@ -1028,8 +1030,55 @@ namespace BizTalkCheckmkPulse.Tests "BEW\\t231bizmon", true, lines); - Assert(!result.IsSuccess, "UNKNOWN stable service must fail runtime acceptance"); - Assert(result.Error.Contains("UNKNOWN=[BizTalk Platform]"), "UNKNOWN stable service reason missing"); + Assert(!result.IsSuccess, "UNKNOWN core service must fail runtime acceptance"); + Assert(result.Error.Contains("UNKNOWN=[BizTalk Platform]"), "UNKNOWN core service reason missing"); + } + + private static void RuntimeValidationAllowsEndpointUnknownAsWarning() + { + var boundary = DateTime.UtcNow.AddMinutes(-1); + var lines = new CheckmkLocalFormatter(new MonitoringOptions()).FormatSelfTest().ToArray(); + var endpointIndex = Array.FindIndex( + lines, + x => x.Contains("\"BizTalk Endpoint Reachability\"")); + Assert(endpointIndex >= 0, "endpoint service missing from self-test contract"); + lines[endpointIndex] = "3 \"BizTalk Endpoint Reachability\" " + + "biztalk_endpoints_unresolved=1;;1;0 Endpoint reachability incomplete; unresolved=1."; + + var result = ValidateRuntimeArtifacts( + boundary, + boundary.AddSeconds(10), + boundary.AddSeconds(5), + "BEW\\t231bizmon", + "BEW\\t231bizmon", + true, + lines); + + Assert(result.IsSuccess, "endpoint UNKNOWN must be accepted as operational warning: " + result.Error); + AssertEqual(1, result.AcceptedUnknownLines.Count, "accepted endpoint UNKNOWN count"); + Assert(result.AcceptedUnknownLines[0].Contains("unresolved=1"), "endpoint UNKNOWN detail must be retained"); + } + + private static void RuntimeValidationRejectsEndpointUnknownWhenProbeDisabled() + { + var boundary = DateTime.UtcNow.AddMinutes(-1); + var lines = new CheckmkLocalFormatter(new MonitoringOptions()).FormatSelfTest().ToArray(); + var endpointIndex = Array.FindIndex( + lines, + x => x.Contains("\"BizTalk Endpoint Reachability\"")); + lines[endpointIndex] = "3 \"BizTalk Endpoint Reachability\" - Unexpected UNKNOWN while probe is disabled."; + + var result = ValidateRuntimeArtifacts( + boundary, + boundary.AddSeconds(10), + null, + "BEW\\t231bizmon", + "BEW\\t231bizmon", + false, + lines); + + Assert(!result.IsSuccess, "endpoint UNKNOWN must be rejected when endpoint probing is disabled"); + Assert(result.Error.Contains("UNKNOWN=[BizTalk Endpoint Reachability]"), "disabled-probe UNKNOWN reason missing"); } private static void ForceEndpointRefreshRequiresProviderMode()