Harden BizTalk WMI monitoring
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 17.0.31903.59
|
VisualStudioVersion = 16.0.31624.102
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse", "src\BizTalkCheckmkPulse\BizTalkCheckmkPulse.csproj", "{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse", "src\BizTalkCheckmkPulse\BizTalkCheckmkPulse.csproj", "{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse.Tests", "tests\BizTalkCheckmkPulse.Tests\BizTalkCheckmkPulse.Tests.csproj", "{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -14,9 +16,12 @@ Global
|
|||||||
{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
||||||
|
|||||||
+16
-9
@@ -100,7 +100,7 @@ BizTalkCheckmkPulse.exe
|
|||||||
Checkmk Local Check Zeilen nach STDOUT
|
Checkmk Local Check Zeilen nach STDOUT
|
||||||
```
|
```
|
||||||
|
|
||||||
Der `.cmd`-Wrapper liefert auch dann eine gueltige `UNKNOWN`-Zeile mit Massnahme, wenn die EXE fehlt oder bereits der Prozessstart mit einem Exitcode fehlschlaegt. Die EXE selbst faengt Laufzeitfehler ab und schreibt fuer alle stabilen Services `UNKNOWN`, damit unvollstaendige Deployments oder WMI-Probleme in Checkmk sichtbar bleiben.
|
Der `.cmd`-Wrapper liefert auch dann fuer alle sechs stabilen Services gueltige `UNKNOWN`-Zeilen mit Massnahme, wenn die EXE fehlt oder bereits der Prozessstart mit einem Exitcode fehlschlaegt. Die EXE selbst faengt Laufzeitfehler ab und schreibt ebenfalls fuer alle stabilen Services `UNKNOWN`, damit unvollstaendige Deployments oder WMI-Probleme in Checkmk sichtbar bleiben.
|
||||||
|
|
||||||
## Datenquellen
|
## Datenquellen
|
||||||
|
|
||||||
@@ -116,14 +116,15 @@ Genutzte Klassen:
|
|||||||
|
|
||||||
| Klasse | Zweck |
|
| Klasse | Zweck |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `MSBTS_GroupSetting` | BizTalk-Gruppe und Management-DB-Hinweise. |
|
| `MSBTS_GroupSetting` | BizTalk-Gruppe, Management-DB und Master-MessageBox (`SubscriptionDB*`). |
|
||||||
| `MSBTS_MessageBoxSetting` | MessageBox-DB-Hinweise. |
|
| `MSBTS_HostInstance` | Host-Instance-Zustand; Ergebnis wird clientseitig auf den ueberwachten Server begrenzt. |
|
||||||
| `MSBTS_HostInstance` | Host-Instance-Zustand. |
|
|
||||||
| `MSBTS_ServiceInstance` | Suspended service instances. |
|
| `MSBTS_ServiceInstance` | Suspended service instances. |
|
||||||
| `MSBTS_ReceiveLocation` | Receive-Location-Zustand. |
|
| `MSBTS_ReceiveLocation` | Receive-Location-Zustand. |
|
||||||
| `MSBTS_SendPort` | Send-Port-Zustand. |
|
| `MSBTS_SendPort` | Send-Port-Zustand. |
|
||||||
| `MSBTS_Orchestration` | Orchestration-Zustand. |
|
| `MSBTS_Orchestration` | Orchestration-Zustand. |
|
||||||
| `MSBTS_ReceivePort` | Application-Mapping fuer Details. |
|
| `MSBTS_ReceivePort` | Optionales Best-Effort-Application-Mapping, nur wenn per-Application-Services aktiviert sind. |
|
||||||
|
|
||||||
|
Die Plattformabfrage verwendet absichtlich keine vermeintliche Klasse `MSBTS_MessageBoxSetting`: Sie ist nicht Bestandteil des dokumentierten BizTalk-WMI-Schemas. Auch die vorhandene Klasse `MSBTS_MsgBoxSetting` ist fuer die Zielermittlung nicht erforderlich. `MSBTS_GroupSetting` liefert mit `SubscriptionDBServerName` und `SubscriptionDBName` bereits das Ziel der Master-MessageBox. Dadurch entfallen eine Providerabfrage und eine unnoetige Berechtigungs-/Schemaschnittstelle.
|
||||||
|
|
||||||
### Windows Application Event Log
|
### Windows Application Event Log
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ Die Liste ist ueber `EventLogSources` konfigurierbar.
|
|||||||
|
|
||||||
### SQL-Zugriffsprobe
|
### SQL-Zugriffsprobe
|
||||||
|
|
||||||
Nach erfolgreicher oder teilweise erfolgreicher Plattformabfrage uebernimmt der SQL-Probe die per WMI ermittelten Management- und MessageBox-Ziele. Fuer jedes eindeutige Ziel wird mit `System.Data.SqlClient` eine Verbindung mit integrierter Windows-Authentifizierung geoeffnet und `SELECT 1` ausgefuehrt. Die Verbindung wird unmittelbar danach geschlossen; es werden keine BizTalk-Tabellen gelesen oder veraendert.
|
Nach erfolgreicher oder teilweise erfolgreicher Plattformabfrage uebernimmt der SQL-Probe die per `MSBTS_GroupSetting` ermittelten Management- und Master-MessageBox-Ziele. Fuer jedes eindeutige Ziel wird mit `System.Data.SqlClient` eine Verbindung mit integrierter Windows-Authentifizierung geoeffnet und `SELECT 1` ausgefuehrt. Die Verbindung wird unmittelbar danach geschlossen; es werden keine BizTalk-Tabellen gelesen oder veraendert.
|
||||||
|
|
||||||
Der Test laeuft unter derselben Identitaet wie der Checkmk Local Check. Damit wird sichtbar, ob `LocalSystem` beziehungsweise das Maschinenkonto des BizTalk-Servers das SQL-Ziel tatsaechlich erreichen und die Datenbank oeffnen kann. Die Probe ist mit `ProbeSqlConnectivity=false` deaktivierbar und verwendet `SqlConnectionTimeoutSeconds` mit dem Default 5 Sekunden je Ziel als Timeout.
|
Der Test laeuft unter derselben Identitaet wie der Checkmk Local Check. Damit wird sichtbar, ob `LocalSystem` beziehungsweise das Maschinenkonto des BizTalk-Servers das SQL-Ziel tatsaechlich erreichen und die Datenbank oeffnen kann. Die Probe ist mit `ProbeSqlConnectivity=false` deaktivierbar und verwendet `SqlConnectionTimeoutSeconds` mit dem Default 5 Sekunden je Ziel als Timeout.
|
||||||
|
|
||||||
@@ -200,13 +201,14 @@ WMI-Verbindungsaufbau und jede erforderliche WMI-Klasse werden separat bewertet.
|
|||||||
| `Wmi/Permission` | Namespace oder BizTalk-WMI-Klasse verweigert den Zugriff. | Namespace-ACL bei Verbindungsfehlern beziehungsweise BizTalk-Operator-Gruppe bei Klassenfehlern pruefen. |
|
| `Wmi/Permission` | Namespace oder BizTalk-WMI-Klasse verweigert den Zugriff. | Namespace-ACL bei Verbindungsfehlern beziehungsweise BizTalk-Operator-Gruppe bei Klassenfehlern pruefen. |
|
||||||
| `Wmi/Connectivity` | WMI-/RPC-Ziel nicht erreichbar. | WMI-Dienst, Provider und bei Remote-WMI zusaetzlich DNS/RPC/Firewall pruefen. |
|
| `Wmi/Connectivity` | WMI-/RPC-Ziel nicht erreichbar. | WMI-Dienst, Provider und bei Remote-WMI zusaetzlich DNS/RPC/Firewall pruefen. |
|
||||||
| `Wmi/Timeout` | WMI-Abfrage ueberschreitet `QueryTimeoutSeconds`. | WMI-, BizTalk- und SQL-Auslastung untersuchen, bevor der Timeout erhoeht wird. |
|
| `Wmi/Timeout` | WMI-Abfrage ueberschreitet `QueryTimeoutSeconds`. | WMI-, BizTalk- und SQL-Auslastung untersuchen, bevor der Timeout erhoeht wird. |
|
||||||
| `Wmi/Configuration` | Namespace oder Klasse fehlt. | BizTalk-WMI-Provider und BizTalk-Installation pruefen beziehungsweise reparieren. |
|
| `Wmi/Configuration` | BizTalk-WMI-Namespace fehlt oder Plattformdaten sind unvollstaendig. | Provider, Namespace und BizTalk-Konfiguration pruefen. |
|
||||||
|
| `Wmi/Schema` | `InvalidClass` oder `InvalidQuery`; Klasse beziehungsweise WQL passt nicht zum installierten Provider. | Klasse/Properties gegen das BizTalk-WMI-Schema pruefen; keine Rechteerhoehung vornehmen. |
|
||||||
| `Sql/Permission` | Login oder Datenbankzugriff wird abgelehnt. | Maschinenkonto der BizTalk-Operator-Gruppe zuordnen, Kerberos erneuern, keine direkten DB-Rollen vergeben. |
|
| `Sql/Permission` | Login oder Datenbankzugriff wird abgelehnt. | Maschinenkonto der BizTalk-Operator-Gruppe zuordnen, Kerberos erneuern, keine direkten DB-Rollen vergeben. |
|
||||||
| `Sql/Connectivity` | SQL-Server oder Instanz nicht erreichbar. | Servername, DNS, SQL-Dienst, TCP-Protokoll, Port und Firewall pruefen. |
|
| `Sql/Connectivity` | SQL-Server oder Instanz nicht erreichbar. | Servername, DNS, SQL-Dienst, TCP-Protokoll, Port und Firewall pruefen. |
|
||||||
| `Sql/Timeout` | SQL-Verbindung oder Testabfrage laeuft in den Timeout. | Netzwerk und SQL-Auslastung pruefen; Timeout nur begruendet anheben. |
|
| `Sql/Timeout` | SQL-Verbindung oder Testabfrage laeuft in den Timeout. | Netzwerk und SQL-Auslastung pruefen; Timeout nur begruendet anheben. |
|
||||||
| `Sql/Configuration` | WMI-Ziele unvollstaendig oder TLS-, Zertifikats-, SPN-/SSPI-Konfiguration fehlerhaft. | Plattformabfragen beziehungsweise Zertifikatskette, Verschluesselung, SPN und Kerberos gezielt pruefen. |
|
| `Sql/Configuration` | WMI-Ziele unvollstaendig oder TLS-, Zertifikats-, SPN-/SSPI-Konfiguration fehlerhaft. | Plattformabfragen beziehungsweise Zertifikatskette, Verschluesselung, SPN und Kerberos gezielt pruefen. |
|
||||||
|
|
||||||
Jede Diagnose enthaelt Bereich/Kategorie, betroffene Komponente, eine kurze Ursache, `Massnahme:` und `Technik:` mit Exception-Typ, HRESULT oder SQL-Fehlernummer. Erforderliche Datenquellen besitzen eigene Verfuegbarkeitsflags. Schlaegt beispielsweise `MSBTS_ServiceInstance` fehl, wird `BizTalk Suspended Instances` zwingend `UNKNOWN`; eine leere Ergebnisliste darf nicht als 'keine Suspensions' fehlinterpretiert werden.
|
Jede Diagnose enthaelt Bereich/Kategorie, betroffene Komponente, eine kurze Ursache, `Massnahme:` und `Technik:` mit Exception-Typ, HRESULT oder SQL-Fehlernummer. Bei WMI-Abfragefehlern werden zusaetzlich WQL und Laufzeit bis zum Fehler ausgegeben. Erforderliche Datenquellen besitzen eigene Verfuegbarkeitsflags. Schlaegt beispielsweise `MSBTS_ServiceInstance` fehl, wird `BizTalk Suspended Instances` zwingend `UNKNOWN`; eine leere Ergebnisliste darf nicht als 'keine Suspensions' fehlinterpretiert werden.
|
||||||
|
|
||||||
Die Operator-Mitgliedschaft des Computerkontos steht allen auf diesem Server als `LocalSystem` laufenden Diensten fuer Netzwerkzugriffe zur Verfuegung. Falls diese Sicherheitsauswirkung nicht akzeptabel ist, kann ein separater Collector unter einem dedizierten gMSA- oder Dienstkonto mit Operator-Rechten Checkmk-Spooldaten erzeugen. Diese Variante ist noch nicht Bestandteil der aktuellen Implementierung. Der komplette Checkmk-Agent sollte nicht allein fuer dieses Plugin auf eine andere Identitaet umgestellt werden, weil dies alle Agent-Sektionen und Local Checks betrifft.
|
Die Operator-Mitgliedschaft des Computerkontos steht allen auf diesem Server als `LocalSystem` laufenden Diensten fuer Netzwerkzugriffe zur Verfuegung. Falls diese Sicherheitsauswirkung nicht akzeptabel ist, kann ein separater Collector unter einem dedizierten gMSA- oder Dienstkonto mit Operator-Rechten Checkmk-Spooldaten erzeugen. Diese Variante ist noch nicht Bestandteil der aktuellen Implementierung. Der komplette Checkmk-Agent sollte nicht allein fuer dieses Plugin auf eine andere Identitaet umgestellt werden, weil dies alle Agent-Sektionen und Local Checks betrifft.
|
||||||
|
|
||||||
@@ -223,9 +225,13 @@ Quellen:
|
|||||||
|
|
||||||
Das Plugin ist bewusst defensiv gebaut:
|
Das Plugin ist bewusst defensiv gebaut:
|
||||||
|
|
||||||
|
- Der dependency-freie Regressionstest laeuft mit dem gleichen .NET-Framework-/MSBuild-Baseline wie die Anwendung.
|
||||||
- WMI-Queries haben ein konfigurierbares Timeout.
|
- WMI-Queries haben ein konfigurierbares Timeout.
|
||||||
- WMI-Namespace und Pflichtklassen werden getrennt auf Berechtigung, Konfiguration, Erreichbarkeit und Timeout geprueft.
|
- WMI-Namespace und Pflichtklassen werden getrennt auf Berechtigung, Konfiguration, Erreichbarkeit und Timeout geprueft.
|
||||||
- Management- und MessageBox-Datenbank werden mit der echten Agent-Identitaet getestet.
|
- Management- und Master-MessageBox-Datenbank werden aus einer dokumentierten WMI-Klasse ermittelt und mit der echten Agent-Identitaet getestet.
|
||||||
|
- `InvalidClass`/`InvalidQuery` werden als Schemafehler statt als Berechtigungsproblem ausgewiesen.
|
||||||
|
- Host Instances werden ohne namensabhaengigen WQL-Filter clientseitig auf den ueberwachten Server begrenzt.
|
||||||
|
- Bereits fuer Runtime-Zustaende gelesene Artefakte werden fuer das Best-Effort-Application-Mapping wiederverwendet; doppelte WMI-Abfragen entfallen.
|
||||||
- SQL-Fehlernummern werden in Berechtigung, Erreichbarkeit, Timeout oder Providerfehler klassifiziert.
|
- SQL-Fehlernummern werden in Berechtigung, Erreichbarkeit, Timeout oder Providerfehler klassifiziert.
|
||||||
- Fehlgeschlagene Pflichtabfragen erzeugen `UNKNOWN` statt irrefuehrender Nullwerte.
|
- Fehlgeschlagene Pflichtabfragen erzeugen `UNKNOWN` statt irrefuehrender Nullwerte.
|
||||||
- Optionale WMI-Klassen erzeugen Diagnosehinweise statt Totalabbruch.
|
- Optionale WMI-Klassen erzeugen Diagnosehinweise statt Totalabbruch.
|
||||||
@@ -338,6 +344,7 @@ Der Checkmk Windows Agent laeuft normalerweise als LocalSystem. Daher immer auch
|
|||||||
Die Diagnose im Service-Text nach `Massnahme:` abarbeiten. Wichtige Kategorien:
|
Die Diagnose im Service-Text nach `Massnahme:` abarbeiten. Wichtige Kategorien:
|
||||||
|
|
||||||
- `Wmi/Permission`: lokale Namespace-ACL oder BizTalk-Operator-Zuordnung pruefen.
|
- `Wmi/Permission`: lokale Namespace-ACL oder BizTalk-Operator-Zuordnung pruefen.
|
||||||
|
- `Wmi/Schema`: Klasse/WQL gegen das installierte BizTalk-Schema pruefen; `InvalidClass` ist nicht durch zusaetzliche Rechte loesbar.
|
||||||
- `Sql/Permission`: Maschinenkonto `DOMAIN\BIZTALKSERVER$` und BizTalk-Operator-Gruppe pruefen.
|
- `Sql/Permission`: Maschinenkonto `DOMAIN\BIZTALKSERVER$` und BizTalk-Operator-Gruppe pruefen.
|
||||||
- `Sql/Connectivity`: SQL-Server-/Instanzname, DNS, SQL-Dienst, TCP und Firewall pruefen.
|
- `Sql/Connectivity`: SQL-Server-/Instanzname, DNS, SQL-Dienst, TCP und Firewall pruefen.
|
||||||
- `Sql/Timeout`: SQL- und Netzwerkauslastung pruefen; Timeout nicht als erste Massnahme erhoehen.
|
- `Sql/Timeout`: SQL- und Netzwerkauslastung pruefen; Timeout nicht als erste Massnahme erhoehen.
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
Der Ansatz ist fuer Umgebungen wie `ACC`, `DEV`, `TST` und `PRD` gedacht, in denen pro Umgebung ein BizTalk Server 2020 und ein SQL Server betrieben werden. SQL Server bleibt beim mitgelieferten Checkmk-MSSQL-Plugin; dieses Projekt ergaenzt die BizTalk-spezifische Sicht.
|
Der Ansatz ist fuer Umgebungen wie `ACC`, `DEV`, `TST` und `PRD` gedacht, in denen pro Umgebung ein BizTalk Server 2020 und ein SQL Server betrieben werden. SQL Server bleibt beim mitgelieferten Checkmk-MSSQL-Plugin; dieses Projekt ergaenzt die BizTalk-spezifische Sicht.
|
||||||
|
|
||||||
|
Die Plattform- und SQL-Zielermittlung verwendet ausschliesslich die dokumentierte WMI-Klasse `MSBTS_GroupSetting`. Management-Datenbank und Master-MessageBox werden ueber `MgmtDbServerName`/`MgmtDbName` sowie `SubscriptionDBServerName`/`SubscriptionDBName` gelesen. Eine Klasse `MSBTS_MessageBoxSetting` gehoert nicht zum BizTalk-WMI-Schema und wird bewusst nicht abgefragt.
|
||||||
|
|
||||||
## Warum Local Check statt serverseitigem Check-Plugin?
|
## Warum Local Check statt serverseitigem Check-Plugin?
|
||||||
|
|
||||||
Checkmk 2.4 kann Windows-Agent-Plugins und Local Checks direkt ausfuehren. Fuer diese Umgebung ist ein C#/.NET-Framework-Programm mit `.cmd`-Wrapper die robusteste Variante:
|
Checkmk 2.4 kann Windows-Agent-Plugins und Local Checks direkt ausfuehren. Fuer diese Umgebung ist ein C#/.NET-Framework-Programm mit `.cmd`-Wrapper die robusteste Variante:
|
||||||
@@ -34,7 +36,7 @@ Beispielausgaben stehen in [docs/ExampleOutput.md](docs/ExampleOutput.md).
|
|||||||
|
|
||||||
Voraussetzungen auf einem Windows-Build-Host:
|
Voraussetzungen auf einem Windows-Build-Host:
|
||||||
|
|
||||||
- Visual Studio 2022 Build Tools oder Visual Studio
|
- Visual Studio 2019/2022 Build Tools oder Visual Studio
|
||||||
- MSBuild im `PATH`
|
- MSBuild im `PATH`
|
||||||
- .NET Framework 4.7.2 Developer Pack
|
- .NET Framework 4.7.2 Developer Pack
|
||||||
|
|
||||||
@@ -44,6 +46,12 @@ Build:
|
|||||||
scripts\build-release.cmd
|
scripts\build-release.cmd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Build plus dependency-free regression tests:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
scripts\test-release.cmd
|
||||||
|
```
|
||||||
|
|
||||||
Deployment-Paket erstellen:
|
Deployment-Paket erstellen:
|
||||||
|
|
||||||
```cmd
|
```cmd
|
||||||
@@ -66,6 +74,8 @@ Validierung nach dem Build:
|
|||||||
artifacts\BizTalkCheckmkPulse-deploy\biztalk_checkmk_pulse.cmd --self-test
|
artifacts\BizTalkCheckmkPulse-deploy\biztalk_checkmk_pulse.cmd --self-test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Der Self-Test fuehrt keine WMI-, SQL- oder Event-Log-Abfrage aus und muss genau sechs `OK`-Zeilen liefern. Der Test-Runner prueft zusaetzlich UNKNOWN-Fallbacks, dynamische Application-Services, FQDN-/Kurznamensvergleich ohne WQL-Namensfilter und den dokumentierten `MSBTS_GroupSetting`-Queryvertrag. Die zusaetzliche lokale Verifikation mit Mono/MSBuild 16 prueft Build und Ausgabeformat, ersetzt aber nicht den Windows-/BizTalk-Test.
|
||||||
|
|
||||||
## Installation auf dem BizTalk-Server
|
## Installation auf dem BizTalk-Server
|
||||||
|
|
||||||
Kopiere den Inhalt von `artifacts\BizTalkCheckmkPulse-deploy` nach:
|
Kopiere den Inhalt von `artifacts\BizTalkCheckmkPulse-deploy` nach:
|
||||||
@@ -113,7 +123,7 @@ Wichtige Werte:
|
|||||||
| `ServicePrefix` | `BizTalk` | Prefix fuer alle Checkmk-Services. |
|
| `ServicePrefix` | `BizTalk` | Prefix fuer alle Checkmk-Services. |
|
||||||
| `EnvironmentName` | leer | Optional `ACC`, `DEV`, `TST` oder `PRD`. |
|
| `EnvironmentName` | leer | Optional `ACC`, `DEV`, `TST` oder `PRD`. |
|
||||||
| `QueryTimeoutSeconds` | `25` | WMI-Timeout pro Query. |
|
| `QueryTimeoutSeconds` | `25` | WMI-Timeout pro Query. |
|
||||||
| `ProbeSqlConnectivity` | `true` | Prueft die integrierte Windows-Anmeldung an den per WMI ermittelten Management- und MessageBox-Datenbanken. |
|
| `ProbeSqlConnectivity` | `true` | Prueft die integrierte Windows-Anmeldung an der per WMI ermittelten Management- und Master-MessageBox-Datenbank. |
|
||||||
| `SqlConnectionTimeoutSeconds` | `5` | Timeout je SQL-Ziel fuer Verbindungsaufbau und harmlose Testabfrage. |
|
| `SqlConnectionTimeoutSeconds` | `5` | Timeout je SQL-Ziel fuer Verbindungsaufbau und harmlose Testabfrage. |
|
||||||
| `WarnResumableThreshold` | `1` | WARN ab n resumable suspended instances. |
|
| `WarnResumableThreshold` | `1` | WARN ab n resumable suspended instances. |
|
||||||
| `CritNonResumableThreshold` | `1` | CRIT ab n non-resumable suspended instances. |
|
| `CritNonResumableThreshold` | `1` | CRIT ab n non-resumable suspended instances. |
|
||||||
@@ -202,13 +212,15 @@ Erwartet werden die sechs stabilen `BizTalk ...` Services mit plausiblen Daten.
|
|||||||
Das Programm prueft Berechtigungen aktiv:
|
Das Programm prueft Berechtigungen aktiv:
|
||||||
|
|
||||||
- Der WMI-Namespace-Verbindungsaufbau und jede erforderliche WMI-Klasse werden getrennt bewertet.
|
- Der WMI-Namespace-Verbindungsaufbau und jede erforderliche WMI-Klasse werden getrennt bewertet.
|
||||||
- Fehler werden als `Permission`, `Connectivity`, `Timeout`, `Configuration` oder `Provider` klassifiziert.
|
- Fehler werden als `Permission`, `Connectivity`, `Timeout`, `Configuration`, `Schema` oder `Provider` klassifiziert.
|
||||||
- `BizTalk SQL Access` oeffnet mit integrierter Windows-Authentifizierung eine Verbindung zur ermittelten Management- und MessageBox-Datenbank und fuehrt `SELECT 1` aus.
|
- `BizTalk SQL Access` oeffnet mit integrierter Windows-Authentifizierung eine Verbindung zur ermittelten Management- und Master-MessageBox-Datenbank und fuehrt `SELECT 1` aus.
|
||||||
- Die Service-Ausgabe nennt Ausfuehrungsidentitaet, erwartete Netzwerkidentitaet, betroffene Komponente, technische Ursache und konkrete Massnahme.
|
- Die Service-Ausgabe nennt Ausfuehrungsidentitaet, erwartete Netzwerkidentitaet, betroffene Komponente, technische Ursache und konkrete Massnahme.
|
||||||
- Fehlgeschlagene Pflichtabfragen werden nie als leerer, erfolgreicher Datenbestand gewertet. Der betroffene Service wird `UNKNOWN`.
|
- Fehlgeschlagene Pflichtabfragen werden nie als leerer, erfolgreicher Datenbestand gewertet. Der betroffene Service wird `UNKNOWN`.
|
||||||
|
|
||||||
`Sql/Configuration` weist je nach Detailtext entweder auf eine unvollstaendige WMI-Zielermittlung oder auf TLS-, Zertifikats-, SPN-/SSPI-Probleme hin. Die Diagnose empfiehlt bewusst nicht, SQL-Verschluesselung pauschal abzuschalten.
|
`Sql/Configuration` weist je nach Detailtext entweder auf eine unvollstaendige WMI-Zielermittlung oder auf TLS-, Zertifikats-, SPN-/SSPI-Probleme hin. Die Diagnose empfiehlt bewusst nicht, SQL-Verschluesselung pauschal abzuschalten.
|
||||||
|
|
||||||
|
`Wmi/Schema` kennzeichnet `InvalidClass` oder `InvalidQuery`. Das ist kein Berechtigungsfehler: Klassen- und Property-Namen muessen gegen das installierte BizTalk-WMI-Schema geprueft werden; eine Rechteerhoehung kann eine nicht vorhandene Klasse nicht erzeugen. Die technischen Details enthalten die ausgefuehrte WQL-Abfrage und deren Laufzeit bis zum Fehler.
|
||||||
|
|
||||||
Der SQL-Zugriffstest ersetzt nicht das Checkmk-MSSQL-Plugin auf dem SQL-Server. Er prueft ausschliesslich, ob genau die Identitaet des BizTalk Local Checks die fuer seine Diagnose benoetigten BizTalk-Datenbankziele erreichen kann.
|
Der SQL-Zugriffstest ersetzt nicht das Checkmk-MSSQL-Plugin auf dem SQL-Server. Er prueft ausschliesslich, ob genau die Identitaet des BizTalk Local Checks die fuer seine Diagnose benoetigten BizTalk-Datenbankziele erreichen kann.
|
||||||
|
|
||||||
Da bei fehlenden Rechten jeder Lauf einen abgewiesenen SQL-Login erzeugen kann, wird fuer den produktiven Betrieb eine asynchrone Ausfuehrung mit 300 Sekunden Cache empfohlen. Das begrenzt SQL-Logeintraege und Last, verzoegert einen Zustandswechsel aber um maximal fuenf Minuten. Beispiel in `%ProgramData%\checkmk\agent\check_mk.user.yml`:
|
Da bei fehlenden Rechten jeder Lauf einen abgewiesenen SQL-Login erzeugen kann, wird fuer den produktiven Betrieb eine asynchrone Ausfuehrung mit 300 Sekunden Cache empfohlen. Das begrenzt SQL-Logeintraege und Last, verzoegert einen Zustandswechsel aber um maximal fuenf Minuten. Beispiel in `%ProgramData%\checkmk\agent\check_mk.user.yml`:
|
||||||
@@ -240,6 +252,7 @@ Entscheidungsmatrix:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Alle BizTalk-Services liefern plausible Daten | Keine Berechtigungsaenderung erforderlich. |
|
| Alle BizTalk-Services liefern plausible Daten | Keine Berechtigungsaenderung erforderlich. |
|
||||||
| Verbindung zu `root\MicrosoftBizTalkServer` scheitert | Namespace, BizTalk-WMI-Provider, WMI-Dienst und Namespace-ACL gezielt pruefen. Keine pauschalen WMI-Rechte vergeben. |
|
| Verbindung zu `root\MicrosoftBizTalkServer` scheitert | Namespace, BizTalk-WMI-Provider, WMI-Dienst und Namespace-ACL gezielt pruefen. Keine pauschalen WMI-Rechte vergeben. |
|
||||||
|
| Service meldet `Wmi/Schema` beziehungsweise `InvalidClass`/`InvalidQuery` | WMI-Klasse und Properties gegen das BizTalk-Schema pruefen. Keine Berechtigungen erweitern. |
|
||||||
| `BizTalk SQL Access` meldet `Sql/Permission` | Computerkonto `DOMAIN\BIZTALKSERVER$` in die konfigurierte BizTalk-Operator-Gruppe aufnehmen, Kerberos erneuern und erneut testen. Keine direkten BizTalk-DB-Rollen vergeben. |
|
| `BizTalk SQL Access` meldet `Sql/Permission` | Computerkonto `DOMAIN\BIZTALKSERVER$` in die konfigurierte BizTalk-Operator-Gruppe aufnehmen, Kerberos erneuern und erneut testen. Keine direkten BizTalk-DB-Rollen vergeben. |
|
||||||
| `BizTalk SQL Access` meldet `Sql/Connectivity` oder `Sql/Timeout` | Server-/Instanzname, DNS, SQL-Dienst, TCP-Protokoll, Port und Firewall aus Sicht des BizTalk-Servers pruefen. |
|
| `BizTalk SQL Access` meldet `Sql/Connectivity` oder `Sql/Timeout` | Server-/Instanzname, DNS, SQL-Dienst, TCP-Protokoll, Port und Firewall aus Sicht des BizTalk-Servers pruefen. |
|
||||||
| Nur SQL-gestuetzte BizTalk-Klassen liefern `Access denied` oder `UNKNOWN` | Computerkonto `DOMAIN\BIZTALKSERVER$` zunaechst in `BizTalk Server Operators` aufnehmen. |
|
| Nur SQL-gestuetzte BizTalk-Klassen liefern `Access denied` oder `UNKNOWN` | Computerkonto `DOMAIN\BIZTALKSERVER$` zunaechst in `BizTalk Server Operators` aufnehmen. |
|
||||||
@@ -270,6 +283,8 @@ Empfohlene Alarmierung:
|
|||||||
- Checkmk MKP-Pakete: https://docs.checkmk.com/latest/en/mkps.html
|
- Checkmk MKP-Pakete: https://docs.checkmk.com/latest/en/mkps.html
|
||||||
- Microsoft BizTalk WMI `MSBTS_ServiceInstance`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-wmi
|
- Microsoft BizTalk WMI `MSBTS_ServiceInstance`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-wmi
|
||||||
- Microsoft BizTalk WMI `ServiceStatus`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-servicestatus-property-wmi
|
- Microsoft BizTalk WMI `ServiceStatus`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-serviceinstance-servicestatus-property-wmi
|
||||||
|
- Microsoft BizTalk WMI `MSBTS_GroupSetting`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-wmi
|
||||||
|
- Microsoft BizTalk WMI Core Server Classes: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/core-server-classes
|
||||||
- Microsoft BizTalk Mindestberechtigungen: https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights
|
- Microsoft BizTalk Mindestberechtigungen: https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights
|
||||||
- Microsoft BizTalk Access Control: https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-security
|
- Microsoft BizTalk Access Control: https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-security
|
||||||
- Microsoft LocalSystem und Computerkonten: https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer
|
- Microsoft LocalSystem und Computerkonten: https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ set "EXE=%BASE%\BizTalkCheckmkPulse.exe"
|
|||||||
|
|
||||||
if not exist "%EXE%" (
|
if not exist "%EXE%" (
|
||||||
echo 3 "BizTalk Platform" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen und danach cmk-agent-ctl.exe dump erneut ausfuehren.
|
echo 3 "BizTalk Platform" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen und danach cmk-agent-ctl.exe dump erneut ausfuehren.
|
||||||
|
echo 3 "BizTalk SQL Access" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||||
|
echo 3 "BizTalk Suspended Instances" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||||
|
echo 3 "BizTalk Host Instances" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||||
|
echo 3 "BizTalk Runtime Artifacts" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||||
|
echo 3 "BizTalk Event Log" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||||
exit /b 0
|
exit /b 0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,5 +18,10 @@ if not exist "%EXE%" (
|
|||||||
set "EXITCODE=%ERRORLEVEL%"
|
set "EXITCODE=%ERRORLEVEL%"
|
||||||
if not "%EXITCODE%"=="0" (
|
if not "%EXITCODE%"=="0" (
|
||||||
echo 3 "BizTalk Platform" - BizTalkCheckmkPulse.exe konnte nicht erfolgreich gestartet werden, Exitcode=%EXITCODE%. Massnahme: .NET Framework 4.7.2, EXE/Config-Dateien und Windows Application Log pruefen.
|
echo 3 "BizTalk Platform" - BizTalkCheckmkPulse.exe konnte nicht erfolgreich gestartet werden, Exitcode=%EXITCODE%. Massnahme: .NET Framework 4.7.2, EXE/Config-Dateien und Windows Application Log pruefen.
|
||||||
|
echo 3 "BizTalk SQL Access" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: .NET Framework 4.7.2, EXE/Config-Dateien und Windows Application Log pruefen.
|
||||||
|
echo 3 "BizTalk Suspended Instances" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||||
|
echo 3 "BizTalk Host Instances" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||||
|
echo 3 "BizTalk Runtime Artifacts" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||||
|
echo 3 "BizTalk Event Log" - BizTalkCheckmkPulse.exe endete mit Exitcode=%EXITCODE%. Massnahme: Programmstart und Windows Application Log pruefen.
|
||||||
)
|
)
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ Die Ausgabe ist so gebaut, dass sie auch mit Checkmk 2.4.0p4 kompatibel bleibt:
|
|||||||
Zweck:
|
Zweck:
|
||||||
|
|
||||||
- Prueft, ob der BizTalk-WMI-Namespace erreichbar ist.
|
- Prueft, ob der BizTalk-WMI-Namespace erreichbar ist.
|
||||||
- Zeigt Server, Gruppe, Management-DB und MessageBox-DB, soweit WMI diese Werte liefert.
|
- Zeigt Server, Gruppe, Management-DB und Master-MessageBox-DB aus `MSBTS_GroupSetting`.
|
||||||
|
|
||||||
Status:
|
Status:
|
||||||
|
|
||||||
| Status | Bedingung |
|
| Status | Bedingung |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `OK` | WMI-Verbindung und beide Plattform-Pflichtklassen erfolgreich. |
|
| `OK` | WMI-Verbindung erfolgreich und `MSBTS_GroupSetting` liefert beide vollstaendigen Datenbankziele. |
|
||||||
| `UNKNOWN` | Namespace, `MSBTS_GroupSetting`, `MSBTS_MessageBoxSetting` oder Programmstart fehlgeschlagen. |
|
| `UNKNOWN` | Namespace, `MSBTS_GroupSetting`, ein erforderliches Datenbankziel oder der Programmstart fehlgeschlagen. |
|
||||||
|
|
||||||
Metriken:
|
Metriken:
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ Metriken:
|
|||||||
|
|
||||||
Zweck:
|
Zweck:
|
||||||
|
|
||||||
- Ermittelt Management- und MessageBox-Datenbank ueber BizTalk-WMI.
|
- Ermittelt Management- und Master-MessageBox-Datenbank ueber `MSBTS_GroupSetting`.
|
||||||
- Oeffnet mit der Windows-Identitaet des Checkmk-Agentprozesses eine integrierte SQL-Verbindung.
|
- Oeffnet mit der Windows-Identitaet des Checkmk-Agentprozesses eine integrierte SQL-Verbindung.
|
||||||
- Fuehrt die harmlose Abfrage `SELECT 1` aus und schliesst die Verbindung sofort wieder.
|
- Fuehrt die harmlose Abfrage `SELECT 1` aus und schliesst die Verbindung sofort wieder.
|
||||||
- Zeigt lokale Ausfuehrungsidentitaet und erwartete Netzwerkidentitaet an.
|
- Zeigt lokale Ausfuehrungsidentitaet und erwartete Netzwerkidentitaet an.
|
||||||
@@ -93,6 +93,7 @@ Metriken:
|
|||||||
Zweck:
|
Zweck:
|
||||||
|
|
||||||
- Ueberwacht BizTalk Host Instances auf dem BizTalk-Server.
|
- Ueberwacht BizTalk Host Instances auf dem BizTalk-Server.
|
||||||
|
- Filtert die gruppenweite WMI-Auflistung clientseitig auf den konfigurierten BizTalk-Server; Namen mit Sonderzeichen gelangen nicht in WQL.
|
||||||
- Nicht gestartete Host Instances sind normalerweise betriebsrelevant.
|
- Nicht gestartete Host Instances sind normalerweise betriebsrelevant.
|
||||||
|
|
||||||
Status:
|
Status:
|
||||||
@@ -134,7 +135,7 @@ Metriken:
|
|||||||
|
|
||||||
| Metrik | Bedeutung |
|
| Metrik | Bedeutung |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `biztalk_applications` | Anzahl erkannter BizTalk-Anwendungen. |
|
| `biztalk_applications` | Anzahl der per WMI erkannten Anwendungs-Buckets; `(unknown)` ist moeglich, da die dokumentierten Artefaktklassen keine verlaessliche Application-Property garantieren. |
|
||||||
| `biztalk_receive_locations` | Gesamtzahl Receive Locations. |
|
| `biztalk_receive_locations` | Gesamtzahl Receive Locations. |
|
||||||
| `biztalk_receive_locations_disabled` | Deaktivierte Receive Locations. |
|
| `biztalk_receive_locations_disabled` | Deaktivierte Receive Locations. |
|
||||||
| `biztalk_send_ports` | Gesamtzahl Send Ports. |
|
| `biztalk_send_ports` | Gesamtzahl Send Ports. |
|
||||||
@@ -171,10 +172,10 @@ Metriken:
|
|||||||
|
|
||||||
## Optionale per-Application-Services
|
## Optionale per-Application-Services
|
||||||
|
|
||||||
Wenn `EmitPerApplicationSuspensionServices=true` gesetzt ist, werden zusaetzliche Services fuer Anwendungen erzeugt, die suspendierte Instanzen haben:
|
Wenn `EmitPerApplicationSuspensionServices=true` gesetzt ist, werden zusaetzliche Services fuer Anwendungen erzeugt, die suspendierte Instanzen haben und deren Anwendung per WMI tatsaechlich zugeordnet werden konnte:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
BizTalk Suspended <ApplicationName>
|
BizTalk Suspended <ApplicationName>
|
||||||
```
|
```
|
||||||
|
|
||||||
Das ist fuer Anwendungsteams hilfreich, kann aber die Service-Anzahl erhoehen. Fuer den Basisausbau wird empfohlen, diese Option deaktiviert zu lassen.
|
Nicht zuordenbare Instanzen bleiben im stabilen Aggregat-Service enthalten; ein irrefuehrender per-Application-Service namens `(unknown)` wird nicht erzeugt. Die Option kann die Service-Anzahl erhoehen und bleibt fuer den Basisausbau deaktiviert.
|
||||||
|
|||||||
+11
-2
@@ -6,13 +6,16 @@
|
|||||||
0 "BizTalk Platform" - Self test OK. Checkmk local check output is valid.
|
0 "BizTalk Platform" - Self test OK. Checkmk local check output is valid.
|
||||||
0 "BizTalk SQL Access" biztalk_sql_targets_total=0;;;0 Self test OK. No SQL connection was opened.
|
0 "BizTalk SQL Access" biztalk_sql_targets_total=0;;;0 Self test OK. No SQL connection was opened.
|
||||||
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0 Self test OK.
|
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0 Self test OK.
|
||||||
|
0 "BizTalk Host Instances" biztalk_host_instances_total=0;;;0 Self test OK. No WMI query was executed.
|
||||||
|
0 "BizTalk Runtime Artifacts" biztalk_applications=0;;;0 Self test OK. No WMI query was executed.
|
||||||
|
0 "BizTalk Event Log" biztalk_eventlog_errors=0;;;0 Self test OK. No event log was read.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Gesunder BizTalk-Server
|
## Gesunder BizTalk-Server
|
||||||
|
|
||||||
```text
|
```text
|
||||||
0 "BizTalk Platform" - BizTalk WMI and platform data reachable, server=BIZTALK01, group=BizTalkMgmtDb, mgmt_db=SQL01\BizTalkMgmtDb, msgbox_db=SQL01\BizTalkMsgBoxDb
|
0 "BizTalk Platform" - BizTalk WMI and platform data reachable, server=BIZTALK01, group=BizTalkMgmtDb, mgmt_db=SQL01\BizTalkMgmtDb, msgbox_db=SQL01\BizTalkMsgBoxDb
|
||||||
0 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=2;;;0|biztalk_sql_targets_failed=0;;1;0 SQL access targets=2, available=2, discovery_complete=True, execution_identity=NT AUTHORITY\SYSTEM, network_identity=<DOMAIN>\BIZTALK01$; databases=Management=SQL01\BizTalkMgmtDb:OK, MessageBox=SQL01\BizTalkMsgBoxDb:OK
|
0 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=2;;;0|biztalk_sql_targets_failed=0;;1;0 SQL access targets=2, available=2, discovery_complete=True, execution_identity=NT AUTHORITY\SYSTEM, network_identity=<DOMAIN>\BIZTALK01$; databases=Management=SQL01\BizTalkMgmtDb:OK, MasterMessageBox=SQL01\BizTalkMsgBoxDb:OK
|
||||||
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0|biztalk_suspended_resumable=0;1;;0|biztalk_suspended_nonresumable=0;;1;0 No suspended BizTalk service instances found.
|
0 "BizTalk Suspended Instances" biztalk_suspended_total=0;;;0|biztalk_suspended_resumable=0;1;;0|biztalk_suspended_nonresumable=0;;1;0 No suspended BizTalk service instances found.
|
||||||
0 "BizTalk Host Instances" biztalk_host_instances_total=4;;;0|biztalk_host_instances_started=4;;;0|biztalk_host_instances_stopped=0;;1;0|biztalk_host_instances_pending=0;1;;0|biztalk_host_instances_unknown=0;;1;0 Host instances total=4, started=4, stopped=0, pending=0, unknown=0
|
0 "BizTalk Host Instances" biztalk_host_instances_total=4;;;0|biztalk_host_instances_started=4;;;0|biztalk_host_instances_stopped=0;;1;0|biztalk_host_instances_pending=0;1;;0|biztalk_host_instances_unknown=0;;1;0 Host instances total=4, started=4, stopped=0, pending=0, unknown=0
|
||||||
0 "BizTalk Runtime Artifacts" biztalk_applications=8;;;0|biztalk_receive_locations=24;;;0|biztalk_receive_locations_disabled=0;1;;0|biztalk_send_ports=31;;;0|biztalk_send_ports_started=31;;;0|biztalk_send_ports_inactive=0;1;;0|biztalk_send_ports_unknown=0;;1;0|biztalk_orchestrations=12;;;0|biztalk_orchestrations_started=12;;;0|biztalk_orchestrations_inactive=0;1;;0|biztalk_orchestrations_unknown=0;;1;0 Applications=8; receive_locations total=24, disabled=0; send_ports total=31, started=31, inactive=0, unknown=0; orchestrations total=12, started=12, inactive=0, unknown=0
|
0 "BizTalk Runtime Artifacts" biztalk_applications=8;;;0|biztalk_receive_locations=24;;;0|biztalk_receive_locations_disabled=0;1;;0|biztalk_send_ports=31;;;0|biztalk_send_ports_started=31;;;0|biztalk_send_ports_inactive=0;1;;0|biztalk_send_ports_unknown=0;;1;0|biztalk_orchestrations=12;;;0|biztalk_orchestrations_started=12;;;0|biztalk_orchestrations_inactive=0;1;;0|biztalk_orchestrations_unknown=0;;1;0 Applications=8; receive_locations total=24, disabled=0; send_ports total=31, started=31, inactive=0, unknown=0; orchestrations total=12, started=12, inactive=0, unknown=0
|
||||||
@@ -28,7 +31,7 @@
|
|||||||
## SQL-Berechtigungsfehler
|
## SQL-Berechtigungsfehler
|
||||||
|
|
||||||
```text
|
```text
|
||||||
3 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=0;;;0|biztalk_sql_targets_failed=2;;1;0 SQL access targets=2, available=0, discovery_complete=True, execution_identity=NT AUTHORITY\SYSTEM, network_identity=<DOMAIN>\BIZTALK01$; databases=Management=SQL01\BizTalkMgmtDb:FAILED, MessageBox=SQL01\BizTalkMsgBoxDb:FAILED; diagnostics: Sql/Permission [Management SQL01\BizTalkMgmtDb]: SQL Server hat die integrierte Anmeldung abgelehnt. Erwartete Netzwerkidentitaet: <DOMAIN>\BIZTALK01$. Massnahme: <DOMAIN>\BIZTALK01$ in die konfigurierte BizTalk-Operator-Gruppe aufnehmen; keine direkten BizTalk-DB-Rollen vergeben. Danach Kerberos-Tickets erneuern und den Agent-Dump wiederholen. Technik: SqlException Number=18456: Login failed for user
|
3 "BizTalk SQL Access" biztalk_sql_targets_total=2;;;0|biztalk_sql_targets_available=0;;;0|biztalk_sql_targets_failed=2;;1;0 SQL access targets=2, available=0, discovery_complete=True, execution_identity=NT AUTHORITY\SYSTEM, network_identity=<DOMAIN>\BIZTALK01$; databases=Management=SQL01\BizTalkMgmtDb:FAILED, MasterMessageBox=SQL01\BizTalkMsgBoxDb:FAILED; diagnostics: Sql/Permission [Management SQL01\BizTalkMgmtDb]: SQL Server hat die integrierte Anmeldung abgelehnt. Erwartete Netzwerkidentitaet: <DOMAIN>\BIZTALK01$. Massnahme: <DOMAIN>\BIZTALK01$ in die konfigurierte BizTalk-Operator-Gruppe aufnehmen; keine direkten BizTalk-DB-Rollen vergeben. Danach Kerberos-Tickets erneuern und den Agent-Dump wiederholen. Technik: SqlException Number=18456: Login failed for user
|
||||||
```
|
```
|
||||||
|
|
||||||
## WMI-Berechtigungsfehler
|
## WMI-Berechtigungsfehler
|
||||||
@@ -37,6 +40,12 @@
|
|||||||
3 "BizTalk Suspended Instances" - Suspendierte Instanzen konnten nicht verlaesslich gelesen werden. Ein leerer Datenbestand wird nicht als OK gewertet.; diagnostics: Wmi/Permission [MSBTS_ServiceInstance]: Zugriff auf MSBTS_ServiceInstance wurde im LocalSystem-Kontext verweigert. Massnahme: Agent-Dump pruefen und Computerkonto <DOMAIN>\BIZTALK01$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen. Technik: UnauthorizedAccessException HRESULT=0x80070005: Access is denied
|
3 "BizTalk Suspended Instances" - Suspendierte Instanzen konnten nicht verlaesslich gelesen werden. Ein leerer Datenbestand wird nicht als OK gewertet.; diagnostics: Wmi/Permission [MSBTS_ServiceInstance]: Zugriff auf MSBTS_ServiceInstance wurde im LocalSystem-Kontext verweigert. Massnahme: Agent-Dump pruefen und Computerkonto <DOMAIN>\BIZTALK01$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen. Technik: UnauthorizedAccessException HRESULT=0x80070005: Access is denied
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## WMI-Schemafehler
|
||||||
|
|
||||||
|
```text
|
||||||
|
3 "BizTalk Runtime Artifacts" - BizTalk Runtime Artifacts konnten nicht vollstaendig gelesen werden. Teilwerte werden nicht als OK gewertet.; diagnostics: Wmi/Schema [MSBTS_Orchestration]: WMI-Klasse oder WQL fuer MSBTS_Orchestration wird vom installierten BizTalk-Provider nicht unterstuetzt. Massnahme: Klassen- und Property-Namen gegen das installierte BizTalk-WMI-Schema und die Microsoft-Dokumentation pruefen. Rechteerhoehung behebt InvalidClass/InvalidQuery nicht. Technik: ManagementException HRESULT=0x80041010: Invalid class WQL={SELECT * FROM MSBTS_Orchestration} DurationMs=18
|
||||||
|
```
|
||||||
|
|
||||||
## Fehlendes Deployment
|
## Fehlendes Deployment
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
+4
-1
@@ -97,7 +97,7 @@ Der direkte Start des Wrappers in einer administrativen Eingabeaufforderung ist
|
|||||||
|
|
||||||
Die Ausgabe muss die sechs stabilen `BizTalk ...` Services mit plausiblen Daten enthalten. `Access denied`, `UnauthorizedAccessException`, `Sql/Permission` und ein berechtigungsbedingtes `UNKNOWN` weisen auf eine fehlende Rollenzuordnung hin.
|
Die Ausgabe muss die sechs stabilen `BizTalk ...` Services mit plausiblen Daten enthalten. `Access denied`, `UnauthorizedAccessException`, `Sql/Permission` und ein berechtigungsbedingtes `UNKNOWN` weisen auf eine fehlende Rollenzuordnung hin.
|
||||||
|
|
||||||
Die EXE klassifiziert WMI- und SQL-Probleme und schreibt zu jeder Diagnose `Massnahme:` und `Technik:`. Eine fehlgeschlagene erforderliche WMI-Abfrage erzeugt beim betroffenen Service immer `UNKNOWN`; fehlende Daten werden nicht als Nullbestand und damit nicht als `OK` ausgegeben.
|
Die EXE klassifiziert WMI- und SQL-Probleme und schreibt zu jeder Diagnose `Massnahme:` und `Technik:`. WMI-Schemafehler (`InvalidClass`/`InvalidQuery`) werden separat als `Wmi/Schema` ausgewiesen und duerfen nicht durch Rechteerweiterungen behandelt werden. Eine fehlgeschlagene erforderliche WMI-Abfrage erzeugt beim betroffenen Service immer `UNKNOWN`; fehlende Daten werden nicht als Nullbestand und damit nicht als `OK` ausgegeben.
|
||||||
|
|
||||||
Fuer den produktiven Betrieb wird empfohlen, den Local Check alle 300 Sekunden asynchron auszufuehren. Dadurch erzeugen fehlende SQL-Rechte nicht bei jedem Agent-Abruf neue fehlgeschlagene Logins. In `%ProgramData%\checkmk\agent\check_mk.user.yml`:
|
Fuer den produktiven Betrieb wird empfohlen, den Local Check alle 300 Sekunden asynchron auszufuehren. Dadurch erzeugen fehlende SQL-Rechte nicht bei jedem Agent-Abruf neue fehlgeschlagene Logins. In `%ProgramData%\checkmk\agent\check_mk.user.yml`:
|
||||||
|
|
||||||
@@ -130,6 +130,7 @@ Entscheidungsmatrix:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Alle sechs stabilen Services liefern plausible Werte | Keine Aenderung erforderlich. |
|
| Alle sechs stabilen Services liefern plausible Werte | Keine Aenderung erforderlich. |
|
||||||
| `root\MicrosoftBizTalkServer` ist nicht erreichbar | BizTalk-WMI-Provider, WMI-Dienst, Namespace und dessen ACL gezielt pruefen. |
|
| `root\MicrosoftBizTalkServer` ist nicht erreichbar | BizTalk-WMI-Provider, WMI-Dienst, Namespace und dessen ACL gezielt pruefen. |
|
||||||
|
| `Wmi/Schema` beziehungsweise `InvalidClass`/`InvalidQuery` | Klassen- und Property-Namen gegen das installierte BizTalk-WMI-Schema pruefen; keine Berechtigungen erweitern. |
|
||||||
| `BizTalk SQL Access` meldet `Sql/Permission` | Maschinenkonto in die konfigurierte BizTalk-Operator-Gruppe aufnehmen, Kerberos erneuern und Agent-Dump wiederholen. |
|
| `BizTalk SQL Access` meldet `Sql/Permission` | Maschinenkonto in die konfigurierte BizTalk-Operator-Gruppe aufnehmen, Kerberos erneuern und Agent-Dump wiederholen. |
|
||||||
| `BizTalk SQL Access` meldet `Sql/Connectivity` | SQL-Server-/Instanzname, DNS, Dienst, TCP-Port und Firewall pruefen. |
|
| `BizTalk SQL Access` meldet `Sql/Connectivity` | SQL-Server-/Instanzname, DNS, Dienst, TCP-Port und Firewall pruefen. |
|
||||||
| `BizTalk SQL Access` meldet `Sql/Timeout` | SQL-/Netzwerkauslastung untersuchen; Timeout nur nach Ursachenanalyse anpassen. |
|
| `BizTalk SQL Access` meldet `Sql/Timeout` | SQL-/Netzwerkauslastung untersuchen; Timeout nur nach Ursachenanalyse anpassen. |
|
||||||
@@ -149,6 +150,8 @@ Quellen:
|
|||||||
- Checkmk Local Checks: https://docs.checkmk.com/latest/en/localchecks.html
|
- Checkmk Local Checks: https://docs.checkmk.com/latest/en/localchecks.html
|
||||||
- BizTalk Minimum Security User Rights: https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights
|
- BizTalk Minimum Security User Rights: https://learn.microsoft.com/en-us/biztalk/core/minimum-security-user-rights
|
||||||
- BizTalk Access Control and Data Security: https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-security
|
- BizTalk Access Control and Data Security: https://learn.microsoft.com/en-us/biztalk/core/access-control-and-data-security
|
||||||
|
- BizTalk `MSBTS_GroupSetting`: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/msbts-groupsetting-wmi
|
||||||
|
- BizTalk WMI Core Server Classes: https://learn.microsoft.com/en-us/biztalk/core/technical-reference/core-server-classes
|
||||||
- Microsoft LocalSystem und Computerkonten: https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer
|
- Microsoft LocalSystem und Computerkonten: https://learn.microsoft.com/en-us/entra/architecture/service-accounts-computer
|
||||||
- Microsoft WMI Namespace Security: https://learn.microsoft.com/en-us/windows/win32/wmisdk/access-to-wmi-namespaces
|
- Microsoft WMI Namespace Security: https://learn.microsoft.com/en-us/windows/win32/wmisdk/access-to-wmi-namespaces
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,5 @@ if errorlevel 1 (
|
|||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
msbuild BizTalkCheckmkPulse.sln /p:Configuration=Release /p:Platform="Any CPU" /m /v:minimal
|
msbuild BizTalkCheckmkPulse.sln /p:Configuration=Release /p:Platform="Any CPU" /m:1 /v:minimal
|
||||||
exit /b %ERRORLEVEL%
|
exit /b %ERRORLEVEL%
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
call "%~dp0build-release.cmd"
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
|
||||||
|
"%~dp0..\tests\BizTalkCheckmkPulse.Tests\bin\Release\BizTalkCheckmkPulse.Tests.exe"
|
||||||
|
exit /b %ERRORLEVEL%
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
<Reference Include="System.Management" />
|
<Reference Include="System.Management" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="CheckmkLocalFormatter.cs" />
|
<Compile Include="CheckmkLocalFormatter.cs" />
|
||||||
<Compile Include="EventLogProbe.cs" />
|
<Compile Include="EventLogProbe.cs" />
|
||||||
<Compile Include="MonitoringOptions.cs" />
|
<Compile Include="MonitoringOptions.cs" />
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ namespace BizTalkCheckmkPulse
|
|||||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Platform"), "-", "Self test OK. Checkmk local check output is valid.");
|
yield return BuildLine(CheckState.Ok, _options.ServiceName("Platform"), "-", "Self test OK. Checkmk local check output is valid.");
|
||||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("SQL Access"), "biztalk_sql_targets_total=0;;;0", "Self test OK. No SQL connection was opened.");
|
yield return BuildLine(CheckState.Ok, _options.ServiceName("SQL Access"), "biztalk_sql_targets_total=0;;;0", "Self test OK. No SQL connection was opened.");
|
||||||
yield return BuildLine(CheckState.Ok, _options.ServiceName("Suspended Instances"), "biztalk_suspended_total=0;;;0", "Self test OK.");
|
yield return BuildLine(CheckState.Ok, _options.ServiceName("Suspended Instances"), "biztalk_suspended_total=0;;;0", "Self test OK.");
|
||||||
|
yield return BuildLine(CheckState.Ok, _options.ServiceName("Host Instances"), "biztalk_host_instances_total=0;;;0", "Self test OK. No WMI query was executed.");
|
||||||
|
yield return BuildLine(CheckState.Ok, _options.ServiceName("Runtime Artifacts"), "biztalk_applications=0;;;0", "Self test OK. No WMI query was executed.");
|
||||||
|
yield return BuildLine(CheckState.Ok, _options.ServiceName("Event Log"), "biztalk_eventlog_errors=0;;;0", "Self test OK. No event log was read.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -96,7 +99,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
AppendOptional(detail, "mgmt_db", JoinDb(result.Platform.ManagementDbServer, result.Platform.ManagementDbName));
|
AppendOptional(detail, "mgmt_db", JoinDb(result.Platform.ManagementDbServer, result.Platform.ManagementDbName));
|
||||||
AppendOptional(detail, "msgbox_db", JoinDb(result.Platform.MessageBoxDbServer, result.Platform.MessageBoxDbName));
|
AppendOptional(detail, "msgbox_db", JoinDb(result.Platform.MessageBoxDbServer, result.Platform.MessageBoxDbName));
|
||||||
|
|
||||||
var diagnostics = SelectDiagnostics(result, DiagnosticArea.Wmi, "WMI namespace connection", "MSBTS_GroupSetting", "MSBTS_MessageBoxSetting");
|
var diagnostics = SelectDiagnostics(result, DiagnosticArea.Wmi, "WMI namespace connection", "MSBTS_GroupSetting");
|
||||||
return BuildLine(state, _options.ServiceName("Platform"), "-", AppendDiagnostics(detail.ToString(), diagnostics));
|
return BuildLine(state, _options.ServiceName("Platform"), "-", AppendDiagnostics(detail.ToString(), diagnostics));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +337,10 @@ namespace BizTalkCheckmkPulse
|
|||||||
/// <returns>Checkmk-Zeilen je betroffener BizTalk-Anwendung.</returns>
|
/// <returns>Checkmk-Zeilen je betroffener BizTalk-Anwendung.</returns>
|
||||||
private IEnumerable<string> FormatApplicationSuspensions(ProbeResult result)
|
private IEnumerable<string> FormatApplicationSuspensions(ProbeResult result)
|
||||||
{
|
{
|
||||||
foreach (var group in result.SuspendedInstances.GroupBy(x => x.ApplicationName).OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase))
|
foreach (var group in result.SuspendedInstances
|
||||||
|
.Where(x => !string.Equals(x.ApplicationName, "(unknown)", StringComparison.OrdinalIgnoreCase))
|
||||||
|
.GroupBy(x => x.ApplicationName)
|
||||||
|
.OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var resumable = group.Count(x => x.Kind == SuspendedKind.Resumable);
|
var resumable = group.Count(x => x.Kind == SuspendedKind.Resumable);
|
||||||
var nonresumable = group.Count(x => x.Kind == SuspendedKind.NonResumable);
|
var nonresumable = group.Count(x => x.Kind == SuspendedKind.NonResumable);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
Connectivity,
|
Connectivity,
|
||||||
Timeout,
|
Timeout,
|
||||||
Configuration,
|
Configuration,
|
||||||
|
Schema,
|
||||||
Provider,
|
Provider,
|
||||||
Unexpected
|
Unexpected
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("BizTalkCheckmkPulse.Tests")]
|
||||||
@@ -35,7 +35,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddTarget(result, "Management", result.Platform.ManagementDbServer, result.Platform.ManagementDbName);
|
AddTarget(result, "Management", result.Platform.ManagementDbServer, result.Platform.ManagementDbName);
|
||||||
AddTarget(result, "MessageBox", result.Platform.MessageBoxDbServer, result.Platform.MessageBoxDbName);
|
AddTarget(result, "MasterMessageBox", result.Platform.MessageBoxDbServer, result.Platform.MessageBoxDbName);
|
||||||
|
|
||||||
if (!result.Platform.PlatformDataAvailable)
|
if (!result.Platform.PlatformDataAvailable)
|
||||||
{
|
{
|
||||||
@@ -46,7 +46,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
Component = "BizTalk database discovery",
|
Component = "BizTalk database discovery",
|
||||||
Required = true,
|
Required = true,
|
||||||
Summary = "SQL-Zielermittlung ist unvollstaendig, weil nicht alle erforderlichen BizTalk-Plattformklassen gelesen wurden.",
|
Summary = "SQL-Zielermittlung ist unvollstaendig, weil nicht alle erforderlichen BizTalk-Plattformklassen gelesen wurden.",
|
||||||
Action = "Zuerst den Service 'BizTalk Platform' sowie MSBTS_GroupSetting und MSBTS_MessageBoxSetting pruefen. Danach den Agent-Dump erneut ausfuehren."
|
Action = "Zuerst den Service 'BizTalk Platform' und MSBTS_GroupSetting pruefen. Danach den Agent-Dump erneut ausfuehren."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -23,6 +24,8 @@ namespace BizTalkCheckmkPulse
|
|||||||
private const int OrchestrationStopped = 3;
|
private const int OrchestrationStopped = 3;
|
||||||
private const int OrchestrationStarted = 4;
|
private const int OrchestrationStarted = 4;
|
||||||
private const int EAccessDenied = unchecked((int)0x80070005);
|
private const int EAccessDenied = unchecked((int)0x80070005);
|
||||||
|
internal const string GroupSettingQuery =
|
||||||
|
"SELECT Name, MgmtDbServerName, MgmtDbName, SubscriptionDBServerName, SubscriptionDBName FROM MSBTS_GroupSetting";
|
||||||
private readonly MonitoringOptions _options;
|
private readonly MonitoringOptions _options;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -53,9 +56,14 @@ namespace BizTalkCheckmkPulse
|
|||||||
|
|
||||||
result.Platform.WmiConnected = true;
|
result.Platform.WmiConnected = true;
|
||||||
result.Platform.PlatformDataAvailable = QueryPlatform(scope, result);
|
result.Platform.PlatformDataAvailable = QueryPlatform(scope, result);
|
||||||
result.Platform.HostInstancesDataAvailable = QueryHostInstances(scope, result);
|
result.Platform.HostInstancesDataAvailable = QueryHostInstances(scope, result, server);
|
||||||
var applicationIndex = BuildApplicationIndex(scope, result);
|
var applicationIndex = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
result.Platform.RuntimeArtifactsDataAvailable = QueryApplicationRuntime(scope, result);
|
result.Platform.RuntimeArtifactsDataAvailable = QueryApplicationRuntime(scope, result, applicationIndex);
|
||||||
|
if (_options.EmitPerApplicationSuspensionServices)
|
||||||
|
{
|
||||||
|
AddArtifactIndex(scope, result, applicationIndex, "MSBTS_ReceivePort");
|
||||||
|
}
|
||||||
|
|
||||||
result.Platform.SuspendedInstancesDataAvailable = QuerySuspendedInstances(scope, result, applicationIndex);
|
result.Platform.SuspendedInstancesDataAvailable = QuerySuspendedInstances(scope, result, applicationIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +82,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
}
|
}
|
||||||
catch (Exception ex) when (IsExpectedWmiException(ex))
|
catch (Exception ex) when (IsExpectedWmiException(ex))
|
||||||
{
|
{
|
||||||
AddWmiDiagnostic(result, "WMI namespace connection", ex, true, true);
|
AddWmiDiagnostic(result, "WMI namespace connection", ex, true, true, null, null);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,23 +96,19 @@ namespace BizTalkCheckmkPulse
|
|||||||
private bool QueryPlatform(ManagementScope scope, ProbeResult result)
|
private bool QueryPlatform(ManagementScope scope, ProbeResult result)
|
||||||
{
|
{
|
||||||
var groupFound = false;
|
var groupFound = false;
|
||||||
var groupAvailable = TryQuery(scope, result, "MSBTS_GroupSetting", "SELECT * FROM MSBTS_GroupSetting", item =>
|
var groupAvailable = TryQuery(scope, result, "MSBTS_GroupSetting", GroupSettingQuery, item =>
|
||||||
{
|
{
|
||||||
|
if (groupFound)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
groupFound = true;
|
groupFound = true;
|
||||||
result.Platform.GroupName = FirstNonEmpty(WmiHelpers.GetString(item, "Name"), WmiHelpers.GetString(item, "MgmtDbName"));
|
result.Platform.GroupName = FirstNonEmpty(WmiHelpers.GetString(item, "Name"), WmiHelpers.GetString(item, "MgmtDbName"));
|
||||||
result.Platform.ManagementDbServer = FirstNonEmpty(WmiHelpers.GetString(item, "MgmtDbServerName"), WmiHelpers.GetString(item, "DBServerName"));
|
result.Platform.ManagementDbServer = WmiHelpers.GetString(item, "MgmtDbServerName");
|
||||||
result.Platform.ManagementDbName = FirstNonEmpty(WmiHelpers.GetString(item, "MgmtDbName"), WmiHelpers.GetString(item, "DatabaseName"));
|
result.Platform.ManagementDbName = WmiHelpers.GetString(item, "MgmtDbName");
|
||||||
}, true);
|
result.Platform.MessageBoxDbServer = WmiHelpers.GetString(item, "SubscriptionDBServerName");
|
||||||
|
result.Platform.MessageBoxDbName = WmiHelpers.GetString(item, "SubscriptionDBName");
|
||||||
var messageBoxFound = false;
|
|
||||||
var messageBoxAvailable = TryQuery(scope, result, "MSBTS_MessageBoxSetting", "SELECT * FROM MSBTS_MessageBoxSetting", item =>
|
|
||||||
{
|
|
||||||
messageBoxFound = true;
|
|
||||||
if (string.IsNullOrWhiteSpace(result.Platform.MessageBoxDbServer))
|
|
||||||
{
|
|
||||||
result.Platform.MessageBoxDbServer = FirstNonEmpty(WmiHelpers.GetString(item, "DBServerName"), WmiHelpers.GetString(item, "ServerName"));
|
|
||||||
result.Platform.MessageBoxDbName = FirstNonEmpty(WmiHelpers.GetString(item, "DBName"), WmiHelpers.GetString(item, "DatabaseName"));
|
|
||||||
}
|
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
if (groupAvailable && !groupFound)
|
if (groupAvailable && !groupFound)
|
||||||
@@ -112,32 +116,33 @@ namespace BizTalkCheckmkPulse
|
|||||||
AddMissingDataDiagnostic(result, "MSBTS_GroupSetting", "Keine BizTalk-Gruppe gefunden.");
|
AddMissingDataDiagnostic(result, "MSBTS_GroupSetting", "Keine BizTalk-Gruppe gefunden.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageBoxAvailable && !messageBoxFound)
|
var managementTargetComplete = HasDatabaseTarget(
|
||||||
|
result.Platform.ManagementDbServer,
|
||||||
|
result.Platform.ManagementDbName);
|
||||||
|
if (groupAvailable && groupFound && !managementTargetComplete)
|
||||||
{
|
{
|
||||||
AddMissingDataDiagnostic(result, "MSBTS_MessageBoxSetting", "Keine BizTalk-MessageBox-Datenbank gefunden.");
|
AddMissingDataDiagnostic(
|
||||||
|
result,
|
||||||
|
"MSBTS_GroupSetting.ManagementDatabase",
|
||||||
|
"BizTalk Management-Datenbankziel ist in MSBTS_GroupSetting unvollstaendig.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupAvailable && groupFound && messageBoxAvailable && messageBoxFound;
|
var messageBoxTargetComplete = HasDatabaseTarget(
|
||||||
|
result.Platform.MessageBoxDbServer,
|
||||||
|
result.Platform.MessageBoxDbName);
|
||||||
|
if (groupAvailable && groupFound && !messageBoxTargetComplete)
|
||||||
|
{
|
||||||
|
AddMissingDataDiagnostic(
|
||||||
|
result,
|
||||||
|
"MSBTS_GroupSetting.SubscriptionDatabase",
|
||||||
|
"Master-MessageBox-Datenbankziel ist in MSBTS_GroupSetting unvollstaendig.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupAvailable && groupFound && managementTargetComplete && messageBoxTargetComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Erstellt einen Index, um suspendierte Instanzen BizTalk-Anwendungen zuzuordnen.
|
/// Fuegt die Schluessel einer optionalen WMI-Artefaktklasse zum Anwendungsindex hinzu.
|
||||||
/// </summary>
|
|
||||||
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
|
||||||
/// <param name="result">Ergebnisobjekt fuer optionale Diagnosen.</param>
|
|
||||||
/// <returns>Index aus moeglichen Artefaktschluesseln und Anwendungsnamen.</returns>
|
|
||||||
private Dictionary<string, string> BuildApplicationIndex(ManagementScope scope, ProbeResult result)
|
|
||||||
{
|
|
||||||
var index = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
AddArtifactIndex(scope, result, index, "MSBTS_SendPort");
|
|
||||||
AddArtifactIndex(scope, result, index, "MSBTS_ReceivePort");
|
|
||||||
AddArtifactIndex(scope, result, index, "MSBTS_ReceiveLocation");
|
|
||||||
AddArtifactIndex(scope, result, index, "MSBTS_Orchestration");
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fuegt die Schluessel einer WMI-Artefaktklasse zum Anwendungsindex hinzu.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
||||||
/// <param name="result">Ergebnisobjekt fuer optionale Diagnosen.</param>
|
/// <param name="result">Ergebnisobjekt fuer optionale Diagnosen.</param>
|
||||||
@@ -147,14 +152,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
{
|
{
|
||||||
TryQuery(scope, result, className + " application index", "SELECT * FROM " + className, item =>
|
TryQuery(scope, result, className + " application index", "SELECT * FROM " + className, item =>
|
||||||
{
|
{
|
||||||
var app = GetApplicationName(item);
|
AddArtifactIndexEntry(index, item);
|
||||||
foreach (var key in CandidateKeys(item))
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(key) && !index.ContainsKey(key))
|
|
||||||
{
|
|
||||||
index.Add(key, app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,16 +161,28 @@ namespace BizTalkCheckmkPulse
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
||||||
/// <param name="result">Zu aktualisierendes Ergebnisobjekt.</param>
|
/// <param name="result">Zu aktualisierendes Ergebnisobjekt.</param>
|
||||||
|
/// <param name="server">BizTalk-Server, dessen Host Instances bewertet werden.</param>
|
||||||
/// <returns><c>true</c>, wenn die Pflichtabfrage erfolgreich war.</returns>
|
/// <returns><c>true</c>, wenn die Pflichtabfrage erfolgreich war.</returns>
|
||||||
private bool QueryHostInstances(ManagementScope scope, ProbeResult result)
|
private bool QueryHostInstances(ManagementScope scope, ProbeResult result, string server)
|
||||||
{
|
{
|
||||||
return TryQuery(scope, result, "MSBTS_HostInstance", "SELECT * FROM MSBTS_HostInstance", item =>
|
return TryQuery(
|
||||||
|
scope,
|
||||||
|
result,
|
||||||
|
"MSBTS_HostInstance",
|
||||||
|
"SELECT Name, HostName, RunningServer, ServiceState FROM MSBTS_HostInstance",
|
||||||
|
item =>
|
||||||
{
|
{
|
||||||
|
var runningServer = WmiHelpers.GetString(item, "RunningServer");
|
||||||
|
if (!string.IsNullOrWhiteSpace(runningServer) && !IsSameServer(runningServer, server))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
result.HostInstances.Add(new HostInstanceState
|
result.HostInstances.Add(new HostInstanceState
|
||||||
{
|
{
|
||||||
InstanceName = FirstNonEmpty(WmiHelpers.GetString(item, "InstanceName"), WmiHelpers.GetString(item, "Name")),
|
InstanceName = FirstNonEmpty(WmiHelpers.GetString(item, "InstanceName"), WmiHelpers.GetString(item, "Name")),
|
||||||
HostName = WmiHelpers.GetString(item, "HostName"),
|
HostName = WmiHelpers.GetString(item, "HostName"),
|
||||||
RunningServer = WmiHelpers.GetString(item, "RunningServer"),
|
RunningServer = runningServer,
|
||||||
ServiceState = WmiHelpers.GetInt32(item, "ServiceState", 0)
|
ServiceState = WmiHelpers.GetInt32(item, "ServiceState", 0)
|
||||||
});
|
});
|
||||||
}, true);
|
}, true);
|
||||||
@@ -183,13 +193,18 @@ namespace BizTalkCheckmkPulse
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
/// <param name="scope">Verbundener BizTalk-WMI-Scope.</param>
|
||||||
/// <param name="result">Zu aktualisierendes Ergebnisobjekt.</param>
|
/// <param name="result">Zu aktualisierendes Ergebnisobjekt.</param>
|
||||||
|
/// <param name="applicationIndex">Best-Effort-Index fuer Suspensionsdetails.</param>
|
||||||
/// <returns><c>true</c>, wenn alle drei Pflichtabfragen erfolgreich waren.</returns>
|
/// <returns><c>true</c>, wenn alle drei Pflichtabfragen erfolgreich waren.</returns>
|
||||||
private bool QueryApplicationRuntime(ManagementScope scope, ProbeResult result)
|
private bool QueryApplicationRuntime(
|
||||||
|
ManagementScope scope,
|
||||||
|
ProbeResult result,
|
||||||
|
Dictionary<string, string> applicationIndex)
|
||||||
{
|
{
|
||||||
var apps = new Dictionary<string, ApplicationRuntimeState>(StringComparer.OrdinalIgnoreCase);
|
var apps = new Dictionary<string, ApplicationRuntimeState>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var receiveLocationsAvailable = TryQuery(scope, result, "MSBTS_ReceiveLocation", "SELECT * FROM MSBTS_ReceiveLocation", item =>
|
var receiveLocationsAvailable = TryQuery(scope, result, "MSBTS_ReceiveLocation", "SELECT * FROM MSBTS_ReceiveLocation", item =>
|
||||||
{
|
{
|
||||||
|
AddArtifactIndexEntry(applicationIndex, item);
|
||||||
var app = GetApplication(apps, GetApplicationName(item));
|
var app = GetApplication(apps, GetApplicationName(item));
|
||||||
app.ReceiveLocationTotal++;
|
app.ReceiveLocationTotal++;
|
||||||
if (WmiHelpers.GetBoolean(item, "IsDisabled", false))
|
if (WmiHelpers.GetBoolean(item, "IsDisabled", false))
|
||||||
@@ -200,6 +215,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
|
|
||||||
var sendPortsAvailable = TryQuery(scope, result, "MSBTS_SendPort", "SELECT * FROM MSBTS_SendPort", item =>
|
var sendPortsAvailable = TryQuery(scope, result, "MSBTS_SendPort", "SELECT * FROM MSBTS_SendPort", item =>
|
||||||
{
|
{
|
||||||
|
AddArtifactIndexEntry(applicationIndex, item);
|
||||||
var app = GetApplication(apps, GetApplicationName(item));
|
var app = GetApplication(apps, GetApplicationName(item));
|
||||||
app.SendPortTotal++;
|
app.SendPortTotal++;
|
||||||
switch (WmiHelpers.GetInt32(item, "Status", 0))
|
switch (WmiHelpers.GetInt32(item, "Status", 0))
|
||||||
@@ -221,6 +237,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
|
|
||||||
var orchestrationsAvailable = TryQuery(scope, result, "MSBTS_Orchestration", "SELECT * FROM MSBTS_Orchestration", item =>
|
var orchestrationsAvailable = TryQuery(scope, result, "MSBTS_Orchestration", "SELECT * FROM MSBTS_Orchestration", item =>
|
||||||
{
|
{
|
||||||
|
AddArtifactIndexEntry(applicationIndex, item);
|
||||||
var app = GetApplication(apps, GetApplicationName(item));
|
var app = GetApplication(apps, GetApplicationName(item));
|
||||||
app.OrchestrationTotal++;
|
app.OrchestrationTotal++;
|
||||||
switch (WmiHelpers.GetInt32(item, "OrchestrationStatus", 0))
|
switch (WmiHelpers.GetInt32(item, "OrchestrationStatus", 0))
|
||||||
@@ -285,6 +302,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
/// <returns><c>true</c>, wenn die Abfrage vollstaendig ausgefuehrt wurde.</returns>
|
/// <returns><c>true</c>, wenn die Abfrage vollstaendig ausgefuehrt wurde.</returns>
|
||||||
private bool TryQuery(ManagementScope scope, ProbeResult result, string label, string queryText, Action<ManagementObject> action, bool required)
|
private bool TryQuery(ManagementScope scope, ProbeResult result, string label, string queryText, Action<ManagementObject> action, bool required)
|
||||||
{
|
{
|
||||||
|
var stopwatch = Stopwatch.StartNew();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ForEachObject(scope, queryText, action);
|
ForEachObject(scope, queryText, action);
|
||||||
@@ -292,7 +310,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
}
|
}
|
||||||
catch (Exception ex) when (IsExpectedWmiException(ex))
|
catch (Exception ex) when (IsExpectedWmiException(ex))
|
||||||
{
|
{
|
||||||
AddWmiDiagnostic(result, label, ex, required, false);
|
AddWmiDiagnostic(result, label, ex, required, false, queryText, stopwatch.Elapsed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,6 +362,28 @@ namespace BizTalkCheckmkPulse
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nimmt nur tatsaechlich vorhandene Anwendungszuordnungen in den Best-Effort-Index auf.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Zu erweiternder Index.</param>
|
||||||
|
/// <param name="item">BizTalk-Artefakt aus WMI.</param>
|
||||||
|
private static void AddArtifactIndexEntry(Dictionary<string, string> index, ManagementBaseObject item)
|
||||||
|
{
|
||||||
|
var app = GetApplicationName(item);
|
||||||
|
if (string.Equals(app, UnknownApplication, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in CandidateKeys(item))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(key) && !index.ContainsKey(key))
|
||||||
|
{
|
||||||
|
index.Add(key, app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ermittelt den Anwendungsnamen direkt oder ueber den Artefaktindex.
|
/// Ermittelt den Anwendungsnamen direkt oder ueber den Artefaktindex.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -406,6 +446,32 @@ namespace BizTalkCheckmkPulse
|
|||||||
return values == null ? null : values.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x));
|
return values == null ? null : values.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prueft, ob Server und Datenbank eines SQL-Ziels vorhanden sind.
|
||||||
|
/// </summary>
|
||||||
|
private static bool HasDatabaseTarget(string server, string database)
|
||||||
|
{
|
||||||
|
return !string.IsNullOrWhiteSpace(server) && !string.IsNullOrWhiteSpace(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vergleicht kurzen Namen und FQDN eines BizTalk-Servers ohne WQL-Namensfilter.
|
||||||
|
/// </summary>
|
||||||
|
internal static bool IsSameServer(string left, string right)
|
||||||
|
{
|
||||||
|
return string.Equals(
|
||||||
|
NormalizeServerName(left),
|
||||||
|
NormalizeServerName(right),
|
||||||
|
StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeServerName(string value)
|
||||||
|
{
|
||||||
|
var normalized = (value ?? string.Empty).Trim().TrimStart('\\');
|
||||||
|
var dotIndex = normalized.IndexOf('.');
|
||||||
|
return dotIndex > 0 ? normalized.Substring(0, dotIndex) : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prueft, ob eine Exception aus dem erwarteten WMI-/COM-Fehlerbereich stammt.
|
/// Prueft, ob eine Exception aus dem erwarteten WMI-/COM-Fehlerbereich stammt.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -426,9 +492,29 @@ namespace BizTalkCheckmkPulse
|
|||||||
/// <param name="exception">Ausgeloeste Exception.</param>
|
/// <param name="exception">Ausgeloeste Exception.</param>
|
||||||
/// <param name="required">Kennzeichen fuer eine Pflichtabfrage.</param>
|
/// <param name="required">Kennzeichen fuer eine Pflichtabfrage.</param>
|
||||||
/// <param name="connectionFailure">Kennzeichen fuer Fehler beim Namespace-Verbindungsaufbau.</param>
|
/// <param name="connectionFailure">Kennzeichen fuer Fehler beim Namespace-Verbindungsaufbau.</param>
|
||||||
private static void AddWmiDiagnostic(ProbeResult result, string component, Exception exception, bool required, bool connectionFailure)
|
private static void AddWmiDiagnostic(
|
||||||
|
ProbeResult result,
|
||||||
|
string component,
|
||||||
|
Exception exception,
|
||||||
|
bool required,
|
||||||
|
bool connectionFailure,
|
||||||
|
string queryText,
|
||||||
|
TimeSpan? duration)
|
||||||
{
|
{
|
||||||
var category = ClassifyWmiException(exception);
|
var category = ClassifyWmiException(exception);
|
||||||
|
var technicalDetails = exception.GetType().Name
|
||||||
|
+ " HRESULT=0x" + exception.HResult.ToString("X8")
|
||||||
|
+ ": " + exception.Message;
|
||||||
|
if (!string.IsNullOrWhiteSpace(queryText))
|
||||||
|
{
|
||||||
|
technicalDetails += " WQL={" + queryText + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duration.HasValue)
|
||||||
|
{
|
||||||
|
technicalDetails += " DurationMs=" + Math.Round(duration.Value.TotalMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
result.Diagnostics.Add(new ProbeDiagnostic
|
result.Diagnostics.Add(new ProbeDiagnostic
|
||||||
{
|
{
|
||||||
Area = DiagnosticArea.Wmi,
|
Area = DiagnosticArea.Wmi,
|
||||||
@@ -437,7 +523,7 @@ namespace BizTalkCheckmkPulse
|
|||||||
Required = required,
|
Required = required,
|
||||||
Summary = BuildWmiSummary(category, component, connectionFailure),
|
Summary = BuildWmiSummary(category, component, connectionFailure),
|
||||||
Action = BuildWmiAction(category, connectionFailure),
|
Action = BuildWmiAction(category, connectionFailure),
|
||||||
TechnicalDetails = exception.GetType().Name + " HRESULT=0x" + exception.HResult.ToString("X8") + ": " + exception.Message
|
TechnicalDetails = technicalDetails
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,12 +563,25 @@ namespace BizTalkCheckmkPulse
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (managementException != null
|
if (managementException != null
|
||||||
&& (managementException.ErrorCode == ManagementStatus.InvalidNamespace
|
&& managementException.ErrorCode == ManagementStatus.InvalidNamespace)
|
||||||
|| managementException.ErrorCode == ManagementStatus.InvalidClass))
|
|
||||||
{
|
{
|
||||||
return DiagnosticCategory.Configuration;
|
return DiagnosticCategory.Configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (managementException != null
|
||||||
|
&& (managementException.ErrorCode == ManagementStatus.InvalidClass
|
||||||
|
|| managementException.ErrorCode == ManagementStatus.InvalidProperty
|
||||||
|
|| managementException.ErrorCode == ManagementStatus.InvalidQuery
|
||||||
|
|| managementException.ErrorCode == ManagementStatus.UnparsableQuery))
|
||||||
|
{
|
||||||
|
return DiagnosticCategory.Schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (managementException != null && managementException.ErrorCode == ManagementStatus.Timedout)
|
||||||
|
{
|
||||||
|
return DiagnosticCategory.Timeout;
|
||||||
|
}
|
||||||
|
|
||||||
var message = exception.Message ?? string.Empty;
|
var message = exception.Message ?? string.Empty;
|
||||||
if (ContainsAny(message, "timed out", "timeout", "Zeitlimit"))
|
if (ContainsAny(message, "timed out", "timeout", "Zeitlimit"))
|
||||||
{
|
{
|
||||||
@@ -513,7 +612,9 @@ namespace BizTalkCheckmkPulse
|
|||||||
case DiagnosticCategory.Configuration:
|
case DiagnosticCategory.Configuration:
|
||||||
return connectionFailure
|
return connectionFailure
|
||||||
? "BizTalk-WMI-Namespace ist nicht vorhanden oder nicht korrekt registriert."
|
? "BizTalk-WMI-Namespace ist nicht vorhanden oder nicht korrekt registriert."
|
||||||
: "BizTalk-WMI-Klasse " + component + " ist nicht vorhanden oder nicht korrekt registriert.";
|
: "BizTalk-WMI-Konfiguration fuer " + component + " ist unvollstaendig.";
|
||||||
|
case DiagnosticCategory.Schema:
|
||||||
|
return "WMI-Klasse oder WQL fuer " + component + " wird vom installierten BizTalk-Provider nicht unterstuetzt.";
|
||||||
case DiagnosticCategory.Timeout:
|
case DiagnosticCategory.Timeout:
|
||||||
return "WMI-Abfrage fuer " + component + " hat das konfigurierte Zeitlimit ueberschritten.";
|
return "WMI-Abfrage fuer " + component + " hat das konfigurierte Zeitlimit ueberschritten.";
|
||||||
case DiagnosticCategory.Connectivity:
|
case DiagnosticCategory.Connectivity:
|
||||||
@@ -539,6 +640,8 @@ namespace BizTalkCheckmkPulse
|
|||||||
: "Agent-Dump pruefen und Computerkonto <DOMAIN>\\" + Environment.MachineName + "$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen.";
|
: "Agent-Dump pruefen und Computerkonto <DOMAIN>\\" + Environment.MachineName + "$ zunaechst der konfigurierten BizTalk-Operator-Gruppe zuordnen.";
|
||||||
case DiagnosticCategory.Configuration:
|
case DiagnosticCategory.Configuration:
|
||||||
return "BizTalk-WMI-Provider/Namespace auf dem BizTalk-Server pruefen und gegebenenfalls mit dem BizTalk-Setup reparieren.";
|
return "BizTalk-WMI-Provider/Namespace auf dem BizTalk-Server pruefen und gegebenenfalls mit dem BizTalk-Setup reparieren.";
|
||||||
|
case DiagnosticCategory.Schema:
|
||||||
|
return "Klassen- und Property-Namen gegen das installierte BizTalk-WMI-Schema und die Microsoft-Dokumentation pruefen. Rechteerhoehung behebt InvalidClass/InvalidQuery nicht.";
|
||||||
case DiagnosticCategory.Timeout:
|
case DiagnosticCategory.Timeout:
|
||||||
return "WMI-Dienst, BizTalk-/SQL-Auslastung und Event Logs pruefen; Timeout erst danach erhoehen.";
|
return "WMI-Dienst, BizTalk-/SQL-Auslastung und Event Logs pruefen; Timeout erst danach erhoehen.";
|
||||||
case DiagnosticCategory.Connectivity:
|
case DiagnosticCategory.Connectivity:
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="false" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>BizTalkCheckmkPulse.Tests</RootNamespace>
|
||||||
|
<AssemblyName>BizTalkCheckmkPulse.Tests</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\BizTalkCheckmkPulse\BizTalkCheckmkPulse.csproj">
|
||||||
|
<Project>{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}</Project>
|
||||||
|
<Name>BizTalkCheckmkPulse</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace BizTalkCheckmkPulse.Tests
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
private static readonly List<string> Failures = new List<string>();
|
||||||
|
|
||||||
|
private static int Main()
|
||||||
|
{
|
||||||
|
Run("SelfTestEmitsAllStableServices", SelfTestEmitsAllStableServices);
|
||||||
|
Run("UnavailableSourcesAreUnknown", UnavailableSourcesAreUnknown);
|
||||||
|
Run("UnknownApplicationDoesNotCreateService", UnknownApplicationDoesNotCreateService);
|
||||||
|
Run("KnownApplicationCreatesService", KnownApplicationCreatesService);
|
||||||
|
Run("ServerNamesAreComparedWithoutWql", ServerNamesAreComparedWithoutWql);
|
||||||
|
Run("GroupSettingQueryUsesDocumentedSchema", GroupSettingQueryUsesDocumentedSchema);
|
||||||
|
|
||||||
|
if (Failures.Count == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("PASS: 6 tests");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var failure in Failures)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("FAIL: " + failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SelfTestEmitsAllStableServices()
|
||||||
|
{
|
||||||
|
var lines = new CheckmkLocalFormatter(new MonitoringOptions()).FormatSelfTest().ToArray();
|
||||||
|
AssertEqual(6, lines.Length, "self-test line count");
|
||||||
|
AssertEqual(6, lines.Distinct(StringComparer.Ordinal).Count(), "unique self-test lines");
|
||||||
|
Assert(lines.All(x => x.StartsWith("0 \"BizTalk ", StringComparison.Ordinal)), "every self-test line must be OK");
|
||||||
|
Assert(lines.Any(x => x.Contains("\"BizTalk Event Log\"")), "Event Log service missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UnavailableSourcesAreUnknown()
|
||||||
|
{
|
||||||
|
var lines = new CheckmkLocalFormatter(new MonitoringOptions()).Format(new ProbeResult()).Take(6).ToArray();
|
||||||
|
AssertEqual(6, lines.Length, "stable service count");
|
||||||
|
Assert(lines.All(x => x.StartsWith("3 \"BizTalk ", StringComparison.Ordinal)), "unavailable sources must be UNKNOWN");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UnknownApplicationDoesNotCreateService()
|
||||||
|
{
|
||||||
|
var options = new MonitoringOptions { EmitPerApplicationSuspensionServices = true };
|
||||||
|
var result = CreateSuspensionResult("(unknown)");
|
||||||
|
var lines = new CheckmkLocalFormatter(options).Format(result).ToArray();
|
||||||
|
AssertEqual(6, lines.Length, "unknown application must not create a dynamic service");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void KnownApplicationCreatesService()
|
||||||
|
{
|
||||||
|
var options = new MonitoringOptions { EmitPerApplicationSuspensionServices = true };
|
||||||
|
var result = CreateSuspensionResult("Orders");
|
||||||
|
var lines = new CheckmkLocalFormatter(options).Format(result).ToArray();
|
||||||
|
AssertEqual(7, lines.Length, "known application should create one dynamic service");
|
||||||
|
Assert(lines.Any(x => x.Contains("\"BizTalk Suspended Orders\"")), "known application service missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ServerNamesAreComparedWithoutWql()
|
||||||
|
{
|
||||||
|
Assert(WmiBizTalkProbe.IsSameServer("BIZTALK01.corp.example", "biztalk01"), "FQDN and short name must match");
|
||||||
|
Assert(WmiBizTalkProbe.IsSameServer(@"\\BIZ-TALK+01", "biz-talk+01.example"), "special characters must be compared client-side");
|
||||||
|
Assert(!WmiBizTalkProbe.IsSameServer("BIZTALK01", "BIZTALK02"), "different servers must not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GroupSettingQueryUsesDocumentedSchema()
|
||||||
|
{
|
||||||
|
var query = WmiBizTalkProbe.GroupSettingQuery;
|
||||||
|
Assert(query.Contains("FROM MSBTS_GroupSetting"), "MSBTS_GroupSetting query missing");
|
||||||
|
Assert(query.Contains("SubscriptionDBServerName"), "master MessageBox server property missing");
|
||||||
|
Assert(query.Contains("SubscriptionDBName"), "master MessageBox database property missing");
|
||||||
|
Assert(query.IndexOf("MessageBoxSetting", StringComparison.OrdinalIgnoreCase) < 0, "unsupported MessageBoxSetting class present");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProbeResult CreateSuspensionResult(string applicationName)
|
||||||
|
{
|
||||||
|
var result = new ProbeResult();
|
||||||
|
result.Platform.SuspendedInstancesDataAvailable = true;
|
||||||
|
result.SuspendedInstances.Add(new SuspendedInstance
|
||||||
|
{
|
||||||
|
ApplicationName = applicationName,
|
||||||
|
ServiceName = "TestService",
|
||||||
|
Kind = SuspendedKind.Resumable
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Run(string name, Action test)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Failures.Add(name + ": " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Assert(bool condition, string message)
|
||||||
|
{
|
||||||
|
if (!condition)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertEqual(int expected, int actual, string label)
|
||||||
|
{
|
||||||
|
if (expected != actual)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(label + ": expected " + expected + ", actual " + actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user