Skip to content

Commit

Permalink
Reworks handling on how plugin thresholds are interpreted
Browse files Browse the repository at this point in the history
  • Loading branch information
LordHepipud committed Aug 29, 2024
1 parent 5bbba96 commit 295fa00
Show file tree
Hide file tree
Showing 16 changed files with 789 additions and 670 deletions.
7 changes: 6 additions & 1 deletion doc/100-General/10-Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ documentation before upgrading to a new release.

Released closed milestones can be found on [GitHub](https://github.com/Icinga/icinga-powershell-framework/milestones?state=closed).

## 1.13.0 (tbd)
## 1.13.0 Beta-1 (2024-08-30)

[Issues and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/32)

### Notes

This beta release has reworked the entire handling on how thresholds and the checker core operate. For that reason, the `Beta-1` release will **not** include the `Metrics over Time` feature. The goal of this beta is to get an idea if the threshold handling is working as expected and evaluate the performance gains for the new check handling. The `Metrics over Time` feature will be re-implemented with an entire new background task and configurations in `Beta-2`.

### Bugfixes

* [#729](https://github.com/Icinga/icinga-powershell-framework/issues/729) Fixes `Update-Icinga` to print an error in case a component is not installed, instead of silently continue
Expand All @@ -27,6 +31,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
* [#739](https://github.com/Icinga/icinga-powershell-framework/pull/739) Adds support to check the encoding of files to ensure we can properly load them and throw errors for unsupported encoding
* [#740](https://github.com/Icinga/icinga-powershell-framework/pull/740) Adds new command `Invoke-IcingaForWindowsRESTApi` for easier API communication
* [#742](https://github.com/Icinga/icinga-powershell-framework/pull/742) Adds support for the CPU provider to limit the CPU usage to 100% for each thread
* [#750](https://github.com/Icinga/icinga-powershell-framework/pull/750) Reworks the internal handling on how plugin thresholds are evaluated and the internal checker core, including on how performance metrics are generated

## 1.12.3 (2024-04-24)

Expand Down
10 changes: 7 additions & 3 deletions lib/core/framework/Get-IcingaCheckSchedulerPerfData.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@
Returns the last performance data output for executed plugins while the
Framework is running as daemon
.OUTPUTS
System.Object
System.String
.LINK
https://github.com/Icinga/icinga-powershell-framework
#>

function Get-IcingaCheckSchedulerPerfData()
{
$PerfData = $Global:Icinga.Private.Scheduler.PerformanceData;
[array]$Global:Icinga.Private.Scheduler.PerformanceData = @();
[string]$PerfData = $Global:Icinga.Private.Scheduler.PerformanceData;
[string]$Global:Icinga.Private.Scheduler.PerformanceData = '';

# Ensure we clear our PerfDataWriter cache and storage to have a clean base state for the next plugin execution
$Global:Icinga.Private.Scheduler.PerfDataWriter.Cache.Clear() | Out-Null;
$Global:Icinga.Private.Scheduler.PerfDataWriter.Storage.Clear() | Out-Null;

return $PerfData;
}
2 changes: 1 addition & 1 deletion lib/core/framework/Invoke-IcingaInternalServiceCall.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function Invoke-IcingaInternalServiceCall()
$IcingaCR = ($IcingaResult.$Command.checkresult.Replace("`r`n", "`n"));

if ($IcingaResult.$Command.perfdata.Count -ne 0) {
$IcingaCR = [string]::Format('{0}{1}| {2}', $IcingaCR, "`r`n", ([string]::Join(' ', $IcingaResult.$Command.perfdata)));
$IcingaCR = [string]::Format('{0}{1}| {2}', $IcingaCR, "`r`n", ([string]::Join('', $IcingaResult.$Command.perfdata)));
}

if ($NoExit) {
Expand Down
6 changes: 5 additions & 1 deletion lib/core/framework/New-IcingaEnvironmentVariable.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ function New-IcingaEnvironmentVariable()
'CheckData' = @{ };
'ThresholdCache' = @{ };
'CheckResults' = @();
'PerformanceData' = @();
'PerformanceData' = '';
'PluginException' = $null;
'ExitCode' = $null;
'PerfDataWriter' = @{
'Cache' = @{};
'Storage' = (New-Object System.Text.StringBuilder);
}
}
);

Expand Down
202 changes: 177 additions & 25 deletions lib/core/tools/Convert-IcingaPluginThresholds.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
to the lowest base of the unit. It does support the Icinga
plugin language, like ~:30, @10:40, 15:30, ...
You can also provide date time values in the format of "yyyy/MM/dd HH:mm:ss"
and use Icinga for Windows plugin thresholds in combination. You have to escape
the ':' inside the date time value with a '`' to ensure the correct conversion.
Example:
2024/08/19 12`:42`:00
The conversion does currently support the following units:
Size: B, KB, MB, GB, TB, PT, KiB, MiB, GiB, TiB, PiB
Expand All @@ -26,43 +33,90 @@
Name Value
---- -----
Value 1728000
EndRange
Unit s
StartRange
Threshold 1728000
Mode 0
Raw 20d
IsDateTime False
Value 1728000
.EXAMPLE
PS>Convert-IcingaPluginThresholds -Threshold '5GB';
Name Value
---- -----
Value 5000000000
EndRange
Unit B
StartRange
Threshold 5000000000
Mode 0
Raw 5GB
IsDateTime False
Value 5000000000
.EXAMPLE
PS>Convert-IcingaPluginThresholds -Threshold '10MB:20MB';
Name Value
---- -----
Value 10000000:20000000
EndRange 20000000
Unit B
StartRange 10000000
Threshold 10000000:20000000
Mode 3
Raw 10MB:20MB
IsDateTime False
Value
.EXAMPLE
PS>Convert-IcingaPluginThresholds -Threshold '10m:1h';
Name Value
---- -----
Value 600:3600
EndRange 3600
Unit s
StartRange 600
Threshold 600:3600
Mode 3
Raw 10m:1h
Value
.EXAMPLE
PS>Convert-IcingaPluginThresholds -Threshold '@10m:1h';
Name Value
---- -----
Value @600:3600
EndRange 3600
Unit s
StartRange 600
Threshold @600:3600
Mode 4
Raw @10m:1h
IsDateTime False
Value
.EXAMPLE
Convert-IcingaPluginThresholds -Threshold '~:1M';
PS>Convert-IcingaPluginThresholds -Threshold '~:1M';
Name Value
---- -----
Value ~:2592000
EndRange
Unit s
StartRange
Threshold ~:2592000
Mode 2
Raw ~:1M
IsDateTime False
Value 2592000
.EXAMPLE
PS>Convert-IcingaPluginThresholds -Threshold '@2024/08/19 12`:42`:00:2024/08/19 12`:42`:00';
Name Value
---- -----
EndRange 133685377200000000
Unit s
StartRange 133685377200000000
Threshold @133685377200000000:133685377200000000
Mode 4
Raw @2024/08/19 12`:42`:00:2024/08/19 12`:42`:00
IsDateTime True
Value
.INPUTS
System.String
.OUTPUTS
Expand All @@ -78,35 +132,80 @@ function Convert-IcingaPluginThresholds()
);

[hashtable]$RetValue = @{
'Unit' = '';
'Value' = $null;
'Raw' = $Threshold;
'Unit' = '';
'Threshold' = $null;
'Value' = $null;
'StartRange' = $null;
'EndRange' = $null;
'Mode' = $IcingaEnums.IcingaThresholdMethod.Default;
'IsDateTime' = $FALSE;
};

if ($null -eq $Threshold) {
if ([string]::IsNullOrEmpty($Threshold)) {
return $RetValue;
}

# Always ensure we are using correct digits
$Threshold = $Threshold.Replace(',', '.');

[array]$Content = @();
$Threshold = $Threshold.Replace(',', '.');
[array]$Content = @();

if ($Threshold.Contains(':')) {
# If we have more than one ':' inside our string, lets check if this is a date time value
# In case it is convert it properly to a FileTime we can work with later on
if ([Regex]::Matches($Threshold, ":").Count -gt 1) {
if ([Regex]::Matches($Threshold, '`:').Count -gt 1) {
[bool]$HasTilde = $FALSE;
[bool]$HasAt = $FALSE;

if ($Threshold.Contains('@')) {
$HasAt = $TRUE;
} elseif ($Threshold.Contains('~')) {
$HasTilde = $TRUE;
}

$Threshold = $Threshold.Replace('`:', '!').Replace('~', '').Replace('@', '');
[array]$DatimeValueArray = $Threshold.Split(':');

try {
$DateTimeValue = [DateTime]::ParseExact($Threshold, 'yyyy\/MM\/dd HH:mm:ss', $null);
$RetValue.Value = $DateTimeValue.ToFileTime();
$RetValue.Unit = 's';
[array]$DateTimeValue = @();
if ([string]::IsNullOrEmpty($DatimeValueArray[0]) -eq $FALSE) {
[array]$DateTimeValue += ([DateTime]::ParseExact($DatimeValueArray[0].Replace('!', ':'), 'yyyy\/MM\/dd HH:mm:ss', $null)).ToFileTime();
}
if ([string]::IsNullOrEmpty($DatimeValueArray[1]) -eq $FALSE) {
[array]$DateTimeValue += ([DateTime]::ParseExact($DatimeValueArray[1].Replace('!', ':'), 'yyyy\/MM\/dd HH:mm:ss', $null)).ToFileTime();
}

if ($DateTimeValue.Count -gt 1) {
$Threshold = [string]::Join(':', $DateTimeValue);
$RetValue.Mode = $IcingaEnums.IcingaThresholdMethod.Between;

if ($HasAt) {
$Threshold = [string]::Format('@{0}', $Threshold);
}
} elseif ($DatimeValueArray.Count -gt 1) {
if ($HasTilde) {
$Threshold = [string]::Format('~:{0}', $DateTimeValue[0]);
} else {
$Threshold = [string]::Format('{0}:', $DateTimeValue[0]);
}
} else {
$Threshold = $DateTimeValue[0];
}
$RetValue.Unit = 's';
$RetValue.IsDateTime = $TRUE;
} catch {
$RetValue.Value = $Threshold;
$RetValue.Threshold = $Threshold.Replace('!', '`:');
Exit-IcingaThrowException -CustomMessage ([string]::Format('Could not convert the provided threshold value {0} to a valid Icinga for Windows range', $RetValue.Raw)) -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.InvalidThresholdValue -Force;
return $RetValue;
}

return $RetValue;
} else {
$RetValue.Mode = $IcingaEnums.IcingaThresholdMethod.Between;
}

$Content = $Threshold.Split(':');
if ($Content.Count -eq 2 -And ([string]::IsNullOrEmpty($Content[1]))) {
$RetValue.Mode = $IcingaEnums.IcingaThresholdMethod.Lower;
}
} else {
$Content += $Threshold;
}
Expand All @@ -123,10 +222,12 @@ function Convert-IcingaPluginThresholds()

if ($ThresholdValue.Contains('~')) {
$ThresholdValue = $ThresholdValue.Replace('~', '');
$HasTilde = $TRUE;
$HasTilde = $TRUE;
$RetValue.Mode = $IcingaEnums.IcingaThresholdMethod.Greater;
} elseif ($ThresholdValue.Contains('@')) {
$HasAt = $TRUE;
$HasAt = $TRUE;
$ThresholdValue = $ThresholdValue.Replace('@', '');
$RetValue.Mode = $IcingaEnums.IcingaThresholdMethod.Outside;
}

if ($ThresholdValue[0] -eq '-' -And $ThresholdValue.Length -ge 1) {
Expand Down Expand Up @@ -201,16 +302,67 @@ function Convert-IcingaPluginThresholds()

[string]$Value = [string]::Join(':', $ConvertedValue);

switch ($RetValue.Mode) {
$IcingaEnums.IcingaThresholdMethod.Default {
$RetValue.Value = $ConvertedValue[0];

if ([string]::IsNullOrEmpty($RetValue.Value)) {
Exit-IcingaThrowException -CustomMessage ([string]::Format('Could not convert the provided threshold value {0} to a valid Icinga for Windows range', $RetValue.Raw)) -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.InvalidThresholdValue -Force;
return $RetValue;
}
break;
};
$IcingaEnums.IcingaThresholdMethod.Lower {
$RetValue.Value = $ConvertedValue[0];

if ([string]::IsNullOrEmpty($RetValue.Value)) {
Exit-IcingaThrowException -CustomMessage ([string]::Format('Could not convert the provided threshold value {0} to a valid Icinga for Windows range', $RetValue.Raw)) -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.InvalidThresholdValue -Force;
return $RetValue;
}
break;
};
$IcingaEnums.IcingaThresholdMethod.Greater {
$RetValue.Value = $ConvertedValue[1];

if ([string]::IsNullOrEmpty($RetValue.Value)) {
Exit-IcingaThrowException -CustomMessage ([string]::Format('Could not convert the provided threshold value {0} to a valid Icinga for Windows range', $RetValue.Raw)) -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.InvalidThresholdValue -Force;
return $RetValue;
}
break;
};
$IcingaEnums.IcingaThresholdMethod.Between {
$RetValue.StartRange = [decimal]$ConvertedValue[0];
$RetValue.EndRange = [decimal]$ConvertedValue[1];

if ([string]::IsNullOrEmpty($RetValue.StartRange) -Or [string]::IsNullOrEmpty($RetValue.EndRange)) {
Exit-IcingaThrowException -CustomMessage ([string]::Format('Could not convert the provided threshold value {0} to a valid Icinga for Windows range', $RetValue.Raw)) -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.InvalidThresholdValue -Force;
return $RetValue;
}
break;
};
$IcingaEnums.IcingaThresholdMethod.Outside {
$RetValue.StartRange = [decimal]($ConvertedValue[0].Replace('@', ''));
$RetValue.EndRange = [decimal]$ConvertedValue[1];

if ([string]::IsNullOrEmpty($RetValue.StartRange) -Or [string]::IsNullOrEmpty($RetValue.EndRange)) {
Exit-IcingaThrowException -CustomMessage ([string]::Format('Could not convert the provided threshold value {0} to a valid Icinga for Windows range', ($RetValue.Raw))) -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.InvalidThresholdValue -Force;
return $RetValue;
}
break;
};
}

if ([string]::IsNullOrEmpty($Value) -eq $FALSE -And $Value.Contains(':') -eq $FALSE) {
if ((Test-Numeric $Value)) {
$RetValue.Value = [decimal]$Value;
$RetValue.Threshold = [decimal]$Value;
$RetValue.Value = [decimal]$Value;
return $RetValue;
}
}

# Always ensure we are using correct digits
$Value = ([string]$Value).Replace(',', '.');
$RetValue.Value = $Value;
$Value = ([string]$Value).Replace(',', '.');
$RetValue.Threshold = $Value;

return $RetValue;
}
Loading

0 comments on commit 295fa00

Please sign in to comment.