mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-21 15:19:58 -05:00
The former implementation had 5 threads permanently spinning fast (10ms sleep) while waiting for a REST connection to process. This causes higher load in general and it breaks systems where "Turn on PowerShell Script Block Logging policy" is enabled, because then each PS statement including Start-Sleep is logged - resulting in 500 event log entries per second. It's a suggested setting in some hardening guidelines. We can easily replace the Queue with a BlockingCollection backed by a ConcurrentQueue, which has the built-in feature to sleep until there are new items. Now the REST API threads consumes zero CPU time while waiting.
116 lines
4.4 KiB
PowerShell
116 lines
4.4 KiB
PowerShell
function New-IcingaForWindowsRESTApi()
|
|
{
|
|
# Allow us to parse the framework global data to this thread
|
|
param (
|
|
[string]$Address = '',
|
|
$Port,
|
|
$CertFile,
|
|
$CertThumbprint,
|
|
$RequireAuth
|
|
);
|
|
|
|
$RESTEndpoints = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaRESTAPIEndpoint*';
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Loading configuration for REST-Endpoints{0}{1}',
|
|
(New-IcingaNewLine),
|
|
($RESTEndpoints | Out-String)
|
|
)
|
|
);
|
|
|
|
Write-IcingaDebugMessage -Message ($Global:Icinga.Public.Daemons.RESTApi | Out-String);
|
|
|
|
foreach ($entry in $RESTEndpoints.Values) {
|
|
[bool]$Success = Add-IcingaHashtableItem `
|
|
-Hashtable $Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints `
|
|
-Key $entry.Alias `
|
|
-Value $entry.Command;
|
|
|
|
if ($Success -eq $FALSE) {
|
|
Write-IcingaEventMessage `
|
|
-EventId 2100 `
|
|
-Namespace 'RESTApi' `
|
|
-Objects ([string]::Format('Adding duplicated REST endpoint "{0}" with command "{1}', $entry.Alias, $entry.Command)), $RESTEndpoints;
|
|
}
|
|
}
|
|
|
|
$CommandAliases = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaRESTApiCommandAliases*';
|
|
|
|
foreach ($entry in $CommandAliases.Values) {
|
|
foreach ($component in $entry.Keys) {
|
|
[bool]$Success = Add-IcingaHashtableItem `
|
|
-Hashtable $Global:Icinga.Public.Daemons.RESTApi.CommandAliases `
|
|
-Key $component `
|
|
-Value $entry[$component];
|
|
|
|
if ($Success -eq $FALSE) {
|
|
Write-IcingaEventMessage `
|
|
-EventId 2101 `
|
|
-Namespace 'RESTApi' `
|
|
-Objects ([string]::Format('Adding duplicated REST command aliases "{0}" for namespace "{1}', $entry[$component], $component)), $CommandAliases;
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-IcingaDebugMessage -Message ($Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints | Out-String);
|
|
|
|
if ($Global:Icinga.Protected.JEAContext) {
|
|
if ($Global:Icinga.Public.ContainsKey('SSLCertificate') -eq $FALSE -Or $null -eq $Global:Icinga.Public.SSLCertificate) {
|
|
Write-IcingaEventMessage -EventId 2001 -Namespace 'RESTApi';
|
|
return;
|
|
}
|
|
|
|
$Certificate = $Global:Icinga.Public.SSLCertificate;
|
|
} else {
|
|
$Certificate = Get-IcingaSSLCertForSocket -CertFile $CertFile -CertThumbprint $CertThumbprint;
|
|
}
|
|
|
|
if ($null -eq $Certificate) {
|
|
Write-IcingaEventMessage -EventId 2000 -Namespace 'RESTApi';
|
|
return;
|
|
}
|
|
|
|
$Socket = New-IcingaTCPSocket -Address $Address -Port $Port -Start;
|
|
|
|
# Keep our code executed as long as the PowerShell service is
|
|
# being executed. This is required to ensure we will execute
|
|
# the code frequently instead of only once
|
|
while ($TRUE) {
|
|
|
|
# Force Icinga for Windows Garbage Collection
|
|
Optimize-IcingaForWindowsMemory -ClearErrorStack;
|
|
|
|
$Connection = Open-IcingaTCPClientConnection `
|
|
-Client (New-IcingaTCPClient -Socket $Socket) `
|
|
-Certificate $Certificate;
|
|
|
|
if (Test-IcingaRESTClientBlacklisted -Client $Connection.Client -ClientList $Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist) {
|
|
Write-IcingaDebugMessage -Message 'A remote client which is trying to connect was blacklisted' -Objects $Connection.Client.Client;
|
|
Close-IcingaTCPConnection -Client $Connection.Client;
|
|
continue;
|
|
}
|
|
|
|
if ((Test-IcingaRESTClientConnection -Connection $Connection) -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
# API not yet ready
|
|
if ($Global:Icinga.Public.Daemons.RESTApi.ApiRequests.Count -eq 0) {
|
|
Close-IcingaTCPConnection -Client $Connection.Client;
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$NextRESTApiThreadId = (Get-IcingaNextRESTApiThreadId);
|
|
|
|
if ($Global:Icinga.Public.Daemons.RESTApi.ApiRequests.ContainsKey($NextRESTApiThreadId) -eq $FALSE) {
|
|
Close-IcingaTCPConnection -Client $Connection.Client;
|
|
continue;
|
|
}
|
|
|
|
$Global:Icinga.Public.Daemons.RESTApi.ApiRequests.$NextRESTApiThreadId.Add($Connection);
|
|
} catch {
|
|
Write-IcingaEventMessage -Namespace 'RESTApi' -EvenId 2050 -ExceptionObject $_;
|
|
}
|
|
}
|
|
}
|