From a9126ce40226c45e4d25bd7d413affdef027c5b5 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Fri, 7 May 2021 14:38:10 +0200 Subject: [PATCH] Re-Write execution of checks --- doc/developerguide/01-New-IcingaCheck.md | 3 +- .../02-New-IcingaCheckPackage.md | 1 + lib/core/tools/Convert-Bytes.psm1 | 3 + ...Convert-IcingaCheckArgumentToPSObject.psm1 | 24 + .../Convert-IcingaPluginValueToString.psm1 | 38 + lib/core/tools/ConvertFrom-Percent.psm1 | 14 + lib/core/tools/ConvertFrom-TimeSpan.psm1 | 53 +- lib/core/tools/ConvertTo-BytesNextUnit.psm1 | 30 + .../tools/Get-IcingaCheckCommandConfig.psm1 | 60 +- .../tools/Get-IcingaNextUnitIteration.psm1 | 20 + lib/help/help/Get-IcingaHelpThresholds.psm1 | 5 +- .../Icinga_IcingaExceptionEnums.psm1 | 2 +- .../Compare-IcingaPluginThresholds.psm1 | 421 +++++ ...nvertTo-IcingaPluginOutputTranslation.psm1 | 34 + lib/icinga/plugin/New-IcingaCheck.psm1 | 1487 ++++++++--------- .../plugin/New-IcingaCheckBaseObject.psm1 | 189 +++ lib/icinga/plugin/New-IcingaCheckPackage.psm1 | 736 ++++---- lib/icinga/plugin/New-IcingaCheckResult.psm1 | 40 +- .../New-IcingaPerformanceDataEntry.psm1 | 21 +- .../plugin/Write-IcingaPluginPerfData.psm1 | 28 +- 20 files changed, 1904 insertions(+), 1305 deletions(-) create mode 100644 lib/core/tools/Convert-IcingaCheckArgumentToPSObject.psm1 create mode 100644 lib/core/tools/Convert-IcingaPluginValueToString.psm1 create mode 100644 lib/core/tools/ConvertFrom-Percent.psm1 create mode 100644 lib/core/tools/ConvertTo-BytesNextUnit.psm1 create mode 100644 lib/core/tools/Get-IcingaNextUnitIteration.psm1 create mode 100644 lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 create mode 100644 lib/icinga/plugin/ConvertTo-IcingaPluginOutputTranslation.psm1 create mode 100644 lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 diff --git a/doc/developerguide/01-New-IcingaCheck.md b/doc/developerguide/01-New-IcingaCheck.md index 50c51e4..8318707 100644 --- a/doc/developerguide/01-New-IcingaCheck.md +++ b/doc/developerguide/01-New-IcingaCheck.md @@ -24,11 +24,12 @@ For performance metrics you can provide a `Unit` to ensure your graphing is disp | Argument | Input | Mandatory | Description | | --- | --- | --- | --- | -| Name | String | * | The unique name of each check within a plugin. Will be display in the check output. | +| Name | String | * | The unique name of each check within a plugin. Will be display in the check output. | | Value | Object | * | The value all comparison is done with. In general this should be a `Numeric` or `String` value | | Unit | Units | | Specify the unit for a value to display graph properly | | Minimum | String | | The minimum value which is displayed on your graphs | | Maximum | String | | The maximum value which is displayed on your graphs | +| BaseValue | Object | | Sets a base value for the check which allows to use dynamic `%` usage on thresholds. The base value will calculate the `%` value from the current value, allowing generic `%` monitoring | | ObjectExists | Bool | | If you are using values coming from objects, like Services, you can use this argument to determin if the object itself exist or not. In case it doesn't, you will receive a proper output on the check result | | Translation | Hashtable | | In case you want to map values to certain descriptions, you can place a hashtable at this argument which will then map the value to the description on the check result. For example this would apply to service running states | | LabelName | String | | Allows to override the default label name generated based on the `-Name` argument to a custom name. Please ensure to remove any special characters manually, as the name set here is the exact name for the label | diff --git a/doc/developerguide/02-New-IcingaCheckPackage.md b/doc/developerguide/02-New-IcingaCheckPackage.md index 3673d53..e8b30c9 100644 --- a/doc/developerguide/02-New-IcingaCheckPackage.md +++ b/doc/developerguide/02-New-IcingaCheckPackage.md @@ -27,6 +27,7 @@ $IcingaPackage = New-IcingaCheckPackage -Name 'My Package' -OperatorAnd; | Checks | Array | | Array of checks to be added to the check package | | Verbose | int | | Defines the level of output detail from 0 lowest to 3 highest detail | | IgnoreEmptyPackage | Switch | | By default a check package will return `Unknown` in case no checks are assigned. Setting this argument will ignore this and return `Ok` instead +| AddSummaryHeader | Switch | | Adds a summary on how many checks are Unknown, Critical, Warning and Ok on the output of the package | Hidden | Switch | | If set, the check package doesn't generate output | ### Examples diff --git a/lib/core/tools/Convert-Bytes.psm1 b/lib/core/tools/Convert-Bytes.psm1 index 757d14a..c4228b3 100644 --- a/lib/core/tools/Convert-Bytes.psm1 +++ b/lib/core/tools/Convert-Bytes.psm1 @@ -5,6 +5,9 @@ function Convert-Bytes() [string]$Unit ); + # Ensure we always use proper formatting of values + $Value = $Value.Replace(',', '.'); + If (($Value -Match "(^[\d\.]*) ?(B|KB|MB|GB|TB|PT|KiB|MiB|GiB|TiB|PiB)") -eq $FALSE) { $Value = [string]::Format('{0}B', $Value); } diff --git a/lib/core/tools/Convert-IcingaCheckArgumentToPSObject.psm1 b/lib/core/tools/Convert-IcingaCheckArgumentToPSObject.psm1 new file mode 100644 index 0000000..79b430e --- /dev/null +++ b/lib/core/tools/Convert-IcingaCheckArgumentToPSObject.psm1 @@ -0,0 +1,24 @@ +function Convert-IcingaCheckArgumentToPSObject() +{ + param ( + $Parameter = $null + ); + + $ParamValue = New-Object -TypeName PSObject; + + if ($null -eq $parameter) { + return $ParamValue; + } + + $ParamValue | Add-Member -MemberType NoteProperty -Name 'type' -Value (New-Object -TypeName PSObject); + $ParamValue | Add-Member -MemberType NoteProperty -Name 'Description' -Value (New-Object -TypeName PSObject); + $ParamValue | Add-Member -MemberType NoteProperty -Name 'Attributes' -Value (New-Object -TypeName PSObject); + $ParamValue | Add-Member -MemberType NoteProperty -Name 'position' -Value $Parameter.position; + $ParamValue | Add-Member -MemberType NoteProperty -Name 'Name' -Value $Parameter.name; + $ParamValue | Add-Member -MemberType NoteProperty -Name 'required' -Value $Parameter.required; + $ParamValue.type | Add-Member -MemberType NoteProperty -Name 'name' -Value $Parameter.type.name; + $ParamValue.Description | Add-Member -MemberType NoteProperty -Name 'Text' -Value $Parameter.Description.Text; + $ParamValue.Attributes | Add-Member -MemberType NoteProperty -Name 'ValidValues' -Value $null; + + return $ParamValue; +} diff --git a/lib/core/tools/Convert-IcingaPluginValueToString.psm1 b/lib/core/tools/Convert-IcingaPluginValueToString.psm1 new file mode 100644 index 0000000..75be75c --- /dev/null +++ b/lib/core/tools/Convert-IcingaPluginValueToString.psm1 @@ -0,0 +1,38 @@ +function Convert-IcingaPluginValueToString() +{ + param ( + $Value, + [string]$Unit = '', + [string]$OriginalUnit = '' + ); + + $AdjustedValue = $Value; + + if ([string]::IsNullOrEmpty($OriginalUnit)) { + $OriginalUnit = $Unit; + } + + try { + $AdjustedValue = ([math]::Round([decimal]$Value, 6)) + } catch { + $AdjustedValue = $Value; + } + + if ($Unit -eq '%' -Or [string]::IsNullOrEmpty($Unit)) { + return ([string]::Format('{0}{1}', $AdjustedValue, $Unit)); + } + + switch ($OriginalUnit) { + { ($_ -eq "B") -or ($_ -eq "KiB") -or ($_ -eq "MiB") -or ($_ -eq "GiB") -or ($_ -eq "TiB") -or ($_ -eq "PiB") -or ($_ -eq "EiB") -or ($_ -eq "ZiB") -or ($_ -eq "YiB") } { + return (ConvertTo-BytesNextUnit -Value $Value -Unit $Unit -Units @('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')); + }; + { ($_ -eq "KB") -or ($_ -eq "MB") -or ($_ -eq "GB") -or ($_ -eq "TB") -or ($_ -eq "PB") -or ($_ -eq "EB") -or ($_ -eq "ZB") -or ($_ -eq "YB") } { + return (ConvertTo-BytesNextUnit -Value $Value -Unit $Unit -Units @('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')); + }; + 's' { + return (ConvertFrom-TimeSpan -Seconds $AdjustedValue) + }; + } + + return ([string]::Format('{0}{1}', $AdjustedValue, $Unit)); +} diff --git a/lib/core/tools/ConvertFrom-Percent.psm1 b/lib/core/tools/ConvertFrom-Percent.psm1 new file mode 100644 index 0000000..ff7b02c --- /dev/null +++ b/lib/core/tools/ConvertFrom-Percent.psm1 @@ -0,0 +1,14 @@ +function ConvertFrom-Percent() +{ + param ( + $Value = $null, + $Percent = $null, + [int]$Digits = 0 + ); + + if ($null -eq $Value -Or $null -eq $Percent) { + return 0; + } + + return ([math]::Round(($Value / 100 * $Percent), $Digits)); +} diff --git a/lib/core/tools/ConvertFrom-TimeSpan.psm1 b/lib/core/tools/ConvertFrom-TimeSpan.psm1 index d6cc444..f953d97 100644 --- a/lib/core/tools/ConvertFrom-TimeSpan.psm1 +++ b/lib/core/tools/ConvertFrom-TimeSpan.psm1 @@ -2,17 +2,52 @@ Import-IcingaLib core\tools; function ConvertFrom-TimeSpan() { - param( - $Seconds + param ( + $Seconds = 0 ); $TimeSpan = [TimeSpan]::FromSeconds($Seconds); - return [string]::Format( - '{0}d {1}h {2}m {3}s', - $TimeSpan.Days, - $TimeSpan.Hours, - $TimeSpan.Minutes, - $TimeSpan.Seconds - ); + if ($TimeSpan.TotalDays -ge 1.0) { + return ( + [string]::Format( + '{0}d', + $TimeSpan.TotalDays + ) + ); + } + if ($TimeSpan.TotalHours -ge 1.0) { + return ( + [string]::Format( + '{0}h', + $TimeSpan.TotalHours + ) + ); + } + if ($TimeSpan.TotalMinutes -ge 1.0) { + return ( + [string]::Format( + '{0}m', + $TimeSpan.TotalMinutes + ) + ); + } + if ($TimeSpan.TotalSeconds -ge 1.0) { + return ( + [string]::Format( + '{0}s', + $TimeSpan.TotalSeconds + ) + ); + } + if ($TimeSpan.TotalMilliseconds -gt 0) { + return ( + [string]::Format( + '{0}ms', + $TimeSpan.TotalMilliseconds + ) + ); + } + + return ([string]::Format('{0}s', $Seconds)); } diff --git a/lib/core/tools/ConvertTo-BytesNextUnit.psm1 b/lib/core/tools/ConvertTo-BytesNextUnit.psm1 new file mode 100644 index 0000000..3a1c3c1 --- /dev/null +++ b/lib/core/tools/ConvertTo-BytesNextUnit.psm1 @@ -0,0 +1,30 @@ +function ConvertTo-BytesNextUnit() +{ + param ( + [string]$Value = $null, + [string]$Unit = $null, + [array]$Units = @('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB') + ); + + [string]$UnitValue = [string]::Format('{0}{1}', $Value, $Unit); + + while ($TRUE) { + $Unit = Get-IcingaNextUnitIteration -Unit $Unit -Units $Units; + [decimal]$NewValue = (Convert-Bytes -Value $UnitValue -Unit $Unit).Value; + if ($NewValue -ge 1.0) { + if ($Unit -eq $RetUnit) { + break; + } + $RetValue = [math]::Round([decimal]$NewValue, 2); + $RetUnit = $Unit; + } else { + if ([string]::IsNullOrEmpty($RetUnit)) { + $RetValue = $Value; + $RetUnit = 'B'; + } + break; + } + } + + return ([string]::Format('{0}{1}', $RetValue, $RetUnit)); +} diff --git a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 index 8fcb669..8430b1c 100644 --- a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 +++ b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 @@ -77,24 +77,28 @@ function Get-IcingaCheckCommandConfig() [switch]$IcingaConfig ); + [array]$BlacklistedArguments = @( + 'ThresholdInterval' + ); + # Check whether all Checks will be exported or just the ones specified if ([string]::IsNullOrEmpty($CheckName) -eq $true) { $CheckName = (Get-Command Invoke-IcingaCheck*).Name } [int]$FieldID = 2; # Starts at '2', because '0' and '1' are reserved for 'Verbose' and 'NoPerfData' - [hashtable]$Basket = @{}; + [hashtable]$Basket = @{ }; # Define basic hashtable structure by adding fields: "Datafield", "DataList", "Command" - $Basket.Add('Datafield', @{}); - $Basket.Add('DataList', @{}); - $Basket.Add('Command', @{}); + $Basket.Add('Datafield', @{ }); + $Basket.Add('DataList', @{ }); + $Basket.Add('Command', @{ }); # At first generate a base Check-Command we can use as import source for all other commands $Basket.Command.Add( 'PowerShell Base', @{ - 'arguments' = @{}; + 'arguments' = @{ }; 'command' = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'; 'disabled' = $FALSE; 'fields' = @(); @@ -104,26 +108,55 @@ function Get-IcingaCheckCommandConfig() 'object_name' = 'PowerShell Base'; 'object_type' = 'object'; 'timeout' = '180'; - 'vars' = @{}; + 'vars' = @{ }; 'zone' = $NULL; } ); + $ThresholdIntervalArg = New-Object -TypeName PSObject; + $ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'type' -Value (New-Object -TypeName PSObject); + $ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'Description' -Value (New-Object -TypeName PSObject); + $ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'position' -Value 99; + $ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'ThresholdInterval'; + $ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'required' -Value $FALSE; + $ThresholdIntervalArg.type | Add-Member -MemberType NoteProperty -Name 'name' -Value 'String'; + $ThresholdIntervalArg.Description | Add-Member -MemberType NoteProperty -Name 'Text' -Value 'Change the value your defined threshold checks against from the current value to a collected time threshold of the Icinga for Windows daemon, as described here: https://icinga.com/docs/icinga-for-windows/latest/doc/service/10-Register-Service-Checks/ An example for this argument would be 1m or 15m which will use the average of 1m or 15m for monitoring.'; + # Loop through ${CheckName}, to get information on every command specified/all commands. foreach ($check in $CheckName) { # Get necessary syntax-information and more through cmdlet "Get-Help" $Data = (Get-Help $check); $ParameterList = (Get-Command -Name $check).Parameters; + $CheckParamList = @( $ThresholdIntervalArg ); $PluginNameSpace = $Data.Name.Replace('Invoke-', ''); + foreach ($entry in $Data.parameters.parameter) { + foreach ($BlackListArg in $BlacklistedArguments) { + if ($BlackListArg.ToLower() -eq $entry.Name.ToLower()) { + Write-IcingaConsoleError -Message 'The argument "{0}" for check command "{1}" is not allowed, as this is reserved as Framework constant argument and can not be used.' -Objects $BlackListArg, $check; + return; + } + } + $CheckParamList += (Convert-IcingaCheckArgumentToPSObject -Parameter $entry); + } + + foreach ($arg in $ParameterList.Keys) { + foreach ($entry in $CheckParamList) { + if ($entry.Name -eq $arg) { + $entry.Attributes.ValidValues = $ParameterList[$arg].Attributes.ValidValues; + break; + } + } + } + # Add command Structure $Basket.Command.Add( $Data.Name, @{ 'arguments' = @{ # Set the Command handling for every check command '-C' = @{ - 'value' = [string]::Format('try {{ Use-Icinga -Minimal; }} catch {{ Write-Output {1}The Icinga PowerShell Framework is either not installed on the system or not configured properly. Please check https://icinga.com/docs/windows for further details{1}; exit 3; }}; Exit-IcingaExecutePlugin -Command {1}{0}{1} ', $Data.Name, "'"); + 'value' = [string]::Format('try {{ Use-Icinga -Minimal; }} catch {{ Write-Output {1}The Icinga PowerShell Framework is either not installed on the system or not configured properly. Please check https://icinga.com/docs/windows for further details{1}; Write-Output "Error: $$($$_.Exception.Message)Components:`r`n$$( Get-Module -ListAvailable "icinga-powershell-*" )`r`nModule-Path:`r`n$$($$Env:PSModulePath)"; exit 3; }}; Exit-IcingaExecutePlugin -Command {1}{0}{1} ', $Data.Name, "'"); 'order' = '0'; } } @@ -136,7 +169,7 @@ function Get-IcingaCheckCommandConfig() ); # Loop through parameters of a given command - foreach ($parameter in $Data.parameters.parameter) { + foreach ($parameter in $CheckParamList) { $IsDataList = $FALSE; @@ -243,9 +276,9 @@ function Get-IcingaCheckCommandConfig() $DataListName = [string]::Format('{0} {1}', $PluginNameSpace, $parameter.Name); - if ($null -ne $ParameterList[$parameter.Name].Attributes.ValidValues) { + if ($null -ne $parameter.Attributes.ValidValues) { $IcingaDataType = 'Datalist'; - Add-PowerShellDataList -Name $DataListName -Basket $Basket -Arguments $ParameterList[$parameter.Name].Attributes.ValidValues; + Add-PowerShellDataList -Name $DataListName -Basket $Basket -Arguments $parameter.Attributes.ValidValues; $IsDataList = $TRUE; } elseif ($parameter.type.name -eq 'SwitchParameter') { $IcingaDataType = 'Boolean'; @@ -315,8 +348,13 @@ function Get-IcingaCheckCommandConfig() $Data = (Get-Help $check) $PluginNameSpace = $Data.Name.Replace('Invoke-', ''); + $CheckParamList = @( $ThresholdIntervalArg ); - foreach ($parameter in $Data.parameters.parameter) { + foreach ($entry in $Data.parameters.parameter) { + $CheckParamList += (Convert-IcingaCheckArgumentToPSObject -Parameter $entry);; + } + + foreach ($parameter in $CheckParamList) { $IcingaCustomVariable = [string]::Format('{0}_{1}_{2}', $PluginNameSpace, (Get-Culture).TextInfo.ToTitleCase($parameter.type.name), $parameter.Name); # Todo: Should we improve this? Actually the handling would be identical, we just need to assign diff --git a/lib/core/tools/Get-IcingaNextUnitIteration.psm1 b/lib/core/tools/Get-IcingaNextUnitIteration.psm1 new file mode 100644 index 0000000..d476efb --- /dev/null +++ b/lib/core/tools/Get-IcingaNextUnitIteration.psm1 @@ -0,0 +1,20 @@ +function Get-IcingaNextUnitIteration() +{ + param ( + [string]$Unit = '', + [array]$Units = @() + ); + + [bool]$Found = $FALSE; + + foreach ($entry in $Units) { + if ($Found) { + return $entry; + } + if ($entry -eq $Unit) { + $Found = $TRUE; + } + } + + return ''; +} diff --git a/lib/help/help/Get-IcingaHelpThresholds.psm1 b/lib/help/help/Get-IcingaHelpThresholds.psm1 index 846678c..b6d4b13 100644 --- a/lib/help/help/Get-IcingaHelpThresholds.psm1 +++ b/lib/help/help/Get-IcingaHelpThresholds.psm1 @@ -10,8 +10,9 @@ function Get-IcingaHelpThresholds() if ([string]::IsNullOrEmpty($Value) -eq $FALSE) { $ExampleCheck = New-IcingaCheck -Name 'Example' -Value $Value; - $ExampleCheck.WarnOutOfRange($Warning).CritOutOfRange($Critical).Compile($TRUE) | Out-Null; - return; + $ExampleCheck.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + + return (New-IcingaCheckResult -Check $ExampleCheck -Compile); } Write-IcingaConsolePlain diff --git a/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 b/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 index 4dedec2..1b9e36b 100644 --- a/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 +++ b/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 @@ -35,7 +35,7 @@ [hashtable]$Configuration = @{ PluginArgumentConflict = 'Your plugin argument configuration is causing a conflict. Mostly this error is caused by missmatching configurations by enabling multiple switch arguments which are resulting in a conflicting configuration for the plugin.'; - PluginArgumentMissing = 'Your plugin argument configuration is missing mandatory arguments. This is error is caused when mandatory or required arguments are missing from a plugin call and the operation is unable to process without them.'; + PluginArgumentMissing = 'Your plugin argument configuration is missing mandatory arguments. This error is caused when mandatory or required arguments are missing from a plugin call and the operation is unable to process without them.'; PluginNotInstalled = 'The plugin assigned to this service check seems not to be installed on this machine. Please review your service check configuration for spelling errors and check if the plugin is installed and executable on this machine by PowerShell.'; PluginNotAssigned = 'Your check for this service could not be processed because it seems like no valid Cmdlet was assigned to the check command. Please review your check command to ensure that a valid Cmdlet is assigned and executed by a PowerShell call.'; EventLogNotInstalled = 'Your Icinga PowerShell Framework has been executed by an unprivileged user before it was properly installed. The Windows EventLog application could not be registered because the current user has insufficient permissions. Please log into the machine and run "Use-Icinga" once from an administrative shell to complete the setup process. Once done this error should vanish.'; diff --git a/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 b/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 new file mode 100644 index 0000000..16bfac3 --- /dev/null +++ b/lib/icinga/plugin/Compare-IcingaPluginThresholds.psm1 @@ -0,0 +1,421 @@ +function Compare-IcingaPluginThresholds() +{ + param ( + [string]$Threshold = $null, + $InputValue = $null, + $BaseValue = $null, + [switch]$Matches = $FALSE, + [switch]$NotMatches = $FALSE, + [string]$Unit = '', + $ThresholdCache = $null, + [string]$CheckName = '', + [hashtable]$Translation = @{ }, + $Minium = $null, + $Maximum = $null, + [switch]$IsBetween = $FALSE, + [switch]$IsLowerEqual = $FALSE, + [switch]$IsGreaterEqual = $FALSE, + [string]$TimeInterval = $null + ); + + $IcingaThresholds = New-Object -TypeName PSObject; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Value' -Value $InputValue; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'BaseValue' -Value $BaseValue; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'RawValue' -Value $InputValue; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Unit' -Value $Unit; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'OriginalUnit' -Value $Unit; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'PerfUnit' -Value $Unit; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'IcingaThreshold' -Value $Threshold; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'RawThreshold' -Value $Threshold; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'CompareValue' -Value $null; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'MinRangeValue' -Value $null; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'MaxRangeValue' -Value $null; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'PercentValue' -Value ''; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'TimeSpan' -Value ''; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'InRange' -Value $TRUE; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Message' -Value ''; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Range' -Value ''; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'FullMessage' -Value ( + [string]::Format('{0}', (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $Unit -Value $InputValue))) + ); + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'HeaderValue' -Value $IcingaThresholds.FullMessage; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'ErrorMessage' -Value ''; + $IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'HasError' -Value $FALSE; + + # In case we are using % values, we should set the BaseValue always to 100 + if ($Unit -eq '%' -And $null -eq $BaseValue) { + $BaseValue = 100; + } + + if ([string]::IsNullOrEmpty($TimeInterval) -eq $FALSE -And $null -ne $ThresholdCache) { + $TimeSeconds = ConvertTo-Seconds $TimeInterval; + $MinuteInterval = ([TimeSpan]::FromSeconds($TimeSeconds)).Minutes; + $CheckPerfDataLabel = [string]::Format('{0}_{1}', (Format-IcingaPerfDataLabel $CheckName), $MinuteInterval); + + if ($null -ne $ThresholdCache.$CheckPerfDataLabel) { + $InputValue = $ThresholdCache.$CheckPerfDataLabel; + $InputValue = [math]::round([decimal]$InputValue, 6); + $IcingaThresholds.TimeSpan = $MinuteInterval; + } else { + $IcingaThresholds.HasError = $TRUE; + $IcingaThresholds.ErrorMessage = [string]::Format( + 'The provided time interval "{0}" which translates to "{1}m" in your "-ThresholdInterval" argument does not exist', + $TimeInterval, + $MinuteInterval + ); + } + } <#else { + # The symbol splitting our threshold from the time index value + # Examples: + # @20:40#15m + # ~:40#15m + # 40#15m + $TimeIndexSeparator = '#'; + + # In case we found a ~ not starting at the beginning, we should load the + # time index values created by our background daemon + # Allows us to specify something like "40:50#15" + if ($Threshold.Contains($TimeIndexSeparator) -And $null -ne $ThresholdCache) { + [int]$LastIndex = $Threshold.LastIndexOf($TimeIndexSeparator); + if ($LastIndex -ne 0) { + $TmpValue = $Threshold; + $Threshold = $TmpValue.Substring(0, $LastIndex); + $TimeIndex = $TmpValue.Substring($LastIndex + 1, $TmpValue.Length - $LastIndex - 1); + $TimeSeconds = ConvertTo-Seconds $TimeIndex; + $MinuteInterval = ([TimeSpan]::FromSeconds($TimeSeconds)).Minutes; + + $CheckPerfDataLabel = [string]::Format('{0}_{1}', (Format-IcingaPerfDataLabel $CheckName), $MinuteInterval); + + if ($null -ne $ThresholdCache.$CheckPerfDataLabel) { + $InputValue = $ThresholdCache.$CheckPerfDataLabel; + $InputValue = [math]::round([decimal]$InputValue, 6); + $IcingaThresholds.TimeSpan = $MinuteInterval; + } else { + $IcingaThresholds.HasError = $TRUE; + $IcingaThresholds.ErrorMessage = [string]::Format( + 'The provided time interval "{0}{1}" which translates to "{2}m" in your "-ThresholdInterval" argument does not exist', + $TimeIndexSeparator, + $TimeIndex, + $MinuteInterval + ); + } + } + } + }#> + + [bool]$UseDynamicPercentage = $FALSE; + [hashtable]$ConvertedThreshold = Convert-IcingaPluginThresholds -Threshold $Threshold; + $Minimum = (Convert-IcingaPluginThresholds -Threshold $Minimum).Value; + $Maximum = (Convert-IcingaPluginThresholds -Threshold $Maximum).Value; + [string]$ThresholdValue = $ConvertedThreshold.Value; + $IcingaThresholds.Unit = $ConvertedThreshold.Unit; + $IcingaThresholds.IcingaThreshold = $ThresholdValue; + $TempValue = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $InputValue, $Unit))); + $InputValue = $TempValue.Value; + $TmpUnit = $TempValue.Unit; + $IcingaThresholds.RawValue = $InputValue; + $TempValue = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $BaseValue, $Unit))); + $BaseValue = $TempValue.Value; + $Unit = $TmpUnit; + $IcingaThresholds.PerfUnit = $Unit; + $IcingaThresholds.BaseValue = $BaseValue; + + if ([string]::IsNullOrEmpty($IcingaThresholds.Unit)) { + $IcingaThresholds.Unit = $Unit; + } + + # Calculate % value from base value of set + if ($null -ne $BaseValue -And $IcingaThresholds.Unit -eq '%') { + $InputValue = $InputValue / $BaseValue * 100; + $UseDynamicPercentage = $TRUE; + } elseif ($null -eq $BaseValue -And $IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.HasError = $TRUE; + $IcingaThresholds.ErrorMessage = 'This argument does not support the % unit'; + } + + # Always override our InputValue, case we might have change it + $IcingaThresholds.Value = $InputValue; + + # If we simply provide a numeric number, we always check Value > Threshold or Value < 0 + if ($Matches) { + # Checks if the InputValue Matches the Threshold + if ($InputValue -Like $ThresholdValue) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is matching threshold'; + $IcingaThresholds.Range = [string]::Format( + '{0}{1}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value $ThresholdValue), + $IcingaThresholds.Unit + ); + } + } elseif ($NotMatches) { + # Checks if the InputValue not Matches the Threshold + if ($InputValue -NotLike $ThresholdValue) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is not matching threshold'; + $IcingaThresholds.Range = [string]::Format( + '{0}{1}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value $ThresholdValue), + $IcingaThresholds.Unit + ); + } + } elseif ($IsBetween) { + if ($InputValue -gt $Minium -And $InputValue -lt $Maximum) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is inside range'; + $IcingaThresholds.Range = [string]::Format( + '{0} and {1}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $Minium -OriginalUnit $IcingaThresholds.OriginalUnit)), + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $Maximum -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({2}) {1}% ({3})', + (ConvertFrom-Percent -Value $BaseValue -Percent $Minium), + (ConvertFrom-Percent -Value $BaseValue -Percent $Maximum), + (Convert-IcingaPluginValueToString -Unit $Unit -Value $Minium -OriginalUnit $IcingaThresholds.OriginalUnit), + (Convert-IcingaPluginValueToString -Unit $Unit -Value $Maximum -OriginalUnit $IcingaThresholds.OriginalUnit) + ); + $IcingaThresholds.PercentValue = [string]::Format( + '@{0}:{1}', + (ConvertFrom-Percent -Value $BaseValue -Percent $Minium), + (ConvertFrom-Percent -Value $BaseValue -Percent $Maximum) + ); + } + } elseif ($IsLowerEqual) { + if ($InputValue -le $ThresholdValue) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is lower equal than threshold'; + $IcingaThresholds.Range = [string]::Format( + '{0}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({1})', + (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue), + (Convert-IcingaPluginValueToString -Unit $Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit) + ); + $IcingaThresholds.PercentValue = [string]::Format( + '{0}:', + (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue) + ); + } + } elseif ($IsGreaterEqual) { + if ($InputValue -ge $ThresholdValue) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is greater equal than threshold'; + $IcingaThresholds.Range = [string]::Format( + '{0}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({1})', + (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue), + (Convert-IcingaPluginValueToString -Unit $Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit) + ); + + $IcingaThresholds.PercentValue = [string]::Format( + '~:{0}', + (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue) + ); + } + } else { + if ((Test-Numeric $ThresholdValue)) { + if ($InputValue -gt $ThresholdValue -Or $InputValue -lt 0) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is greater than threshold'; + $IcingaThresholds.Range = [string]::Format('{0}', (Convert-IcingaPluginValueToString -Unit $Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit)); + } + + $IcingaThresholds.CompareValue = [decimal]$ThresholdValue; + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format('{0}% ({1})', $ThresholdValue, (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue) -OriginalUnit $IcingaThresholds.OriginalUnit)); + + $IcingaThresholds.PercentValue = [string]::Format( + '{0}', + (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue) + ); + } + } else { + # Transform our provided thresholds to split everything into single objects + [array]$thresholds = $ThresholdValue.Split(':'); + [string]$rangeMin = $thresholds[0]; + [string]$rangeMax = $thresholds[1]; + [bool]$IsNegating = $rangeMin.Contains('@'); + [string]$rangeMin = $rangeMin.Replace('@', ''); + + if ((Test-Numeric ($rangeMin.Replace('@', '').Replace('~', '')))) { + $IcingaThresholds.MinRangeValue = [decimal]($rangeMin.Replace('@', '').Replace('~', '')); + } + if ((Test-Numeric $rangeMax)) { + $IcingaThresholds.MaxRangeValue = [decimal]$rangeMax; + } + + if ($IsNegating -eq $FALSE -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) { + # Handles: 30:40 + # Error on: < 30 or > 40 + # Ok on: between {30 .. 40} + + if ($InputValue -lt $rangeMin -Or $InputValue -gt $rangeMax) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is outside range'; + $IcingaThresholds.Range = [string]::Format( + '{0} and {1}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)), + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({2}) and {1}% ({3})', + $rangeMin, + $rangeMax, + (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)), + (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + + $IcingaThresholds.PercentValue = [string]::Format( + '{0}:{1}', + (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin), + (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax) + ); + } + } elseif ((Test-Numeric $rangeMin) -And [string]::IsNullOrEmpty($rangeMax) -eq $TRUE) { + # Handles: 20: + # Error on: 20: + # Ok on: between 20 .. ∞ + + if ($InputValue -lt $rangeMin) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is lower than threshold'; + $IcingaThresholds.Range = [string]::Format( + '{0}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({1})', + $rangeMin, + (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + + $IcingaThresholds.PercentValue = [string]::Format( + '{0}:', + (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin) + ); + } + } elseif ($rangeMin -eq '~' -And (Test-Numeric $rangeMax)) { + # Handles: ~:20 + # Error on: > 20 + # Ok on: between -∞ .. 20 + + if ($InputValue -gt $rangeMax) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is greater than threshold'; + $IcingaThresholds.Range = [string]::Format( + '{0}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({1})', + $rangeMax, + (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + + $IcingaThresholds.PercentValue = [string]::Format( + '~:{0}', + (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax) + ); + } + } elseif ($IsNegating -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) { + # Handles: @30:40 + # Error on: ≥ 30 and ≤ 40 + # Ok on: -∞ .. 29 and 41 .. ∞ + + if ($InputValue -ge $rangeMin -And $InputValue -le $rangeMax) { + $IcingaThresholds.InRange = $FALSE; + $IcingaThresholds.Message = 'is inside range'; + $IcingaThresholds.Range = [string]::Format( + '{0} and {1}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)), + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + } + + if ($IcingaThresholds.Unit -eq '%') { + $IcingaThresholds.RawThreshold = [string]::Format( + '{0}% ({2}) {1}% ({3})', + $rangeMin, + $rangeMax, + (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)), + (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + + $IcingaThresholds.PercentValue = [string]::Format( + '@{0}:{1}', + (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin), + (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax) + ); + } + } else { + if ([string]::IsNullOrEmpty($Threshold) -eq $FALSE) { + # Unhandled + $IcingaThresholds.ErrorMessage = [string]::Format( + 'Invalid range specified for threshold: InputValue "{0}" and Threshold {1}', + $InputValue, + $Threshold + ); + $IcingaThresholds.HasError = $TRUE; + } + } + } + } + + $PluginOutputMessage = [System.Text.StringBuilder]::New(); + + [string]$PluginCurrentValue = [string]::Format( + '{0}', + (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $IcingaThresholds.Value -OriginalUnit $IcingaThresholds.OriginalUnit)) + ); + + [string]$PluginThresholdValue = $IcingaThresholds.Range; + + if ($UseDynamicPercentage -And $Unit -ne '%') { + $IcingaThresholds.IcingaThreshold = $IcingaThresholds.PercentValue; + $PluginCurrentValue = [string]::Format('{0}% ({1})', ([math]::Round($IcingaThresholds.Value, 2)), (Convert-IcingaPluginValueToString -Unit $Unit -Value $IcingaThresholds.RawValue -OriginalUnit $IcingaThresholds.OriginalUnit)); + $PluginThresholdValue = $IcingaThresholds.RawThreshold; + } + + $IcingaThresholds.HeaderValue = $PluginCurrentValue; + $PluginOutputMessage.Append($PluginCurrentValue) | Out-Null; + + if ([string]::IsNullOrEmpty($IcingaThresholds.Message) -eq $FALSE) { + $PluginOutputMessage.Append(' ') | Out-Null; + $PluginOutputMessage.Append($IcingaThresholds.Message) | Out-Null; + + if ([string]::IsNullOrEmpty($PluginThresholdValue) -eq $FALSE) { + $PluginOutputMessage.Append(' ') | Out-Null; + $PluginOutputMessage.Append($PluginThresholdValue) | Out-Null; + } + } + + # Lets build our full message for adding on the value + $IcingaThresholds.FullMessage = $PluginOutputMessage.ToString(); + + return $IcingaThresholds; +} diff --git a/lib/icinga/plugin/ConvertTo-IcingaPluginOutputTranslation.psm1 b/lib/icinga/plugin/ConvertTo-IcingaPluginOutputTranslation.psm1 new file mode 100644 index 0000000..9fa785d --- /dev/null +++ b/lib/icinga/plugin/ConvertTo-IcingaPluginOutputTranslation.psm1 @@ -0,0 +1,34 @@ +function ConvertTo-IcingaPluginOutputTranslation() +{ + param ( + $Value = $null, + [hashtable]$Translation = @{ } + ); + + if ($null -eq $Value) { + return 'Nothing'; + } + + if ($null -eq $Translation -Or $Translation.Count -eq 0) { + return $Value; + } + + [array]$TranslationKeys = $Translation.Keys; + [array]$TranslationValues = $Translation.Values; + [int]$Index = 0; + [bool]$FoundTranslation = $FALSE; + + foreach ($entry in $TranslationKeys) { + if (([string]($Value)).ToLower() -eq ([string]($entry)).ToLower()) { + $FoundTranslation = $TRUE; + break; + } + $Index += 1; + } + + if ($FoundTranslation -eq $FALSE) { + return $Value; + } + + return $TranslationValues[$Index]; +} diff --git a/lib/icinga/plugin/New-IcingaCheck.psm1 b/lib/icinga/plugin/New-IcingaCheck.psm1 index 313a164..4474e49 100644 --- a/lib/icinga/plugin/New-IcingaCheck.psm1 +++ b/lib/icinga/plugin/New-IcingaCheck.psm1 @@ -1,856 +1,679 @@ -Import-IcingaLib icinga\enums; -Import-IcingaLib core\tools; - function New-IcingaCheck() { param( [string]$Name = '', $Value = $null, - $Unit = $null, + $BaseValue = $null, + $Unit = '', [string]$Minimum = '', [string]$Maximum = '', $ObjectExists = -1, $Translation = $null, [string]$LabelName = $null, - [switch]$NoPerfData + [switch]$NoPerfData = $FALSE ); - $Check = New-Object -TypeName PSObject; - $Check | Add-Member -MemberType NoteProperty -Name 'name' -Value $Name; - $Check | Add-Member -MemberType NoteProperty -Name 'verbose' -Value 0; - $Check | Add-Member -MemberType NoteProperty -Name 'messages' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'oks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'warnings' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'criticals' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'unknowns' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'okchecks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'warningchecks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'criticalchecks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'unknownchecks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'value' -Value $Value; - $Check | Add-Member -MemberType NoteProperty -Name 'exitcode' -Value -1; - $Check | Add-Member -MemberType NoteProperty -Name 'unit' -Value $Unit; - $Check | Add-Member -MemberType NoteProperty -Name 'spacing' -Value 0; - $Check | Add-Member -MemberType NoteProperty -Name 'compiled' -Value $FALSE; - $Check | Add-Member -MemberType NoteProperty -Name 'perfdata' -Value (-Not $NoPerfData); - $Check | Add-Member -MemberType NoteProperty -Name 'warning' -Value ''; - $Check | Add-Member -MemberType NoteProperty -Name 'critical' -Value ''; - $Check | Add-Member -MemberType NoteProperty -Name 'minimum' -Value $Minimum; - $Check | Add-Member -MemberType NoteProperty -Name 'maximum' -Value $Maximum; - $Check | Add-Member -MemberType NoteProperty -Name 'objectexists' -Value $ObjectExists; - $Check | Add-Member -MemberType NoteProperty -Name 'translation' -Value $Translation; - $Check | Add-Member -MemberType NoteProperty -Name 'labelname' -Value $LabelName; - $Check | Add-Member -MemberType NoteProperty -Name 'checks' -Value $null; - $Check | Add-Member -MemberType NoteProperty -Name 'completed' -Value $FALSE; - $Check | Add-Member -MemberType NoteProperty -Name 'checkcommand' -Value ''; - $Check | Add-Member -MemberType NoteProperty -Name 'checkpackage' -Value $FALSE; + $IcingaCheck = New-IcingaCheckBaseObject; - $Check | Add-Member -MemberType ScriptMethod -Name 'HandleDaemon' -Value { - # Only apply this once the checkcommand is set - if ([string]::IsNullOrEmpty($this.checkcommand) -Or $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) { - return; - } + $IcingaCheck.Name = $Name; + $IcingaCheck.__ObjectType = 'IcingaCheck'; - if ($null -eq $global:Icinga -Or $global:Icinga.ContainsKey('CheckData') -eq $FALSE) { - return; - } + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Value' -Value $Value; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'BaseValue' -Value $BaseValue; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Unit' -Value $Unit; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Minimum' -Value $Minimum; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Maximum' -Value $Maximum; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'ObjectExists' -Value $ObjectExists; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Translation' -Value $Translation; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'LabelName' -Value $LabelName; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name 'NoPerfData' -Value $NoPerfData; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name '__WarningValue' -Value $null; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name '__CriticalValue' -Value $null; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name '__LockedState' -Value $FALSE; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name '__ThresholdObject' -Value $null; + $IcingaCheck | Add-Member -MemberType NoteProperty -Name '__TimeInterval' -Value $null; - if ($global:Icinga.CheckData.ContainsKey($this.checkcommand)) { - if ($global:Icinga.CheckData[$this.checkcommand]['results'].ContainsKey($this.name) -eq $FALSE) { - $global:Icinga.CheckData[$this.checkcommand]['results'].Add( - $this.name, - @{ } - ); + $IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__SetInternalTimeInterval' -Value { + $CallStack = Get-PSCallStack; + [bool]$FoundInterval = $FALSE; + + foreach ($entry in $CallStack) { + if ($FoundInterval) { + break; } - - # Fix possible error for identical time stamps due to internal exceptions - # and check execution within the same time slot because of this - [string]$TimeIndex = Get-IcingaUnixTime; - - if ($global:Icinga.CheckData[$this.checkcommand]['results'][$this.name].ContainsKey($TimeIndex)) { - return; - } - - $global:Icinga.CheckData[$this.checkcommand]['results'][$this.name].Add( - $TimeIndex, - $this.value - ); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddSpacing' -Value { - $this.spacing += 1; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AssignCheckCommand' -Value { - param($CheckCommand); - - $this.checkcommand = $CheckCommand; - $this.HandleDaemon(); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetWarnings' -Value { - return $this.warningchecks; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetCriticals' -Value { - return $this.criticalchecks; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetUnknowns' -Value { - return $this.unknownchecks; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'SetUnknown' -Value { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Unknown, - $null, - $null - ); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'SetWarning' -Value { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $null, - $null - ); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnOutOfRange' -Value { - param($warning); - - if ([string]::IsNullOrEmpty($warning)) { - return $this; - } - - if ((Test-Numeric $warning)) { - $this.WarnIfGreaterThan($warning).WarnIfLowerThan(0) | Out-Null; - } else { - [array]$thresholds = $warning.Split(':'); - [string]$rangeMin = $thresholds[0]; - [string]$rangeMax = $thresholds[1]; - $negate = $rangeMin.Contains('@'); - $rangeMin = $rangeMin.Replace('@', ''); - if (-Not $negate -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) { - $this.WarnIfLowerThan($rangeMin).WarnIfGreaterThan($rangeMax) | Out-Null; - } elseif ((Test-Numeric $rangeMin) -And [string]::IsNullOrEmpty($rangeMax) -eq $TRUE) { - $this.WarnIfLowerThan($rangeMin) | Out-Null; - } elseif ($rangeMin -eq '~' -And (Test-Numeric $rangeMax)) { - $this.WarnIfGreaterThan($rangeMax) | Out-Null; - } elseif ($negate -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) { - $this.WarnIfBetweenAndEqual($rangeMin, $rangeMax) | Out-Null; - } else { - $this.AddMessage( - [string]::Format( - 'Invalid range specified for Warning argument: "{0}" of check {1}', - $warning, - $this.name - ), - $IcingaEnums.IcingaExitCode.Unknown - ) - $this.exitcode = $IcingaEnums.IcingaExitCode.Unknown; - return $this; - } - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfLike' -Value { - param($warning); - - if ($this.value -Like $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'like' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotLike' -Value { - param($warning); - - if (-Not ($this.value -Like $warning)) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'not like' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfMatch' -Value { - param($warning); - - if ($this.value -eq $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'matching' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotMatch' -Value { - param($warning); - - if ($this.value -ne $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'not matching' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfBetweenAndEqual' -Value { - param($min, $max); - - if ($this.value -ge $min -And $this.value -le $max) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - [string]::Format('{0}:{1}', $min, $max), - 'between' - ); - } - - $this.warning = [string]::Format('{0}:{1}', $min, $max); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfBetween' -Value { - param($min, $max); - - if ($this.value -gt $min -And $this.value -lt $max) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - [string]::Format('{0}:{1}', $min, $max), - 'between' - ); - } - - $this.warning = [string]::Format('{0}:{1}', $min, $max); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerThan' -Value { - param($warning); - - if ($this.value -lt $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'lower than' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerEqualThan' -Value { - param($warning); - - if ($this.value -le $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'lower or equal than' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterThan' -Value { - param($warning); - - if ($this.value -gt $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'greater than' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterEqualThan' -Value { - param($warning); - - if ($this.value -ge $warning) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Warning, - $warning, - 'greater or equal than' - ); - } - - $this.warning = $warning; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'SetCritical' -Value { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $null, - $null - ); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritOutOfRange' -Value { - param($critical); - - if ([string]::IsNullOrEmpty($critical)) { - return $this; - } - - if ((Test-Numeric $critical)) { - $this.CritIfGreaterThan($critical).CritIfLowerThan(0) | Out-Null; - } else { - [array]$thresholds = $critical.Split(':'); - [string]$rangeMin = $thresholds[0]; - [string]$rangeMax = $thresholds[1]; - $negate = $rangeMin.Contains('@'); - $rangeMin = $rangeMin.Replace('@', ''); - if (-Not $negate -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) { - $this.CritIfLowerThan($rangeMin).CritIfGreaterThan($rangeMax) | Out-Null; - } elseif ((Test-Numeric $rangeMin) -And [string]::IsNullOrEmpty($rangeMax) -eq $TRUE) { - $this.CritIfLowerThan($rangeMin) | Out-Null; - } elseif ($rangeMin -eq '~' -And (Test-Numeric $rangeMax)) { - $this.CritIfGreaterThan($rangeMax) | Out-Null; - } elseif ($negate -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) { - $this.CritIfBetweenAndEqual($rangeMin, $rangeMax) | Out-Null; - } else { - $this.AddMessage( - [string]::Format( - 'Invalid range specified for Critical argument: "{0}" of check {1}', - $critical, - $this.name - ), - $IcingaEnums.IcingaExitCode.Unknown - ) - $this.exitcode = $IcingaEnums.IcingaExitCode.Unknown; - return $this; - } - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfLike' -Value { - param($critical); - - if ($this.value -Like $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'like' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfNotLike' -Value { - param($critical); - - if (-Not ($this.value -Like $critical)) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'not like' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfMatch' -Value { - param($critical); - - if ($this.value -eq $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'matching' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfNotMatch' -Value { - param($critical); - - if ($this.value -ne $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'not matching' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfBetweenAndEqual' -Value { - param($min, $max); - - if ($this.value -ge $min -And $this.value -le $max) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - [string]::Format('{0}:{1}', $min, $max), - 'between' - ); - } - - $this.critical = [string]::Format('{0}:{1}', $min, $max); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfBetween' -Value { - param($min, $max); - - if ($this.value -gt $min -And $this.value -lt $max) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - [string]::Format('{0}:{1}', $min, $max), - 'between' - ); - } - - $this.critical = [string]::Format('{0}:{1}', $min, $max); - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerThan' -Value { - param($critical); - - if ($this.value -lt $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'lower than' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerEqualThan' -Value { - param($critical); - - if ($this.value -le $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'lower or equal than' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterThan' -Value { - param($critical); - - if ($this.value -gt $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'greater than' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterEqualThan' -Value { - param($critical); - - if ($this.value -ge $critical) { - $this.AddInternalCheckMessage( - $IcingaEnums.IcingaExitCode.Critical, - $critical, - 'greater or equal than' - ); - } - - $this.critical = $critical; - - return $this; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'TranslateValue' -Value { - param($value); - - $value = Format-IcingaPerfDataValue $value; - - if ($null -eq $this.translation -Or $null -eq $value) { - return $value; - } - - $checkValue = $value; - - if ((Test-Numeric $checkValue)) { - $checkValue = [int]$checkValue; - } else { - $checkValue = [string]$checkValue; - } - - if ($this.translation.ContainsKey($checkValue)) { - return $this.translation[$checkValue]; - } - - return $value; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddInternalCheckMessage' -Value { - param($state, $value, $type); - - if ($this.objectexists -ne -1 -And $null -eq $this.objectexists) { - $this.SetExitCode($IcingaEnums.IcingaExitCode.Unknown); - $this.AddMessage( - [string]::Format( - '{0} does not exist', $this.name - ), - $IcingaEnums.IcingaExitCode.Unknown - ); - return; - } - - $this.SetExitCode($state); - - if ($null -eq $value -And $null -eq $type) { - $this.AddMessage( - $this.name, - $state - ); - } else { - $this.AddMessage( - [string]::Format( - '{0}: Value "{1}{4}" is {2} threshold "{3}{4}"', - $this.name, - $this.TranslateValue($this.value), - $type, - $this.TranslateValue($value), - $this.unit - ), - $state - ); - } - - switch ($state) { - $IcingaEnums.IcingaExitCode.Warning { - $this.warning = $value; - break; - }; - $IcingaEnums.IcingaExitCode.Critical { - $this.critical = $value; - break; - }; - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddMessage' -Value { - param($message, [int]$exitcode); - - [string]$outputMessage = [string]::Format( - '{0} {1}', - $IcingaEnums.IcingaExitCodeText[$exitcode], - $message - ); - $this.messages += $outputMessage; - - switch ([int]$exitcode) { - $IcingaEnums.IcingaExitCode.Ok { - $this.oks += $outputMessage; - break; - }; - $IcingaEnums.IcingaExitCode.Warning { - $this.warnings += $outputMessage; - break; - }; - $IcingaEnums.IcingaExitCode.Critical { - $this.criticals += $outputMessage; - break; - }; - $IcingaEnums.IcingaExitCode.Unknown { - $this.unknowns += $outputMessage; - break; - }; - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddCheckStateArrays' -Value { - switch ([int]$this.exitcode) { - $IcingaEnums.IcingaExitCode.Ok { - $this.okchecks += $this.name; - break; - }; - $IcingaEnums.IcingaExitCode.Warning { - $this.warningchecks += $this.name; - break; - }; - $IcingaEnums.IcingaExitCode.Critical { - $this.criticalchecks += $this.name; - break; - }; - $IcingaEnums.IcingaExitCode.Unknown { - $this.unknownchecks += $this.name; - break; - }; - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintOkMessages' -Value { - param([string]$spaces); - $this.OutputMessageArray($this.oks, $spaces); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintWarningMessages' -Value { - param([string]$spaces); - $this.OutputMessageArray($this.warnings, $spaces); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintCriticalMessages' -Value { - param([string]$spaces); - $this.OutputMessageArray($this.criticals, $spaces); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintUnknownMessages' -Value { - param([string]$spaces); - $this.OutputMessageArray($this.unknowns, $spaces); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintAllMessages' -Value { - [string]$spaces = New-StringTree $this.spacing; - $this.OutputMessageArray($this.unknowns, $spaces); - $this.OutputMessageArray($this.criticals, $spaces); - $this.OutputMessageArray($this.warnings, $spaces); - $this.OutputMessageArray($this.oks, $spaces); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'OutputMessageArray' -Value { - param($msgArray, [string]$spaces); - - foreach ($msg in $msgArray) { - Write-IcingaPluginOutput ([string]::Format('{0}{1}', $spaces, $msg)); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintOutputMessages' -Value { - [string]$spaces = New-StringTree $this.spacing; - if ($this.unknowns.Count -ne 0) { - $this.PrintUnknownMessages($spaces); - } elseif ($this.criticals.Count -ne 0) { - $this.PrintCriticalMessages($spaces); - } elseif ($this.warnings.Count -ne 0) { - $this.PrintWarningMessages($spaces); - } else { - if ($this.oks.Count -ne 0) { - $this.PrintOkMessages($spaces); - } - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'SetExitCode' -Value { - param([int]$code); - - # Only overwrite the exit code in case our new value is greater then - # the current one Ok > Warning > Critical - if ([int]$this.exitcode -gt $code) { - return $this; - } - - switch ($code) { - 0 { break; }; - 1 { - $this.oks = @(); - break; - }; - 2 { - $this.oks = @(); - $this.warnings = @(); - break; - }; - 3 { - $this.oks = @(); - $this.warnings = @(); - $this.criticals = @(); - break; - }; - } - - $this.exitcode = $code; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'ValidateUnit' -Value { - if ($null -ne $this.unit -And (-Not $IcingaEnums.IcingaMeasurementUnits.ContainsKey($this.unit))) { - $this.AddMessage( - [string]::Format( - 'Error on check "{0}": Usage of invalid plugin unit "{1}". Allowed units are: {2}', - $this.name, - $this.unit, - (($IcingaEnums.IcingaMeasurementUnits.Keys | Sort-Object name) -Join ', ') - ), - $IcingaEnums.IcingaExitCode.Unknown - ) - $this.unit = ''; - $this.exitcode = $IcingaEnums.IcingaExitCode.Unknown; - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddOkOutput' -Value { - if ([int]$this.exitcode -eq -1) { - $this.exitcode = $IcingaEnums.IcingaExitCode.Ok; - $this.AddMessage( - [string]::Format( - '{0}: {1}{2}', - $this.name, - $this.TranslateValue($this.value), - $this.unit - ), - $IcingaEnums.IcingaExitCode.Ok - ); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'SilentCompile' -Value { - if ($this.compiled) { - return; - } - - $this.AddOkOutput(); - $this.compiled = $TRUE; - $this.AddCheckStateArrays(); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value { - param([bool]$Verbose = $FALSE); - - if ($this.compiled) { - return; - } - - $this.AddOkOutput(); - $this.compiled = $TRUE; - - if ($Verbose) { - $this.PrintOutputMessages(); - } - - $this.AddCheckStateArrays(); - - return $this.exitcode; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetPerfData' -Value { - - if ($this.completed -Or -Not $this.perfdata) { - return $null; - } - - $this.AutodiscoverMinMax(); - - $this.completed = $TRUE; - [string]$LabelName = (Format-IcingaPerfDataLabel $this.name); - $value = ConvertTo-Integer -Value $this.value -NullAsEmpty; - $warning = ConvertTo-Integer -Value $this.warning -NullAsEmpty; - $critical = ConvertTo-Integer -Value $this.critical -NullAsEmpty; - - if ([string]::IsNullOrEmpty($this.labelname) -eq $FALSE) { - $LabelName = $this.labelname; - } - - $perfdata = @{ - 'label' = $LabelName; - 'perfdata' = ''; - 'unit' = $this.unit; - 'value' = (Format-IcingaPerfDataValue $value); - 'warning' = (Format-IcingaPerfDataValue $warning); - 'critical' = (Format-IcingaPerfDataValue $critical); - 'minimum' = (Format-IcingaPerfDataValue $this.minimum); - 'maximum' = (Format-IcingaPerfDataValue $this.maximum); - 'package' = $FALSE; - }; - - return $perfdata; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AutodiscoverMinMax' -Value { - if ([string]::IsNullOrEmpty($this.minimum) -eq $FALSE -Or [string]::IsNullOrEmpty($this.maximum) -eq $FALSE) { - return; - } - - switch ($this.unit) { - '%' { - $this.minimum = '0'; - $this.maximum = '100'; - if ($this.value -gt $this.maximum) { - $this.maximum = $this.value + [string]$CheckCommand = $entry.Command; + if ($CheckCommand -eq $this.__CheckCommand) { + [string]$CheckArguments = $entry.Arguments.Replace('{', '').Replace('}', ''); + [array]$SplitArgs = $CheckArguments.Split(','); + + foreach ($SetArg in $SplitArgs) { + $SetArg = $SetArg.Replace(' ', ''); + if ($FoundInterval) { + $this.__TimeInterval = $SetArg; + break; + } + if ($SetArg -eq '-ThresholdInterval') { + $FoundInterval = $TRUE; + continue; + } } break; } } } - $Check.ValidateUnit(); - $Check.HandleDaemon(); + # Override shared function + $IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__GetHeaderOutputValue' -Value { + if ($null -eq $this.__ThresholdObject) { + return '' + } - return $Check; + if ([string]::IsNullOrEmpty($this.__ThresholdObject.HeaderValue)) { + return ''; + } + + return ( + [string]::Format( + ' ({0})', + $this.__ThresholdObject.HeaderValue + ) + ) + } + + # Override shared function + $IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__SetCheckOutput' -Value { + param ($PluginOutput); + + if ($this.__InLockState()) { + return; + } + + $PluginThresholds = ''; + $TimeSpan = ''; + + if ($null -ne $this.__ThresholdObject) { + $PluginThresholds = $this.__ThresholdObject.FullMessage; + } elseif ($null -ne $this.Value) { + # In case we simply added a value to a check and not did anything with it, output the raw value properly formatted like anything else + $PluginThresholds = (ConvertTo-IcingaPluginOutputTranslation -Translation $this.Translation -Value (Convert-IcingaPluginValueToString -Unit $this.Unit -Value $this.Value)); + } + + if ([string]::IsNullOrEmpty($PluginOutput) -eq $FALSE) { + $PluginThresholds = $PluginOutput; + } + + if ($null -ne $this.__ThresholdObject -And [string]::IsNullOrEmpty($this.__ThresholdObject.TimeSpan) -eq $FALSE) { + $TimeSpan = [string]::Format( + '{0}({1}m avg.)', + (&{ if ([string]::IsNullOrEmpty($PluginThresholds)) { return ''; } else { return ' ' } }), + $this.__ThresholdObject.TimeSpan + ); + } + + $this.__CheckOutput = [string]::Format( + '{0} {1}: {2}{3}', + $IcingaEnums.IcingaExitCodeText[$this.__CheckState], + $this.Name, + $PluginThresholds, + $TimeSpan + ); + + $this.__SetPerformanceData(); + } + + # __GetTimeSpanThreshold(0, 'Core_30_20', 'Core_30') + $IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__GetTimeSpanThreshold' -Value { + param ($TimeSpanLabel, $Label); + + [hashtable]$TimeSpans = @{ + 'Warning' = ''; + 'Critical' = ''; + } + + [string]$LabelName = (Format-IcingaPerfDataLabel $this.Name); + if ([string]::IsNullOrEmpty($this.LabelName) -eq $FALSE) { + $LabelName = $this.LabelName; + } + + if ($Label -ne $LabelName) { + return $TimeSpans; + } + + $TimeSpan = $TimeSpanLabel.Replace($Label, '').Replace('_', ''); + + if ($null -ne $this.__WarningValue -And [string]::IsNullOrEmpty($this.__WarningValue.TimeSpan) -eq $FALSE -And $this.__WarningValue.TimeSpan -eq $TimeSpan) { + $TimeSpans.Warning = $this.__WarningValue.IcingaThreshold; + } + if ($null -ne $this.__CriticalValue -And [string]::IsNullOrEmpty($this.__CriticalValue.TimeSpan) -eq $FALSE -And $this.__CriticalValue.TimeSpan -eq $TimeSpan) { + $TimeSpans.Critical = $this.__CriticalValue.IcingaThreshold; + } + + return $TimeSpans; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__GetWarningThresholdObject' -Value { + return $this.__WarningValue; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__GetCriticalThresholdObject' -Value { + return $this.__CriticalValue; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__SetPerformanceData' -Value { + if ($null -eq $this.__ThresholdObject -Or $this.NoPerfData) { + return; + } + + [string]$LabelName = (Format-IcingaPerfDataLabel $this.Name); + $value = ConvertTo-Integer -Value $this.__ThresholdObject.RawValue -NullAsEmpty; + $warning = ''; + $critical = ''; + + # Set our threshold to nothing if we use time spans, as it would cause performance metrics to + # contain warning/critical values for everything, which is not correct + if ([string]::IsNullOrEmpty($this.__WarningValue.TimeSpan)) { + $warning = ConvertTo-Integer -Value $this.__WarningValue.IcingaThreshold -NullAsEmpty; + } + if ([string]::IsNullOrEmpty($this.__CriticalValue.TimeSpan)) { + $critical = ConvertTo-Integer -Value $this.__CriticalValue.IcingaThreshold -NullAsEmpty; + } + + if ([string]::IsNullOrEmpty($this.LabelName) -eq $FALSE) { + $LabelName = $this.LabelName; + } + + if ([string]::IsNullOrEmpty($this.Minimum) -And [string]::IsNullOrEmpty($this.Maximum)) { + if ($this.Unit -eq '%') { + $this.Minimum = '0'; + $this.Maximum = '100'; + } elseif ($null -ne $this.BaseValue) { + $this.Minimum = '0'; + $this.Maximum = $this.__ThresholdObject.BaseValue; + } + + if ($this.Value -gt $this.Maximum) { + $this.Maximum = $this.__ThresholdObject.RawValue; + } + } + + $this.__CheckPerfData = @{ + 'label' = $LabelName; + 'perfdata' = ''; + 'unit' = $this.__ThresholdObject.PerfUnit; + 'value' = (Format-IcingaPerfDataValue $value); + 'warning' = (Format-IcingaPerfDataValue $warning); + 'critical' = (Format-IcingaPerfDataValue $critical); + 'minimum' = (Format-IcingaPerfDataValue $this.Minimum); + 'maximum' = (Format-IcingaPerfDataValue $this.Maximum); + 'package' = $FALSE; + }; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ValidateObject' -Value { + if ($null -eq $this.ObjectExists) { + $this.SetUnknown() | Out-Null; + $this.__SetCheckOutput('The object does not exist'); + $this.__LockState(); + } + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__LockState' -Value { + $this.__LockedState = $TRUE; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__InLockState' -Value { + return $this.__LockedState; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ValidateUnit' -Value { + if ([string]::IsNullOrEmpty($this.Unit) -eq $FALSE -And (-Not $IcingaEnums.IcingaMeasurementUnits.ContainsKey($this.Unit))) { + $this.SetUnknown(); + $this.__SetCheckOutput( + [string]::Format( + 'Usage of invalid plugin unit "{0}". Allowed units are: {1}', + $this.Unit, + (($IcingaEnums.IcingaMeasurementUnits.Keys | Sort-Object name) -Join ', ') + ) + ); + + $this.__LockState(); + $this.unit = $null; + } + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ConvertMinMax' -Value { + if ([string]::IsNullOrEmpty($this.Unit) -eq $FALSE) { + if ([string]::IsNullOrEmpty($this.Minimum) -eq $FALSE) { + $this.Minimum = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $this.Minimum, $this.Unit))).Value; + } + if ([string]::IsNullOrEmpty($this.Maximum) -eq $FALSE) { + $this.Maximum = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $this.Maximum, $this.Unit))).Value; + } + } + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__AddCheckDataToCache' -Value { + + # We only require this in case we are running as daemon + if ([string]::IsNullOrEmpty($this.__CheckCommand) -Or $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) { + return; + } + + # If no check table has been created, do nothing + if ($null -eq $global:Icinga -Or $global:Icinga.ContainsKey('CheckData') -eq $FALSE) { + return; + } + + if ($global:Icinga.CheckData.ContainsKey($this.__CheckCommand) -eq $FALSE) { + return; + } + + # Fix possible error for identical time stamps due to internal exceptions + # and check execution within the same time slot because of this + [string]$TimeIndex = Get-IcingaUnixTime; + + Add-IcingaHashtableItem -Hashtable $global:Icinga.CheckData[$this.__CheckCommand]['results'] -Key $this.Name -Value @{ } | Out-Null; + Add-IcingaHashtableItem -Hashtable $global:Icinga.CheckData[$this.__CheckCommand]['results'][$this.Name] -Key $TimeIndex -Value $this.Value -Override | Out-Null; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetOk' -Value { + param ([string]$Message, [bool]$Lock); + + if ($this.__InLockState() -eq $FALSE) { + $this.__CheckState = $IcingaEnums.IcingaExitCode.Ok; + $this.__SetCheckOutput($Message); + } + + if ($Lock) { + $this.__LockState(); + } + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetWarning' -Value { + param ([string]$Message, [bool]$Lock); + + if ($this.__InLockState() -eq $FALSE) { + $this.__CheckState = $IcingaEnums.IcingaExitCode.Warning; + $this.__SetCheckOutput($Message); + } + + if ($Lock) { + $this.__LockState(); + } + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetCritical' -Value { + param ([string]$Message, [bool]$Lock); + + if ($this.__InLockState() -eq $FALSE) { + $this.__CheckState = $IcingaEnums.IcingaExitCode.Critical; + $this.__SetCheckOutput($Message); + } + + if ($Lock) { + $this.__LockState(); + } + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetUnknown' -Value { + param ([string]$Message, [bool]$Lock); + + if ($this.__InLockState() -eq $FALSE) { + $this.__CheckState = $IcingaEnums.IcingaExitCode.Unknown; + $this.__SetCheckOutput($Message); + } + + if ($Lock) { + $this.__LockState(); + } + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__SetCheckState' -Value { + param ($ThresholdObject, $State); + + if ($ThresholdObject.HasError) { + $this.SetUnknown() | Out-Null; + $this.__ThresholdObject = $ThresholdObject; + $this.__SetCheckOutput($this.__ThresholdObject.ErrorMessage); + $this.__LockState(); + return; + } + + if ($this.__InLockState()) { + return; + } + + # In case no thresholds are set, always set the first value + if ($null -eq $this.__ThresholdObject) { + $this.__ThresholdObject = $ThresholdObject; + } + + if ($ThresholdObject.InRange -eq $FALSE) { + if ($this.__CheckState -lt $State) { + $this.__CheckState = $State; + $this.__ThresholdObject = $ThresholdObject; + } + } + + $this.__SetCheckOutput(); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__GetBaseThresholdArguments' -Value { + return @{ + '-InputValue' = $this.Value; + '-BaseValue' = $this.BaseValue; + '-Unit' = $this.Unit; + '-CheckName' = $this.__GetName(); + '-ThresholdCache' = $Global:Icinga.ThresholdCache[$this.__CheckCommand]; + '-Translation' = $this.Translation; + '-TimeInterval' = $this.__TimeInterval; + }; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnOutOfRange' -Value { + param ($Threshold); + + [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 'WarnIfLike' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-Matches', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__WarningValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotLike' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-NotMatches', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__WarningValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfMatch' -Value { + param ($Threshold); + + return $this.WarnIfLike($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotMatch' -Value { + param ($Threshold); + + return $this.WarnIfNotLike($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritOutOfRange' -Value { + param ($Threshold); + + [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 'CritIfLike' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-Matches', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__CriticalValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfNotLike' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-NotMatches', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__CriticalValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfMatch' -Value { + param ($Threshold); + + return $this.CritIfLike($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfNotMatch' -Value { + param ($Threshold); + + return $this.CritIfNotLike($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfBetweenAndEqual' -Value { + param ($Min, $Max); + + [string]$Threshold = [string]::Format('@{0}:{1}', $Min, $Max); + + return $this.WarnOutOfRange($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfBetweenAndEqual' -Value { + param ($Min, $Max); + + [string]$Threshold = [string]::Format('@{0}:{1}', $Min, $Max); + + return $this.CritOutOfRange($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerThan' -Value { + param ($Value); + + [string]$Threshold = [string]::Format('{0}:', $Value); + + return $this.WarnOutOfRange($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerThan' -Value { + param ($Value); + + [string]$Threshold = [string]::Format('{0}:', $Value); + + return $this.CritOutOfRange($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterThan' -Value { + param ($Value); + + [string]$Threshold = [string]::Format('~:{0}', $Value); + + return $this.WarnOutOfRange($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterThan' -Value { + param ($Value); + + [string]$Threshold = [string]::Format('~:{0}', $Value); + + return $this.CritOutOfRange($Threshold); + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfBetween' -Value { + param ($Min, $Max); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Minimum', $Min); + $ThresholdArguments.Add('-Maximum', $Max); + $ThresholdArguments.Add('-IsBetween', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__WarningValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfBetween' -Value { + param ($Min, $Max); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Minimum', $Min); + $ThresholdArguments.Add('-Maximum', $Max); + $ThresholdArguments.Add('-IsBetween', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__CriticalValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerEqualThan' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-IsLowerEqual', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__WarningValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerEqualThan' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-IsLowerEqual', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__CriticalValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterEqualThan' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-IsGreaterEqual', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__WarningValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterEqualThan' -Value { + param ($Threshold); + + [hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments(); + $ThresholdArguments.Add('-Threshold', $Threshold); + $ThresholdArguments.Add('-IsGreaterEqual', $TRUE); + + $ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments; + + $this.__CriticalValue = $ThresholdObject; + $this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical); + + return $this; + } + + $IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__ValidateThresholdInput' -Value { + if ($null -eq $this.__WarningValue -Or $null -eq $this.__CriticalValue) { + return; + } + + [bool]$OutOfRange = $FALSE; + + #Handles 20 + if ($null -ne $this.__WarningValue.CompareValue -And $null -ne $this.__CriticalValue.CompareValue) { + if ($this.__WarningValue.CompareValue -gt $this.__CriticalValue.CompareValue) { + $OutOfRange = $TRUE; + } + } + + # Handles: @30:40 and 30:40 + # Never throw an "error" here, as these ranges can be dynamic + if ($null -ne $this.__WarningValue.MinRangeValue -And $null -ne $this.__CriticalValue.MinRangeValue -And $null -ne $this.__WarningValue.MaxRangeValue -And $null -ne $this.__CriticalValue.MaxRangeValue) { + return; + } + + # Handles: 20: + if ($null -ne $this.__WarningValue.MinRangeValue -And $null -ne $this.__CriticalValue.MinRangeValue -And $null -eq $this.__WarningValue.MaxRangeValue -And $null -eq $this.__CriticalValue.MaxRangeValue) { + if ($this.__WarningValue.MinRangeValue -lt $this.__CriticalValue.MinRangeValue) { + $OutOfRange = $TRUE; + } + } + + # Handles: ~:20 + if ($null -eq $this.__WarningValue.MinRangeValue -And $null -eq $this.__CriticalValue.MinRangeValue -And $null -ne $this.__WarningValue.MaxRangeValue -And $null -ne $this.__CriticalValue.MaxRangeValue) { + if ($this.__WarningValue.MaxRangeValue -gt $this.__CriticalValue.MaxRangeValue) { + $OutOfRange = $TRUE; + } + } + + if ($OutOfRange) { + $this.SetUnknown([string]::Format('Warning threshold range "{0}" is greater than Critical threshold range "{1}"', $this.__WarningValue.RawThreshold, $this.__CriticalValue.RawThreshold), $TRUE) | Out-Null; + } + } + + $IcingaCheck.__ValidateObject(); + $IcingaCheck.__ValidateUnit(); + $IcingaCheck.__AddCheckDataToCache(); + $IcingaCheck.__SetInternalTimeInterval(); + $IcingaCheck.__ConvertMinMax(); + + return $IcingaCheck; } diff --git a/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 b/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 new file mode 100644 index 0000000..f8ea1c7 --- /dev/null +++ b/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 @@ -0,0 +1,189 @@ +function New-IcingaCheckBaseObject() +{ + $IcingaCheckBaseObject = New-Object -TypeName PSObject; + + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name 'Name' -Value ''; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name 'Verbose' -Value 0; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckPerfData' -Value @{ }; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__Hidden' -Value $FALSE; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__Parent' -Value $IcingaCheckBaseObject; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__Indention' -Value 0; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__ErrorMessage' -Value ''; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckState' -Value $IcingaEnums.IcingaExitCode.Ok; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckCommand' -Value ''; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckOutput' -Value $null; + $IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__ObjectType' -Value 'IcingaCheckBaseObject'; + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetCheckCommand' -Value { + $CallStack = Get-PSCallStack; + + foreach ($entry in $CallStack) { + [string]$CheckCommand = $entry.Command; + if ($CheckCommand.ToLower() -Like 'invoke-icingacheck*') { + $this.__CheckCommand = $CheckCommand; + break; + } + } + + if ($null -eq $Global:Icinga) { + $Global:Icinga = @{ }; + } + + if ($Global:Icinga.ContainsKey('ThresholdCache') -eq $FALSE) { + $Global:Icinga.Add('ThresholdCache', @{ }); + } + + if ($Global:Icinga.ThresholdCache.ContainsKey($this.__CheckCommand)) { + return; + } + + $Global:Icinga.ThresholdCache.Add( + $this.__CheckCommand, + (Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $this.__CheckCommand) + ); + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetParent' -Value { + param ($Parent); + + $this.__Parent = $Parent; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetParent' -Value { + return $this.__Parent; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__IsHidden' -Value { + return $this.__Hidden; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetHidden' -Value { + param ([bool]$Hidden); + + $this.__Hidden = $Hidden; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetName' -Value { + return $this.Name; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetIndention' -Value { + param ($Indention); + + $this.__Indention = $Indention; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetIndention' -Value { + return $this.__Indention; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__NewIndention' -Value { + return ($this.__Indention + 1); + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetCheckState' -Value { + return $this.__CheckState; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetCheckCommand' -Value { + return $this.__CheckCommand; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Force -Name '__SetCheckOutput' -Value { + param ($PluginOutput); + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetCheckOutput' -Value { + + if ($this.__IsHidden()) { + return '' + }; + + if ($this._CanOutput() -eq $FALSE) { + return ''; + } + + return ( + [string]::Format( + '{0}{1}', + (New-StringTree -Spacing $this.__GetIndention()), + $this.__CheckOutput + ) + ); + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value { + $this.__ValidateThresholdInput(); + $this.__SetCheckOutput(); + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetVerbosity' -Value { + param ($Verbosity); + + $this.Verbose = $Verbosity; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetVerbosity' -Value { + return $this.Verbose; + } + + # Shared function + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetHeaderOutputValue' -Value { + return ''; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '_CanOutput' -Value { + # Always allow the output of the top parent elements + if ($this.__GetIndention() -eq 0) { + return $TRUE; + } + + switch ($this.Verbose) { + 0 { # Only print states not being OK + if ($this.__CheckState -ne $IcingaEnums.IcingaExitCode.Ok) { + return $TRUE; + } + + if ($this.__ObjectType -eq 'IcingaCheckPackage') { + return $this.__HasNotOkChecks(); + } + + return $FALSE; + }; + 1 { # Print states not being OK and all content of affected check packages + if ($this.__CheckState -ne $IcingaEnums.IcingaExitCode.Ok) { + return $TRUE; + } + + if ($this.__ObjectType -eq 'IcingaCheckPackage') { + return $this.__HasNotOkChecks(); + } + + if ($this.__GetParent().__ObjectType -eq 'IcingaCheckPackage') { + return $this.__GetParent().__HasNotOkChecks(); + } + + return $FALSE; + }; + } + + # For any other verbosity, print everything + return $TRUE; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetPerformanceData' -Value { + return $this.__CheckPerfData; + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__ValidateThresholdInput' -Value { + # Shared function + } + + $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name 'HasChecks' -Value { + # Shared function + } + + $IcingaCheckBaseObject.__SetCheckCommand(); + + return $IcingaCheckBaseObject; +} diff --git a/lib/icinga/plugin/New-IcingaCheckPackage.psm1 b/lib/icinga/plugin/New-IcingaCheckPackage.psm1 index 4081e4e..57bae1c 100644 --- a/lib/icinga/plugin/New-IcingaCheckPackage.psm1 +++ b/lib/icinga/plugin/New-IcingaCheckPackage.psm1 @@ -1,456 +1,342 @@ -Import-IcingaLib icinga\enums; -Import-IcingaLib core\tools; - function New-IcingaCheckPackage() { - param( - [string]$Name, - [switch]$OperatorAnd, - [switch]$OperatorOr, - [switch]$OperatorNone, + param ( + [string]$Name = '', + [switch]$OperatorAnd = $FALSE, + [switch]$OperatorOr = $FALSE, + [switch]$OperatorNone = $FALSE, [int]$OperatorMin = -1, [int]$OperatorMax = -1, [array]$Checks = @(), [int]$Verbose = 0, [switch]$IgnoreEmptyPackage = $FALSE, - [switch]$Hidden = $FALSE + [switch]$Hidden = $FALSE, + [switch]$AddSummaryHeader = $FALSE ); - $Check = New-Object -TypeName PSObject; - $Check | Add-Member -MemberType NoteProperty -Name 'name' -Value $Name; - $Check | Add-Member -MemberType NoteProperty -Name 'exitcode' -Value -1; - $Check | Add-Member -MemberType NoteProperty -Name 'verbose' -Value $Verbose; - $Check | Add-Member -MemberType NoteProperty -Name 'hidden' -Value $Hidden; - $Check | Add-Member -MemberType NoteProperty -Name 'ignoreemptypackage' -Value $IgnoreEmptyPackage; - $Check | Add-Member -MemberType NoteProperty -Name 'checks' -Value $Checks; - $Check | Add-Member -MemberType NoteProperty -Name 'opand' -Value $OperatorAnd; - $Check | Add-Member -MemberType NoteProperty -Name 'opor' -Value $OperatorOr; - $Check | Add-Member -MemberType NoteProperty -Name 'opnone' -Value $OperatorNone; - $Check | Add-Member -MemberType NoteProperty -Name 'opmin' -Value $OperatorMin; - $Check | Add-Member -MemberType NoteProperty -Name 'opmax' -Value $OperatorMax; - $Check | Add-Member -MemberType NoteProperty -Name 'spacing' -Value 0; - $Check | Add-Member -MemberType NoteProperty -Name 'compiled' -Value $FALSE; - $Check | Add-Member -MemberType NoteProperty -Name 'perfdata' -Value $FALSE; - $Check | Add-Member -MemberType NoteProperty -Name 'checkcommand' -Value ''; - $Check | Add-Member -MemberType NoteProperty -Name 'headermsg' -Value ''; - $Check | Add-Member -MemberType NoteProperty -Name 'checkpackage' -Value $TRUE; - $Check | Add-Member -MemberType NoteProperty -Name 'warningchecks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'criticalchecks' -Value @(); - $Check | Add-Member -MemberType NoteProperty -Name 'unknownchecks' -Value @(); + $IcingaCheckPackage = New-IcingaCheckBaseObject; - $Check | Add-Member -MemberType ScriptMethod -Name 'HasChecks' -Value { - if ($this.checks -ne 0) { - return $TRUE - } + $IcingaCheckPackage.Name = $Name; + $IcingaCheckPackage.__ObjectType = 'IcingaCheckPackage'; + $IcingaCheckPackage.__SetHidden($Hidden); + $IcingaCheckPackage.__SetVerbosity($Verbose); - return $FALSE; - } + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorAnd' -Value $OperatorAnd; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorOr' -Value $OperatorOr; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorNone' -Value $OperatorNone; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorMin' -Value $OperatorMin; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorMax' -Value $OperatorMax; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'IgnoreEmptyPackage' -Value $IgnoreEmptyPackage; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'AddSummaryHeader' -Value $AddSummaryHeader; + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__Checks' -Value @(); + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__OkChecks' -Value @(); + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__WarningChecks' -Value @(); + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__CriticalChecks' -Value @(); + $IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__UnknownChecks' -Value @(); - $Check | Add-Member -MemberType ScriptMethod -Name 'Initialise' -Value { - foreach ($check in $this.checks) { - $this.InitCheck($check); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'InitCheck' -Value { - param($check); - - if ($null -eq $check) { + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Name 'ValidateOperators' -Value { + if ($this.OperatorMin -ne -1) { return; } - $check.verbose = $this.verbose; - $check.AddSpacing(); - $check.SilentCompile(); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddSpacing' -Value { - $this.spacing += 1; - foreach ($check in $this.checks) { - $check.spacing = $this.spacing; - $check.AddSpacing(); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddCheck' -Value { - param($check); - - if ($null -eq $check) { + if ($this.OperatorMax -ne -1) { return; } - $this.InitCheck($check); - $this.checks += $check; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetWarnings' -Value { - foreach ($check in $this.checks) { - $this.warningchecks += $check.GetWarnings(); - } - - return $this.warningchecks; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetCriticals' -Value { - foreach ($check in $this.checks) { - $this.criticalchecks += $check.GetCriticals(); - } - - return $this.criticalchecks; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetUnknowns' -Value { - foreach ($check in $this.checks) { - $this.unknownchecks += $check.GetUnknowns(); - } - - return $this.unknownchecks; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AssignCheckCommand' -Value { - param($CheckCommand); - - $this.checkcommand = $CheckCommand; - - foreach ($check in $this.checks) { - $check.AssignCheckCommand($CheckCommand); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value { - param([bool]$Verbose); - - if ($this.compiled) { + if ($this.OperatorNone -ne $FALSE) { return; } - $this.compiled = $TRUE; - - if ($this.checks.Count -ne 0) { - if ($this.opand) { - if ($this.CheckAllOk() -eq $FALSE) { - $this.GetWorstExitCode(); - } - } elseif ($this.opor) { - if ($this.CheckOneOk() -eq $FALSE) { - $this.GetWorstExitCode(); - } - } elseif ($this.opnone) { - if ($this.CheckOneOk() -eq $TRUE) { - $this.GetWorstExitCode(); - $this.exitcode = $IcingaEnums.IcingaExitCode.Critical; - } else { - $this.exitcode = $IcingaEnums.IcingaExitCode.Ok; - } - } elseif ([int]$this.opmin -ne -1) { - if ($this.CheckMinimumOk() -eq $FALSE) { - $this.GetWorstExitCode(); - } else { - $this.exitcode = $IcingaEnums.IcingaExitCode.Ok; - } - } elseif ([int]$this.opmax -ne -1) { - if ($this.CheckMaximumOk() -eq $FALSE) { - $this.GetWorstExitCode(); - } else { - $this.exitcode = $IcingaEnums.IcingaExitCode.Ok; - } - } - } else { - if ($this.ignoreemptypackage) { - $this.exitcode = $IcingaEnums.IcingaExitCode.Ok; - } else { - $this.exitcode = $IcingaEnums.IcingaExitCode.Unknown; - } + if ($this.OperatorOr -ne $FALSE) { + return; } - if ([int]$this.exitcode -eq -1) { - $this.exitcode = $IcingaEnums.IcingaExitCode.Ok; - } - - if ($Verbose -eq $TRUE) { - $this.PrintOutputMessages(); - } - - return $this.exitcode; + # If no operator is set, use And as default + $this.OperatorAnd = $TRUE; } - $Check | Add-Member -MemberType ScriptMethod -Name 'SilentCompile' -Value { - $this.Compile($FALSE) | Out-Null; - } + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Name 'AddCheck' -Value { + param([array]$Checks); - $Check | Add-Member -MemberType ScriptMethod -Name 'GetOkCount' -Value { - [int]$okCount = 0; - foreach ($check in $this.checks) { - if ([int]$check.exitcode -eq [int]$IcingaEnums.IcingaExitCode.Ok) { - $okCount += 1; - } + if ($null -eq $Checks -Or $Checks.Count -eq 0) { + return; } - return $okCount; + foreach ($check in $Checks) { + $check.__SetIndention($this.__NewIndention()); + $check.__SetCheckOutput(); + $check.__SetVerbosity($this.__GetVerbosity()); + $check.__SetParent($this); + $this.__Checks += $check; + } } - $Check | Add-Member -MemberType ScriptMethod -Name 'CheckMinimumOk' -Value { - if ($this.opmin -gt $this.checks.Count) { - Write-IcingaPluginOutput ( - [string]::Format( - 'Unknown: The minimum argument ({0}) is exceeding the amount of assigned checks ({1}) to this package "{2}"', - $this.opmin, $this.checks.Count, $this.name - ) + # Override shared function + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__SetIndention' -Value { + param ($Indention); + + $this.__Indention = $Indention; + + foreach ($check in $this.__Checks) { + $check.__SetIndention($this.__NewIndention()); + } + } + + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Name '__SetCheckState' -Value { + param ($State); + + if ($this.__GetCheckState() -lt $State) { + $this.__CheckState = $State; + $this.__SetCheckOutput(); + } + } + + # Override shared function + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__SetCheckOutput' -Value { + param ($PluginOutput); + + $UnknownChecks = ''; + $CriticalChecks = ''; + $WarningChecks = ''; + $CheckSummary = [System.Text.StringBuilder]::New(); + [bool]$HasContent = $FALSE; + + # Only apply this to the top parent package + if ($this.__GetIndention() -eq 0) { + if ($this.__UnknownChecks.Count -ne 0) { + $UnknownChecks = [string]::Format(' [UNKNOWN] {0}', ([string]::Join(', ', $this.__UnknownChecks))); + $HasContent = $TRUE; + $CheckSummary.Append( + [string]::Format(' {0} Unknown', $this.__UnknownChecks.Count) + ) | Out-Null; + } + if ($this.__CriticalChecks.Count -ne 0) { + $CriticalChecks = [string]::Format(' [CRITICAL] {0}', ([string]::Join(', ', $this.__CriticalChecks))); + $HasContent = $TRUE; + $CheckSummary.Append( + [string]::Format(' {0} Critical', $this.__CriticalChecks.Count) + ) | Out-Null; + } + if ($this.__WarningChecks.Count -ne 0) { + $WarningChecks = [string]::Format(' [WARNING] {0}', ([string]::Join(', ', $this.__WarningChecks))); + $HasContent = $TRUE; + $CheckSummary.Append( + [string]::Format(' {0} Warning', $this.__WarningChecks.Count) + ) | Out-Null; + } + } + if ([string]::IsNullOrEmpty($this.__ErrorMessage) -eq $FALSE) { + $HasContent = $TRUE; + } + if ($this.__OkChecks.Count -ne 0) { + $CheckSummary.Append( + [string]::Format(' {0} Ok', $this.__OkChecks.Count) + ) | Out-Null; + $HasContent = $TRUE; + } + + if ($this.AddSummaryHeader -eq $FALSE) { + $CheckSummary.Clear() | Out-Null; + $CheckSummary.Append('') | Out-Null; + } + + $this.__CheckOutput = [string]::Format( + '{0} {1}{2}{3}{4}{5}{6}{7}{8}', + $IcingaEnums.IcingaExitCodeText[$this.__GetCheckState()], + $this.Name, + (&{ if ($HasContent) { return ':'; } else { return ''; } }), + $CheckSummary.ToString(), + ([string]::Format('{0}{1}', (&{ if ($this.__ErrorMessage.Length -gt 1) { return ' '; } else { return ''; } }), $this.__ErrorMessage)), + $UnknownChecks, + $CriticalChecks, + $WarningChecks, + $this.__ShowPackageConfig() + ); + } + + $IcingaCheckPackage | Add-Member -Force -MemberType ScriptMethod -Name 'Compile' -Value { + $this.__OkChecks.Clear(); + $this.__WarningChecks.Clear(); + $this.__CriticalChecks.Clear(); + $this.__UnknownChecks.Clear(); + + $WorstState = $IcingaEnums.IcingaExitCode.Ok; + $BestState = $IcingaEnums.IcingaExitCode.Ok; + $NotOkChecks = 0; + $OkChecks = 0; + + if ($this.__Checks.Count -eq 0 -And $this.IgnoreEmptyPackage -eq $FALSE) { + $this.__ErrorMessage = 'No checks added to this package'; + $this.__SetCheckState($IcingaEnums.IcingaExitCode.Unknown); + $this.__SetCheckOutput(); + return; + } + + $this.__Checks = $this.__Checks | Sort-Object -Property Name; + + # Loop all checks to understand the content of result + foreach ($check in $this.__Checks) { + + $check.Compile(); + + if ($WorstState -lt $check.__GetCheckState()) { + $WorstState = $check.__GetCheckState(); + } + + if ($BestState -gt $check.__GetCheckState()) { + $BestState = $check.__GetCheckState(); + } + + [string]$CheckStateOutput = [string]::Format( + '{0}{1}', + $check.__GetName(), + $check.__GetHeaderOutputValue() ); - $this.exitcode = $IcingaEnums.IcingaExitCode.Unknown; - return $FALSE; + + switch ($check.__GetCheckState()) { + $IcingaEnums.IcingaExitCode.Ok { + $this.__OkChecks += $CheckStateOutput; + $OkChecks += 1; + break; + }; + $IcingaEnums.IcingaExitCode.Warning { + $this.__WarningChecks += $CheckStateOutput; + $NotOkChecks += 1; + break; + }; + $IcingaEnums.IcingaExitCode.Critical { + $this.__CriticalChecks += $CheckStateOutput; + $NotOkChecks += 1; + break; + }; + $IcingaEnums.IcingaExitCode.Unknown { + $this.__UnknownChecks += $CheckStateOutput; + $NotOkChecks += 1; + break; + }; + } } - [int]$okCount = $this.GetOkCount(); + if ($this.OperatorAnd -And $NotOkChecks -ne 0) { + $this.__SetCheckState($WorstState); + } elseif ($this.OperatorOr -And $OkChecks -eq 0 ) { + $this.__SetCheckState($WorstState); + } elseif ($this.OperatorNone -And $OkChecks -ne 0 ) { + $this.__SetCheckState($WorstState); + } elseif ($this.OperatorMin -ne -1) { + if (-Not ($this.__Checks.Count -eq 0 -And $this.IgnoreEmptyPackage -eq $TRUE)) { + if ($this.OperatorMin -gt $this.__Checks.Count) { + $this.__SetCheckState($IcingaEnums.IcingaExitCode.Unknown); + $this.__ErrorMessage = [string]::Format('Minium check count ({0}) is larger than number of assigned checks ({1})', $this.OperatorMin, $this.__Checks.Count); + } elseif ($OkChecks -lt $this.OperatorMin) { + $this.__SetCheckState($WorstState); + $this.__ErrorMessage = ''; + } + } + } elseif ($this.OperatorMax -ne -1) { + if (-Not ($this.__Checks.Count -eq 0 -And $this.IgnoreEmptyPackage -eq $TRUE)) { + if ($this.OperatorMax -gt $this.__Checks.Count) { + $this.__SetCheckState($IcingaEnums.IcingaExitCode.Unknown); + $this.__ErrorMessage = [string]::Format('Maximum check count ({0}) is larger than number of assigned checks ({1})', $this.OperatorMax, $this.__Checks.Count); + } elseif ($OkChecks -gt $this.OperatorMax) { + $this.__SetCheckState($WorstState); + $this.__ErrorMessage = ''; + } + } + } - if ($this.opmin -le $okCount) { + $this.__SetCheckOutput(); + } + + # Override default behaviour from shared function + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__SetVerbosity' -Value { + param ($Verbosity); + # Do nothing for check packages + } + + # Override default behaviour from shared function + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__GetCheckOutput' -Value { + + if ($this.__IsHidden()) { + return '' + }; + + if ($this._CanOutput() -eq $FALSE) { + return ''; + } + + $CheckOutput = [string]::Format( + '{0}{1}', + (New-StringTree -Spacing $this.__GetIndention()), + $this.__CheckOutput + ); + + foreach ($check in $this.__Checks) { + if ($check.__IsHidden()) { + continue; + }; + + if ($check._CanOutput() -eq $FALSE) { + continue; + } + + $CheckOutput = [string]::Format( + '{0}{1}{2}', + $CheckOutput, + "`n", + $check.__GetCheckOutput() + ); + } + + return $CheckOutput; + } + + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__HasNotOkChecks' -Value { + + if ($this.__WarningChecks.Count -ne 0) { + return $TRUE; + } + + if ($this.__CriticalChecks.Count -ne 0) { + return $TRUE; + } + + if ($this.__UnknownChecks.Count -ne 0) { return $TRUE; } return $FALSE; } - $Check | Add-Member -MemberType ScriptMethod -Name 'CheckMaximumOk' -Value { - if ($this.opmax -gt $this.checks.Count) { - Write-IcingaPluginOutput ( - [string]::Format( - 'Unknown: The maximum argument ({0}) is exceeding the amount of assigned checks ({1}) to this package "{2}"', - $this.opmax, $this.checks.Count, $this.name - ) - ); - $this.exitcode = $IcingaEnums.IcingaExitCode.Unknown; - return $FALSE; + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__ShowPackageConfig' -Value { + if ($this.__GetVerbosity() -lt 3) { + return ''; } - [int]$okCount = $this.GetOkCount(); - - if ($this.opmax -ge $okCount) { - return $TRUE; + if ($this.OperatorAnd) { + return ' (All must be [OK])'; + } + if ($this.OperatorOr) { + return ' (Atleast one must be [OK])'; + } + if ($this.OperatorMin -ne -1) { + return ([string]::Format(' (Atleast {0} must be [OK])', $this.OperatorMin)); + } + if ($this.OperatorMax -ne -1) { + return ([string]::Format(' (Not more than {0} must be [OK])', $this.OperatorMax)); } - return $FALSE; + return ''; } - $Check | Add-Member -MemberType ScriptMethod -Name 'CheckAllOk' -Value { - foreach ($check in $this.checks) { - if ([int]$check.exitcode -ne [int]$IcingaEnums.IcingaExitCode.Ok) { - return $FALSE; - } - } - - return $TRUE; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'CheckOneOk' -Value { - foreach ($check in $this.checks) { - if ([int]$check.exitcode -eq [int]$IcingaEnums.IcingaExitCode.Ok) { - $this.exitcode = $check.exitcode; - return $TRUE; - } - } - - return $FALSE; - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetPackageConfigMessage' -Value { - if ($this.opand) { - return 'Match All'; - } elseif ($this.opor) { - return 'Match Any'; - } elseif ($this.opnone) { - return 'Match None'; - } elseif ([int]$this.opmin -ne -1) { - return [string]::Format('Minimum {0}', $this.opmin) - } elseif ([int]$this.opmax -ne -1) { - return [string]::Format('Maximum {0}', $this.opmax) - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintOutputMessageSorted' -Value { - param($skipHidden, $skipExitCode); - - if ($this.hidden -And $skipHidden) { - return; - } - - [hashtable]$MessageOrdering = @{}; - foreach ($check in $this.checks) { - if ($this.verbose -eq 0) { - if ([int]$check.exitcode -eq $skipExitCode) { - continue; - } - } elseif ($this.verbose -eq 1) { - if ([int]$check.exitcode -eq $skipExitCode -And $check.checkpackage) { - continue; - } - } - - if ($MessageOrdering.ContainsKey($check.Name) -eq $FALSE) { - $MessageOrdering.Add($check.name, $check); - } else { - [int]$DuplicateKeyIndex = 1; - while ($TRUE) { - $newCheckName = [string]::Format('{0}[{1}]', $check.Name, $DuplicateKeyIndex); - if ($MessageOrdering.ContainsKey($newCheckName) -eq $FALSE) { - $MessageOrdering.Add($newCheckName, $check); - break; - } - $DuplicateKeyIndex += 1; - } - } - } - - $SortedArray = $MessageOrdering.GetEnumerator() | Sort-Object name; - - foreach ($entry in $SortedArray) { - $entry.Value.PrintAllMessages(); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WriteAllOutput' -Value { - $this.PrintOutputMessageSorted($TRUE, $IcingaEnums.IcingaExitCode.Ok); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintAllMessages' -Value { - $this.WritePackageOutputStatus(); - $this.WriteAllOutput(); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WriteCheckErrors' -Value { - $this.PrintOutputMessageSorted($FALSE, $IcingaEnums.IcingaExitCode.Ok); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintNoChecksConfigured' -Value { - if ($this.checks.Count -eq 0) { - Write-IcingaPluginOutput ( - [string]::Format( - '{0}{1} No checks configured for package "{2}"', - (New-StringTree ($this.spacing + 1)), - $IcingaEnums.IcingaExitCodeText.($this.exitcode), - $this.name - ) - ) - return; - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'WritePackageOutputStatus' -Value { - if ($this.hidden) { - return; - } - - [string]$outputMessage = '{0}{1} Check package "{2}"'; - if ($this.verbose -ne 0) { - $outputMessage += ' ({3})'; - } - - if ($this.exitcode -ne 0 -And $this.spacing -eq 0) { - $outputMessage += ' - {4}'; - } - - Write-IcingaPluginOutput ( - [string]::Format( - $outputMessage, - (New-StringTree $this.spacing), - $IcingaEnums.IcingaExitCodeText.($this.exitcode), - $this.name, - $this.GetPackageConfigMessage(), - $this.headermsg - ) - ); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'PrintOutputMessages' -Value { - [bool]$printAll = $FALSE; - - switch ($this.verbose) { - 0 { - # Default value. Only print a package but not the services include - break; - }; - 1 { - # Include the Operator into the check package result and OK checks of package - break; - }; - Default { - $printAll = $TRUE; - break; - } - } - - $this.WritePackageOutputStatus(); - - if ($printAll) { - $this.WriteAllOutput(); - $this.PrintNoChecksConfigured(); - } else { - if ([int]$this.exitcode -ne $IcingaEnums.IcingaExitCode.Ok) { - $this.WriteCheckErrors(); - $this.PrintNoChecksConfigured(); - } - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'AddUniqueSortedChecksToHeader' -Value { - param($checkarray, $state); - - [hashtable]$CheckHash = @{}; - - foreach ($entry in $checkarray) { - if ($CheckHash.ContainsKey($entry) -eq $FALSE) { - $CheckHash.Add($entry, $TRUE); - } - } - - [array]$SortedCheckArray = $CheckHash.GetEnumerator() | Sort-Object name; - - if ($SortedCheckArray.Count -ne 0) { - $this.headermsg += [string]::Format( - '{0} {1} ', - $IcingaEnums.IcingaExitCodeText[$state], - [string]::Join(', ', $SortedCheckArray.Key) - ); - } - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetWorstExitCode' -Value { - if ([int]$this.exitcode -eq [int]$IcingaEnums.IcingaExitCode.Unknown) { - return; - } - - foreach ($check in $this.checks) { - if ([int]$this.exitcode -lt $check.exitcode) { - $this.exitcode = $check.exitcode; - } - - $this.criticalchecks += $check.GetCriticals(); - $this.warningchecks += $check.GetWarnings(); - $this.unknownchecks += $check.GetUnknowns(); - } - - # Only apply this to our top package - if ($this.spacing -ne 0) { - return; - } - - $this.AddUniqueSortedChecksToHeader( - $this.criticalchecks, $IcingaEnums.IcingaExitCode.Critical - ); - $this.AddUniqueSortedChecksToHeader( - $this.warningchecks, $IcingaEnums.IcingaExitCode.Warning - ); - $this.AddUniqueSortedChecksToHeader( - $this.unknownchecks, $IcingaEnums.IcingaExitCode.Unknown - ); - } - - $Check | Add-Member -MemberType ScriptMethod -Name 'GetPerfData' -Value { + # Override default behaviour from shared function + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__GetPerformanceData' -Value { [string]$perfData = ''; - [hashtable]$CollectedPerfData = @{}; + [hashtable]$CollectedPerfData = @{ }; # At first lets collect all perf data, but ensure we only add possible label duplication only once - foreach ($check in $this.checks) { - $data = $check.GetPerfData(); + foreach ($check in $this.__Checks) { + $data = $check.__GetPerformanceData(); if ($null -eq $data -Or $null -eq $data.label) { continue; @@ -463,22 +349,42 @@ function New-IcingaCheckPackage() $CollectedPerfData.Add($data.label, $data); } - # Now sort the label output by name - $SortedArray = $CollectedPerfData.GetEnumerator() | Sort-Object name; - - # Buold the performance data output based on the sorted result - foreach ($entry in $SortedArray) { - $perfData += $entry.Value; - } - return @{ - 'label' = $this.name; + 'label' = $this.Name; 'perfdata' = $CollectedPerfData; 'package' = $TRUE; } } - $Check.Initialise(); + # __GetTimeSpanThreshold(0, 'Core_30_20', 'Core_30') + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__GetTimeSpanThreshold' -Value { + param ($TimeSpanLabel, $Label); - return $Check; + foreach ($check in $this.__Checks) { + $Result = $check.__GetTimeSpanThreshold($TimeSpanLabel, $Label); + + if ([string]::IsNullOrEmpty($Result) -eq $FALSE) { + return $Result; + } + } + + return @{ + 'Warning' = ''; + 'Critical' = ''; + }; + } + + # Override shared function + $IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name 'HasChecks' -Value { + if ($this.__Checks.Count -eq 0) { + return $FALSE; + } + + return $TRUE; + } + + $IcingaCheckPackage.ValidateOperators(); + $IcingaCheckPackage.AddCheck($Checks); + + return $IcingaCheckPackage; } diff --git a/lib/icinga/plugin/New-IcingaCheckResult.psm1 b/lib/icinga/plugin/New-IcingaCheckResult.psm1 index 798f778..621de95 100644 --- a/lib/icinga/plugin/New-IcingaCheckResult.psm1 +++ b/lib/icinga/plugin/New-IcingaCheckResult.psm1 @@ -1,38 +1,38 @@ -Import-IcingaLib icinga\enums; - -function New-IcingaCheckresult() +function New-IcingaCheckResult() { - param( + param ( $Check, - [bool]$NoPerfData, - [switch]$Compile + [bool]$NoPerfData = $FALSE, + [switch]$Compile = $FALSE ); - $CheckResult = New-Object -TypeName PSObject; - $CheckResult | Add-Member -MemberType NoteProperty -Name 'check' -Value $Check; - $CheckResult | Add-Member -MemberType NoteProperty -Name 'noperfdata' -Value $NoPerfData; + $IcingaCheckResult = New-Object -TypeName PSObject; + $IcingaCheckResult | Add-Member -MemberType NoteProperty -Name 'Check' -Value $Check; + $IcingaCheckResult | Add-Member -MemberType NoteProperty -Name 'NoPerfData' -Value $NoPerfData; - $CheckResult | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value { - if ($null -eq $this.check) { + $IcingaCheckResult | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value { + if ($null -eq $this.Check) { return $IcingaEnums.IcingaExitCode.Unknown; } - $CheckCommand = (Get-PSCallStack)[2].Command; - # Compile the check / package if not already done - $this.check.AssignCheckCommand($CheckCommand); - $this.check.Compile($TRUE) | Out-Null; + $this.Check.Compile(); - if ([int]$this.check.exitcode -ne [int]$IcingaEnums.IcingaExitCode.Unknown -And -Not $this.noperfdata) { - Write-IcingaPluginPerfData -PerformanceData ($this.check.GetPerfData()) -CheckCommand $CheckCommand; + Write-IcingaPluginOutput -Output ($this.Check.__GetCheckOutput()); + + if ($this.NoPerfData -eq $FALSE) { + Write-IcingaPluginPerfData -IcingaCheck $this.Check; } - return $this.check.exitcode; + # Ensure we reset our internal cache once the plugin was executed + $Global:Icinga.ThresholdCache[$this.Check.__GetCheckCommand()] = $null; + + return $this.Check.__GetCheckState(); } if ($Compile) { - return $CheckResult.Compile(); + return $IcingaCheckResult.Compile(); } - return $CheckResult; + return $IcingaCheckResult; } diff --git a/lib/icinga/plugin/New-IcingaPerformanceDataEntry.psm1 b/lib/icinga/plugin/New-IcingaPerformanceDataEntry.psm1 index 75f1c73..3fa8ad6 100644 --- a/lib/icinga/plugin/New-IcingaPerformanceDataEntry.psm1 +++ b/lib/icinga/plugin/New-IcingaPerformanceDataEntry.psm1 @@ -3,15 +3,19 @@ function New-IcingaPerformanceDataEntry() param ( $PerfDataObject, $Label = $null, - $Value = $null + $Value = $null, + $Warning = $null, + $Critical = $null ); if ($null -eq $PerfDataObject) { return ''; } - [string]$LabelName = $PerfDataObject.label; - [string]$PerfValue = $PerfDataObject.value; + [string]$LabelName = $PerfDataObject.label; + [string]$PerfValue = $PerfDataObject.value; + [string]$WarningValue = $PerfDataObject.warning; + [string]$CriticalValue = $PerfDataObject.critical; if ([string]::IsNullOrEmpty($Label) -eq $FALSE) { $LabelName = $Label; @@ -20,6 +24,13 @@ function New-IcingaPerformanceDataEntry() $PerfValue = $Value; } + # Override our warning/critical values only if the label does not match. + # Eg. Core_1 not matching Core_1_5 - this is only required for time span checks + if ([string]::IsNullOrEmpty($Label) -eq $FALSE -And $Label -ne $PerfDataObject.label) { + $WarningValue = $Warning; + $CriticalValue = $Critical; + } + $minimum = ''; $maximum = ''; @@ -36,8 +47,8 @@ function New-IcingaPerformanceDataEntry() $LabelName.ToLower(), (Format-IcingaPerfDataValue $PerfValue), $PerfDataObject.unit, - (Format-IcingaPerfDataValue $PerfDataObject.warning), - (Format-IcingaPerfDataValue $PerfDataObject.critical), + (Format-IcingaPerfDataValue $WarningValue), + (Format-IcingaPerfDataValue $CriticalValue), (Format-IcingaPerfDataValue $minimum), (Format-IcingaPerfDataValue $maximum) ) diff --git a/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 b/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 index 10a3b60..40e27ad 100644 --- a/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 +++ b/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 @@ -1,10 +1,16 @@ function Write-IcingaPluginPerfData() { - param( - $PerformanceData, - $CheckCommand + param ( + $IcingaCheck = $null ); + if ($null -eq $IcingaCheck) { + return; + } + + $PerformanceData = $IcingaCheck.__GetPerformanceData(); + $CheckCommand = $IcingaCheck.__GetCheckCommand(); + if ($PerformanceData.package -eq $FALSE) { $PerformanceData = @{ $PerformanceData.label = $PerformanceData; @@ -13,13 +19,13 @@ function Write-IcingaPluginPerfData() $PerformanceData = $PerformanceData.perfdata; } - $CheckResultCache = Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $CheckCommand; + $CheckResultCache = $Global:Icinga.ThresholdCache[$CheckCommand]; if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) { - [string]$PerfDataOutput = (Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache); + [string]$PerfDataOutput = (Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -IcingaCheck $IcingaCheck); Write-IcingaConsolePlain ([string]::Format('| {0}', $PerfDataOutput)); } else { - [void](Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -AsObject $TRUE); + [void](Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -AsObject $TRUE -IcingaCheck $IcingaCheck); } } @@ -28,7 +34,8 @@ function Get-IcingaPluginPerfDataContent() param( $PerfData, $CheckResultCache, - [bool]$AsObject = $FALSE + [bool]$AsObject = $FALSE, + $IcingaCheck = $null ); [string]$PerfDataOutput = ''; @@ -36,13 +43,16 @@ function Get-IcingaPluginPerfDataContent() foreach ($package in $PerfData.Keys) { $data = $PerfData[$package]; if ($data.package) { - $PerfDataOutput += (Get-IcingaPluginPerfDataContent -PerfData $data.perfdata -CheckResultCache $CheckResultCache -AsObject $AsObject); + $PerfDataOutput += (Get-IcingaPluginPerfDataContent -PerfData $data.perfdata -CheckResultCache $CheckResultCache -AsObject $AsObject -IcingaCheck $IcingaCheck); } else { foreach ($checkresult in $CheckResultCache.PSobject.Properties) { + $SearchPattern = [string]::Format('{0}_', $data.label); $SearchEntry = $checkresult.Name; if ($SearchEntry -like "$SearchPattern*") { - $cachedresult = (New-IcingaPerformanceDataEntry -PerfDataObject $data -Label $SearchEntry -Value $checkresult.Value); + $TimeSpan = $IcingaCheck.__GetTimeSpanThreshold($SearchEntry, $data.label); + + $cachedresult = (New-IcingaPerformanceDataEntry -PerfDataObject $data -Label $SearchEntry -Value $checkresult.Value -Warning $TimeSpan.Warning -Critical $TimeSpan.Critical); if ($AsObject) { # New behavior with local thread separated results