diff --git a/doc/100-General/10-Changelog.md b/doc/100-General/10-Changelog.md index 81b9d07..6a8ce2e 100644 --- a/doc/100-General/10-Changelog.md +++ b/doc/100-General/10-Changelog.md @@ -11,9 +11,14 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic [Issues and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/38) +## 1.13.3 (tbd) + +[Issues and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/39) + ### Bugfixes * [#787](https://github.com/Icinga/icinga-powershell-framework/pull/787) Fixes the return value in case the `Agent` component could not be installed from `$FALSE` to `null` +* [#796](https://github.com/Icinga/icinga-powershell-framework/issues/796) [#798](https://github.com/Icinga/icinga-powershell-framework/issues/798) Fixes an issue with the new check handling, which did not properly convert values from checks to the correct performance data values and base values in some cases ## 1.13.3 (tbd) diff --git a/lib/core/tools/ConvertTo-IcingaUnixTime.psm1 b/lib/core/tools/ConvertTo-IcingaUnixTime.psm1 new file mode 100644 index 0000000..94d292b --- /dev/null +++ b/lib/core/tools/ConvertTo-IcingaUnixTime.psm1 @@ -0,0 +1,38 @@ +<# +.SYNOPSIS +Converts a time string to a Unix timestamp. + +.DESCRIPTION +Converts a given time string like "2025-04-10 20:00:00" to a Unix timestamp. +The function returns 0 if the input is null or empty. +If the input cannot be parsed, it returns -1. +The function uses the UTC time zone for the conversion. + +.PARAMETER TimeString +The time string to convert. It should be in a format that can be parsed by [datetime]::Parse, like "2025-04-10 20:00:00" + +.EXAMPLE +$UnixTime = ConvertTo-IcingaUnixTime -TimeString "2025-04-10 20:00:00" +$UnixTime +#> + +function ConvertTo-IcingaUnixTime() +{ + param ( + [string]$TimeString = $null + ); + + if ([string]::IsNullOrEmpty($TimeString)) { + return 0; + } + + try { + return [decimal][double]::Parse( + (Get-Date -UFormat %s -Date (Get-Date -Date $TimeString).ToUniversalTime()) + ); + } catch { + return -1; + } + + return 0; +} diff --git a/lib/core/tools/Get-IcingaUnixTimeOffsetNow.psm1 b/lib/core/tools/Get-IcingaUnixTimeOffsetNow.psm1 new file mode 100644 index 0000000..a8ea9ea --- /dev/null +++ b/lib/core/tools/Get-IcingaUnixTimeOffsetNow.psm1 @@ -0,0 +1,51 @@ +<# +.SYNOPSIS +Calculates the offset in seconds between the current Unix time and a specified Unix time or time string. + +.DESCRIPTION +The `Get-IcingaUnixTimeOffsetNow` function computes the difference in seconds between the current Unix time and a provided Unix time or time string. If no valid input is provided, the function returns 0. + +.PARAMETER TimeString +A string representing a specific time. This string will be converted to Unix time using the `ConvertTo-IcingaUnixTime` function. + +.PARAMETER UnixTime +A decimal value representing a specific Unix time. If provided, the offset will be calculated using this value. + +.RETURNS +The offset in seconds as a decimal value. If no valid input is provided or the conversion fails, the function returns 0. + +.EXAMPLE +PS> Get-IcingaUnixTimeOffsetNow -TimeString "2025-04-20 10:00:00" +Calculates the offset in seconds between the current Unix time and the specified time string. + +.EXAMPLE +PS> Get-IcingaUnixTimeOffsetNow -UnixTime 1672531200 +Calculates the offset in seconds between the current Unix time and the specified Unix time. + +.NOTES +This function depends on the `ConvertTo-IcingaUnixTime` and `Get-IcingaUnixTime` functions to perform time conversions and retrieve the current Unix time. +#> + +function Get-IcingaUnixTimeOffsetNow() +{ + param ( + [string]$TimeString = '', + [decimal]$UnixTime = 0 + ); + + if ([string]::IsNullOrEmpty($TimeString) -And $UnixTime -eq 0) { + return 0; + } + + if ([string]::IsNullOrEmpty($TimeString) -eq $FALSE) { + $UnixTime = ConvertTo-IcingaUnixTime -TimeString $TimeString; + + if ($UnixTime -le 0) { + return 0; + } + } + + $CurrentUnixTime = Get-IcingaUnixTime; + + return ($CurrentUnixTime - $UnixTime); +} diff --git a/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 b/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 index 0dae7ae..998d289 100644 --- a/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 +++ b/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 @@ -134,6 +134,24 @@ function Compare-IcingaPluginThresholds() $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Minimum' -Value (Convert-IcingaPluginThresholds -Threshold $Minium); $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Maximum' -Value (Convert-IcingaPluginThresholds -Threshold $Maximum); + if ($TestInput.Decimal) { + $ConvertedValue = Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $InputValue, $Unit)); + + if ((Test-IcingaDecimal -Value $ConvertedValue.Value).Decimal) { + $InputValue = [decimal]$ConvertedValue.Value; + $IcingaThresholds.Value = [decimal]$ConvertedValue.Value; + $IcingaThresholds.Unit = $ConvertedValue.Unit; + } + } + + if ($BaseInput.Decimal) { + $ConvertedBaseValue = Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $BaseValue, $Unit)); + + if ((Test-IcingaDecimal -Value $ConvertedBaseValue.Value).Decimal) { + $BaseValue = [decimal]$ConvertedBaseValue.Value; + } + } + # In case we are using % values, we should set the BaseValue always to 100 if ($Unit -eq '%' -And $null -eq $BaseValue) { $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'BaseValue' -Value 100; @@ -144,17 +162,17 @@ function Compare-IcingaPluginThresholds() $CheckResult = $null; if ($Matches) { - $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.Matches -MetricsOverTime $MoTData; + $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $IcingaThresholds.Unit -CheckUnit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.Matches -MetricsOverTime $MoTData; } elseif ($NotMatches) { - $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.NotMatches -MetricsOverTime $MoTData; + $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $IcingaThresholds.Unit -CheckUnit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.NotMatches -MetricsOverTime $MoTData; } elseif ($IsBetween) { - $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.Between -MetricsOverTime $MoTData; + $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $IcingaThresholds.Unit -CheckUnit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.Between -MetricsOverTime $MoTData; } elseif ($IsLowerEqual) { - $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.LowerEqual -MetricsOverTime $MoTData; + $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $IcingaThresholds.Unit -CheckUnit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.LowerEqual -MetricsOverTime $MoTData; } elseif ($IsGreaterEqual) { - $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.GreaterEqual -MetricsOverTime $MoTData; + $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $IcingaThresholds.Unit -CheckUnit $Unit -Translation $Translation -OverrideMode $IcingaEnums.IcingaThresholdMethod.GreaterEqual -MetricsOverTime $MoTData; } else { - $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $Unit -Translation $Translation -MetricsOverTime $MoTData; + $CheckResult = Compare-IcingaPluginValueToThreshold -Value $InputValue -BaseValue $IcingaThresholds.BaseValue -Threshold $IcingaThresholds.Threshold -Unit $IcingaThresholds.Unit -CheckUnit $Unit -Translation $Translation -MetricsOverTime $MoTData; } $IcingaThresholds.Message = $CheckResult.Message; diff --git a/lib/icinga/plugin/Compare-IcingaPluginValueToThreshold.psm1 b/lib/icinga/plugin/Compare-IcingaPluginValueToThreshold.psm1 index 45cf8da..dddeb8b 100644 --- a/lib/icinga/plugin/Compare-IcingaPluginValueToThreshold.psm1 +++ b/lib/icinga/plugin/Compare-IcingaPluginValueToThreshold.psm1 @@ -57,6 +57,7 @@ function Compare-IcingaPluginValueToThreshold() $Value = $null, $BaseValue = $null, $Unit = $null, + $CheckUnit = $null, $Translation = $null, $Threshold = $null, $OverrideMode = $null, @@ -94,7 +95,7 @@ function Compare-IcingaPluginValueToThreshold() # Otherwise just convert the values to human readble values $HumanReadableValue = ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value $HumanReadableValue; - $HumanReadableValue = Convert-IcingaPluginValueToString -Value $HumanReadableValue -Unit $Unit; + $HumanReadableValue = Convert-IcingaPluginValueToString -Value $HumanReadableValue -Unit $Unit -OriginalUnit $CheckUnit; if ($null -eq $Value -Or $null -eq $Threshold -Or [string]::IsNullOrEmpty($Threshold.Raw)) { $RetValue.Message = $HumanReadableValue; @@ -139,7 +140,7 @@ function Compare-IcingaPluginValueToThreshold() } if ($Value -gt $Threshold.Value) { - $RetValue.Message = [string]::Format('Value {0} is greater than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is greater than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } } @@ -147,42 +148,42 @@ function Compare-IcingaPluginValueToThreshold() }; $IcingaEnums.IcingaThresholdMethod.Lower { if ($Value -lt $Threshold.Value) { - $RetValue.Message = [string]::Format('Value {0} is lower than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is lower than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } break; }; $IcingaEnums.IcingaThresholdMethod.LowerEqual { if ($Value -le $Threshold.Value) { - $RetValue.Message = [string]::Format('Value {0} is lower or equal than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is lower or equal than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } break; }; $IcingaEnums.IcingaThresholdMethod.Greater { if ($Value -gt $Threshold.Value) { - $RetValue.Message = [string]::Format('Value {0} is greater than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is greater than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } break; }; $IcingaEnums.IcingaThresholdMethod.GreaterEqual { if ($Value -gt $Threshold.Value) { - $RetValue.Message = [string]::Format('Value {0} is greater or equal than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is greater or equal than threshold {1}{2}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.Value -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } break; }; $IcingaEnums.IcingaThresholdMethod.Between { if ($Value -lt $Threshold.StartRange -Or $Value -gt $Threshold.EndRange) { - $RetValue.Message = [string]::Format('Value {0} is not between thresholds <{1} or >{2}{3}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.StartRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), (Convert-IcingaPluginValueToString -Value $Threshold.EndRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is not between thresholds <{1} or >{2}{3}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.StartRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), (Convert-IcingaPluginValueToString -Value $Threshold.EndRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } break; }; $IcingaEnums.IcingaThresholdMethod.Outside { if ($Value -ge $Threshold.StartRange -And $Value -le $Threshold.EndRange) { - $RetValue.Message = [string]::Format('Value {0} is between thresholds >={1} and <={2}{3}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.StartRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), (Convert-IcingaPluginValueToString -Value $Threshold.EndRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); + $RetValue.Message = [string]::Format('Value {0} is between thresholds >={1} and <={2}{3}', $HumanReadableValue, (Convert-IcingaPluginValueToString -Value $Threshold.StartRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $CheckUnit -UsePercent:$UsePercent -IsThreshold), (Convert-IcingaPluginValueToString -Value $Threshold.EndRange -BaseValue $BaseValue -Unit $Threshold.Unit -OriginalUnit $Unit -UsePercent:$UsePercent -IsThreshold), $MoTMessage); return $RetValue; } break; diff --git a/lib/icinga/plugin/New-IcingaCheck.psm1 b/lib/icinga/plugin/New-IcingaCheck.psm1 index 16adf13..20ddcee 100644 --- a/lib/icinga/plugin/New-IcingaCheck.psm1 +++ b/lib/icinga/plugin/New-IcingaCheck.psm1 @@ -258,9 +258,9 @@ function New-IcingaCheck() [string]$PerfDataLabel = [string]::Format( '{0}={1}{2};{3};{4};{5};{6}', - $PerfDataName, + $PerfDataName.ToLower(), (Format-IcingaPerfDataValue $value), - $this.__ThresholdObject.PerfUnit, + $this.__ThresholdObject.Unit, (Format-IcingaPerfDataValue $warning), (Format-IcingaPerfDataValue $critical), (Format-IcingaPerfDataValue $this.Minimum), @@ -289,7 +289,7 @@ function New-IcingaCheck() } } - $Global:Icinga.Private.Scheduler.PerfDataWriter.Storage.Append($PerfDataLabel.ToLower()) | Out-Null; + $Global:Icinga.Private.Scheduler.PerfDataWriter.Storage.Append($PerfDataLabel) | Out-Null; } $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ValidateObject' -Value {