From 3afbce090e057d0de80fe7e3229570726de3bbf3 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Thu, 15 Jul 2021 15:37:53 +0200 Subject: [PATCH] Adds array thresholds and date time support --- doc/31-Changelog.md | 3 +- .../tools/Convert-IcingaPluginThresholds.psm1 | 14 + .../Compare-IcingaPluginThresholds.psm1 | 42 +++ lib/icinga/plugin/New-IcingaCheck.psm1 | 256 ++++++++++++++++++ lib/icinga/plugin/New-IcingaCheckResult.psm1 | 2 + 5 files changed, 316 insertions(+), 1 deletion(-) diff --git a/doc/31-Changelog.md b/doc/31-Changelog.md index ab306da8..2eddacbc 100644 --- a/doc/31-Changelog.md +++ b/doc/31-Changelog.md @@ -7,7 +7,7 @@ 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.6.0 (pending) +## 1.6.0 (2021-09-07) [Issue and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/15?closed=1) @@ -19,6 +19,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic ### Enhancements * [#301](https://github.com/Icinga/icinga-powershell-framework/pull/301) Improves error handling to no longer print passwords in case `String` is used for `SecureString` arguments +* [#303](https://github.com/Icinga/icinga-powershell-framework/pull/303) Adds support to parse arrays to Icinga Check thresholds functions like `WarnOutOfRange` and adds two new functions `WarnDateTime` and `CritDateTime`, for easier comparing of time stamps. * [#305](https://github.com/Icinga/icinga-powershell-framework/pull/305) Adds a new Cmdlet to test if functions with `Add-Type` are already present inside the current scope of the shell * [#306](https://github.com/Icinga/icinga-powershell-framework/pull/306) Adds new Cmdlet `Exit-IcingaThrowCritical` to throw critical exit with a custom message, either by force or by using string filtering and adds storing of plugin exit codes internally * [#314](https://github.com/Icinga/icinga-powershell-framework/pull/314) Adds support to configure on which address TCP sockets are created on, defaults to `loopback` interface diff --git a/lib/core/tools/Convert-IcingaPluginThresholds.psm1 b/lib/core/tools/Convert-IcingaPluginThresholds.psm1 index 7930fc4b..8987b39a 100644 --- a/lib/core/tools/Convert-IcingaPluginThresholds.psm1 +++ b/lib/core/tools/Convert-IcingaPluginThresholds.psm1 @@ -92,6 +92,20 @@ function Convert-IcingaPluginThresholds() [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) { + try { + $DateTimeValue = [DateTime]::ParseExact($Threshold, 'yyyy\/MM\/dd HH:mm:ss', $null); + $RetValue.Value = $DateTimeValue.ToFileTime(); + $RetValue.Unit = 's'; + } catch { + $RetValue.Value = $Threshold; + } + + return $RetValue; + } + $Content = $Threshold.Split(':'); } else { $Content += $Threshold; diff --git a/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 b/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 index d3847110..8659e732 100644 --- a/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 +++ b/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 @@ -6,6 +6,7 @@ function Compare-IcingaPluginThresholds() $BaseValue = $null, [switch]$Matches = $FALSE, [switch]$NotMatches = $FALSE, + [switch]$DateTime = $FALSE, [string]$Unit = '', $ThresholdCache = $null, [string]$CheckName = '', @@ -178,6 +179,47 @@ function Compare-IcingaPluginThresholds() (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit)) ); } + } elseif ($DateTime) { + # Checks if the InputValue Is Inside our time value + + try { + $DateTimeValue = 0; + [decimal]$TimeThreshold = 0; + $CurrentDate = $global:Icinga.CurrentDate; + $IcingaThresholds.Unit = ''; + + if ([string]::IsNullOrEmpty($InputValue) -eq $FALSE) { + $DateTimeValue = [DateTime]::FromFileTime($InputValue); + $IcingaThresholds.Value = $DateTimeValue.ToString('yyyy\/MM\/dd HH:mm:ss'); + } + + if ([string]::IsNullOrEmpty($ThresholdValue) -eq $FALSE) { + $TimeThreshold = (ConvertTo-Seconds -Value $Threshold); + $CurrentDate = $CurrentDate.AddSeconds($TimeThreshold); + $IcingaThresholds.IcingaThreshold = $CurrentDate.ToFileTimeUtc(); + } + + if ([string]::IsNullOrEmpty($ThresholdValue) -eq $FALSE -And ($DateTimeValue -eq 0 -Or $DateTimeValue -lt $CurrentDate)) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is lower than'; + $IcingaThresholds.Range = [string]::Format( + '{0} ({1}{2})', + ((Get-Date).ToString('yyyy\/MM\/dd HH:mm:ss')), + ( $( if ($TimeThreshold -ge 0) { '+'; } else { ''; } )), + $Threshold + ); + } + } catch { + $IcingaThresholds.ErrorMessage = [string]::Format( + 'Invalid date time specified. Your InputValue "{0}" seems not be a valid date time or your provided Threshold "{1}" cannot be converted to seconds. Exception: {2}', + $InputValue, + $ThresholdValue, + $_.Exception.Message + ); + $IcingaThresholds.HasError = $TRUE; + + return $IcingaThresholds; + } } elseif ($IsBetween) { if ($InputValue -gt $Minium -And $InputValue -lt $Maximum) { $IcingaThresholds.InRange = $FALSE; diff --git a/lib/icinga/plugin/New-IcingaCheck.psm1 b/lib/icinga/plugin/New-IcingaCheck.psm1 index 3e8d2e70..f16f2fbc 100644 --- a/lib/icinga/plugin/New-IcingaCheck.psm1 +++ b/lib/icinga/plugin/New-IcingaCheck.psm1 @@ -267,6 +267,23 @@ function New-IcingaCheck() } } + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__SetCurrentExecutionTime' -Value { + if ($null -eq $global:Icinga) { + $global:Icinga = @{ }; + } + + if ($global:Icinga.ContainsKey('CurrentDate') -eq $FALSE) { + $global:Icinga.Add('CurrentDate', (Get-Date)); + return; + } + + if ($null -ne $global:Icinga.CurrentDate) { + return; + } + + $global:Icinga.CurrentDate = (Get-Date).ToUniversalTime(); + } + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__AddCheckDataToCache' -Value { # We only require this in case we are running as daemon @@ -396,8 +413,49 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnOutOfRange' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.WarnOutOfRange($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__WarningValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnDateTime' -Value { + param ($Threshold); + + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.WarnDateTime($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-DateTime', $TRUE); $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; @@ -410,6 +468,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLike' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.WarnIfLike($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-Matches', $TRUE); @@ -425,6 +496,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotLike' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.WarnIfNotLike($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-NotMatches', $TRUE); @@ -452,8 +536,49 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritOutOfRange' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.CritOutOfRange($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__CriticalValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritDateTime' -Value { + param ($Threshold); + + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.CritDateTime($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-DateTime', $TRUE); $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; @@ -466,6 +591,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLike' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.CritIfLike($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-Matches', $TRUE); @@ -481,6 +619,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfNotLike' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.CritIfNotLike($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-NotMatches', $TRUE); @@ -524,6 +675,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerThan' -Value { param ($Value); + if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Value) { + $this.WarnIfLowerThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [string]$Threshold = [string]::Format('{0}:', $Value); return $this.WarnOutOfRange($Threshold); @@ -532,6 +696,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerThan' -Value { param ($Value); + if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Value) { + $this.CritIfLowerThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [string]$Threshold = [string]::Format('{0}:', $Value); return $this.CritOutOfRange($Threshold); @@ -540,6 +717,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterThan' -Value { param ($Value); + if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Value) { + $this.WarnIfGreaterThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [string]$Threshold = [string]::Format('~:{0}', $Value); return $this.WarnOutOfRange($Threshold); @@ -548,6 +738,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterThan' -Value { param ($Value); + if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Value) { + $this.CritIfGreaterThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [string]$Threshold = [string]::Format('~:{0}', $Value); return $this.CritOutOfRange($Threshold); @@ -588,6 +791,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerEqualThan' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.WarnIfLowerEqualThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-IsLowerEqual', $TRUE); @@ -603,6 +819,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerEqualThan' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.CritIfLowerEqualThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-IsLowerEqual', $TRUE); @@ -618,6 +847,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterEqualThan' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.WarnIfGreaterEqualThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-IsGreaterEqual', $TRUE); @@ -633,6 +875,19 @@ function New-IcingaCheck() $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterEqualThan' -Value { param ($Threshold); + if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') { + foreach ($entry in $Threshold) { + $this.CritIfGreaterEqualThan($entry) | Out-Null; + + # Break on first value causing a warning + if ($ThresholdObject.InRange -eq $FALSE) { + break; + } + } + + return $this; + } + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); $ThresholdArguments.Add('-Threshold', $Threshold); $ThresholdArguments.Add('-IsGreaterEqual', $TRUE); @@ -686,6 +941,7 @@ function New-IcingaCheck() $IcingaCheck.__ValidateObject(); $IcingaCheck.__ValidateUnit(); + $IcingaCheck.__SetCurrentExecutionTime(); $IcingaCheck.__AddCheckDataToCache(); $IcingaCheck.__SetInternalTimeInterval(); $IcingaCheck.__ConvertMinMax(); diff --git a/lib/icinga/plugin/New-IcingaCheckResult.psm1 b/lib/icinga/plugin/New-IcingaCheckResult.psm1 index a353b161..ca921100 100644 --- a/lib/icinga/plugin/New-IcingaCheckResult.psm1 +++ b/lib/icinga/plugin/New-IcingaCheckResult.psm1 @@ -26,6 +26,8 @@ function New-IcingaCheckResult() # Ensure we reset our internal cache once the plugin was executed $Global:Icinga.ThresholdCache[$this.Check.__GetCheckCommand()] = $null; + # Reset the current execution date + $Global:Icinga.CurrentDate = $null; $ExitCode = $this.Check.__GetCheckState();