diff --git a/doc/100-General/01-Upgrading.md b/doc/100-General/01-Upgrading.md index 3810310..29eb191 100644 --- a/doc/100-General/01-Upgrading.md +++ b/doc/100-General/01-Upgrading.md @@ -20,6 +20,24 @@ After upgrading to Icinga for Windows v1.8.0, you will require to open a new Ici **NOTE:** In some cases the changes for the EventLog will only apply, **after** the system has been rebooted. Afterwards every Icinga for Windows EventLog entry is written in a newly created `Icinga for Windows` log. +### Custom Daemon Handling + +With Icinga for Windows v1.8.0 we removed the entire list of currently available `$Global` variables: + +* `$Global:IcingaThreads` +* `$Global:IcingaThreadContent` +* `$Global:IcingaThreadPool` +* `$Global:IcingaTimers` +* `$Global:IcingaDaemonData` + +All of these have been centralized inside one, new variable called `$Global:Icinga`. You can read more about the structure of this `hashtable` object on the [Developer Guide](../900-Developer-Guide/00-General.md/#Data-Management). + +The important change is, that in case you created custom daemons or API endpoints using on of the above globals, you will have to migrate your code to properly make use of `$Global:Icinga`, otherwise your daemons will not work anymore once you upgrade to Icinga for Windows v1.8.0. + +The benefit of this change is that you no longer require to take care of synchronising global data between newly created threads, as Icinga for Windows will make the public part of `$Global:Icinga.Public` shared for every single instance automatically. + +Please [contact us](https://icinga.com/company/contact/) in case you require assistance with migrating your current code to Icinga for Windows v1.8.0. + ## Upgrading to v1.7.0 (2021-11-09) ### REST-Api and Api-Checks diff --git a/doc/100-General/10-Changelog.md b/doc/100-General/10-Changelog.md index 3b88815..d14ebcb 100644 --- a/doc/100-General/10-Changelog.md +++ b/doc/100-General/10-Changelog.md @@ -23,6 +23,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#409](https://github.com/Icinga/icinga-powershell-framework/issues/409) Fixes URL builder for `Sync-IcingaRepository` which will now properly test the JSON file and try a secondary fallback by pointing to the `ifw.repo.json` in case a URL is returning the directory listing instead * [#411](https://github.com/Icinga/icinga-powershell-framework/pull/411) Fixes Icinga Director error message output because of missing `[string]::Format()` * [#412](https://github.com/Icinga/icinga-powershell-framework/issues/412) Fixes possible defective state of the Icinga Agent by using a custom service user for JEA profiles which is larger than 20 digits +* [#414](https://github.com/Icinga/icinga-powershell-framework/pull/414) Fixes Service Check Daemon with a total rewrite to improve performance, decrease required resources and fix memory leaks * [#418](https://github.com/Icinga/icinga-powershell-framework/pull/418) Fixes crash on wrong variable usage introduced by [#411](https://github.com/Icinga/icinga-powershell-framework/pull/411) * [#421](https://github.com/Icinga/icinga-powershell-framework/issues/421) Fixes experimental state of `API Check` feature by removing that term and removing the requirement to install `icinga-powershell-restapi` and `icinga-powershell-apichecks` * [#436](https://github.com/Icinga/icinga-powershell-framework/pull/436) Fixes a lookup error for existing plugin documentation files, which caused files not being generated properly in case a similar name was already present on the system diff --git a/doc/900-Developer-Guide/00-General.md b/doc/900-Developer-Guide/00-General.md index a7ed922..547b3b4 100644 --- a/doc/900-Developer-Guide/00-General.md +++ b/doc/900-Developer-Guide/00-General.md @@ -45,6 +45,81 @@ In this case, our `NestedModules` variable within our `.psd1` file requires the ) ``` +### Data Management + +Icinga for Windows is using one global variable `$Global:Icinga`, to store information for daemons and other tasks. This variable is split into three different categories, which you can read more on below. The general architecture of this construct is a simple `hashtable`. +You can interact with this variable and sub-entries like you would with normal `hashtables`, making data stored a lot easier to access and maintain. + +#### Private + +Everything which should be stored while a daemon is running internally or within a PowerShell session and **not** being shared with other daemons, is stored within the `$Global:Icinga.Private` space. + +The following entries are set by default within the `Private` space: + +| Category | Description | +| --- | --- | +| Timers | All created timers by using `Start-IcingaTimer` are stored under this environment variable | +| Scheduler | Once plugins are executed, performance data, check results and exit codes are stored in this section, in case the PowerShell instance is set to run as daemon | +| Daemons | This is a place where all daemon data should be added and stored, separated by a namespace for each module as entry. This data is **not** shared between other daemons | + +#### Example Data + +```powershell +$Global:Icinga.Private.Timers.DefaultTimer +``` + +```powershell +$Global:Icinga.Private.Scheduler.CheckResults +``` + +```powershell +$Global:Icinga.Private.Daemons.ServiceCheck.PerformanceCache +``` + +#### Public + +Everything stored within the `Public` space of `$Global:Icinga` is automatically shared between all threads of the current PowerShell instance. If you run the `ServiceCheckDaemon` in addition with the `RestAPI` for example, metrics over time will be read from the public shared space from the `RestApi` and used during check execution. + +There is no manual configuration required to share the information, as Icinga for Windows will deal with this for you, once a new thread instance is created. + +The following entries are set by default within the `Public` space: + +| Category | Description | +| --- | --- | +| ThreadPools | A list of all thread pools available to create new thread limits for certain background daemons | +| Daemons | A place to store shared information for each single daemon within a namespace, making data accessible to other threads | +| Threads | A list of all started and available threads running by Icinga for Windows | +| PerformanceCounter | A space to share all PerformanceCounter information between threads, which counters are already created for internal usage | + +##### Example Data + +```powershell +$Global:Icinga.Public.ThreadPools.MainPool +``` + +```powershell +$Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist +``` + +```powershell +$Global:Icinga.Public.Threads.'Start-IcingaForWindowsDaemon::Add-IcingaForWindowsDaemon::Main::0' +``` + +#### Protected + +This is a section reserved for Icinga for Windows and Icinga developers in general. This space will store general information for Icinga for Windows, determining on how the PowerShell instance is handling internal requests and procedures. + +As custom module developer, you can **read** from this space but are in genetal **not** allowed to store information there. Please use the `Private` and `Public` space for this. + +The following entries are set by default within the `Protected` space: + +| Category | Description | +| --- | --- | +| JEAContext | Tells Icinga for Windows that the current environment is running within a JEA context | +| RunAsDaemon | Tells Icinga for Windows that the current PowerShell instance is running as daemon, changing behaviors on error and plugin execution handling | +| DebugMode | Enables the debug mode of Icinga for Windows, printing additional details during operations or tasks | +| Minimal | Changes certain behavior regarding check execution and internal error handling | + ## Using Icinga for Windows Dev Tools Maintaining the entire structure above seems to be complicated at the beginning, especially when considering to update the `NestedModules` section whenever you make changes. To mitigate this, Icinga for Windows provides a bunch of Cmdlets to help with the process diff --git a/doc/900-Developer-Guide/10-Custom-Daemons.md b/doc/900-Developer-Guide/10-Custom-Daemons.md index f8928a3..d664d1d 100644 --- a/doc/900-Developer-Guide/10-Custom-Daemons.md +++ b/doc/900-Developer-Guide/10-Custom-Daemons.md @@ -94,18 +94,13 @@ function Add-IcingaAgentServiceTest() } ``` -Depending on our daemon, later usage and possible sharing of data between all loaded daemons might be required. In addition we might want to spawn child threads as single tasks being executed. To do so, we will parse the frameworks `global` data to the thread. +Depending on our daemon, later usage and possible sharing of data between all loaded daemons might be required. In addition we might want to spawn child threads as single tasks being executed. To access the global, shared data, use can use the `Global:Icinga.Public` variable. This content is shared automatically between each single created thread. Our recommendation is to always do this for every daemon, as later changes might be more complicated and time consuming. ```powershell function Add-IcingaAgentServiceTest() { - # Allow us to parse the framework global data to this thread - param ( - $IcingaDaemonData - ); - # Everything which will be executed inside the thread # belongs here } @@ -116,11 +111,6 @@ Now as the basic part is finished, we will require to make our framework librari ```powershell function Add-IcingaAgentServiceTest() { - # Allow us to parse the framework global data to this thread - param ( - $IcingaDaemonData - ); - # Import the framework library components and initialise it # as daemon Use-Icinga -LibOnly -Daemon; @@ -132,29 +122,19 @@ As we will parse the `global` framework data anyways, we should already make use ```powershell function Add-IcingaAgentServiceTest() { - # Allow us to parse the framework global data to this thread - param ( - $IcingaDaemonData - ); - # Import the framework library components and initialise it # as daemon Use-Icinga -LibOnly -Daemon; - # Add a synchronized hashtable to the global data background + # Add a hashtable to the public data background # daemon hashtable to write data to. In addition it will # allow to share data collected from this daemon with others - $IcingaDaemonData.BackgroundDaemon.Add( - 'TestIcingaAgentService', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.Add('TestIcingaAgentService', @{ }); + # This will add another hashtable to our previous # TestIcingaAgentService hashtable to store actual service # information - $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.Add( - 'ServiceState', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.TestIcingaAgentService.Add('ServiceState', @{ }); } ``` @@ -165,29 +145,19 @@ Because the code is executed as separate thread, we will have to ensure it will ```powershell function Add-IcingaAgentServiceTest() { - # Allow us to parse the framework global data to this thread - param ( - $IcingaDaemonData - ); - # Import the framework library components and initialise it # as daemon Use-Icinga -LibOnly -Daemon; - # Add a synchronized hashtable to the global data background + # Add a hashtable to the public data background # daemon hashtable to write data to. In addition it will # allow to share data collected from this daemon with others - $IcingaDaemonData.BackgroundDaemon.Add( - 'TestIcingaAgentService', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.Add('TestIcingaAgentService', @{ }); + # This will add another hashtable to our previous # TestIcingaAgentService hashtable to store actual service # information - $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.Add( - 'ServiceState', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.TestIcingaAgentService.Add('ServiceState', @{ }); # Keep our code executed as long as the PowerShell service is # being executed. This is required to ensure we will execute @@ -197,34 +167,24 @@ function Add-IcingaAgentServiceTest() } ``` -*ALWAYS* ensure you add some sort for `sleep` at the end of the `while` loop to allow your CPU some breaks. If you do not do this, you might suffer from high CPU loads. The `sleep duration` interval can depend either on a simple CPU cycle break or by telling the daemon to execute tasks only in certain interval. In our case we wish to execute the daemon every `5 seconds`. +*ALWAYS* ensure you add some sort for `sleep` at the end of the `while` loop to allow your CPU some breaks. If you do not do this, you might suffer from high CPU loads. The `sleep duration` interval can depend either on a simple CPU cycle break or by telling the daemon to execute tasks only in certain Intervalls. In our case we wish to execute the daemon every `5 seconds`. ```powershell function Add-IcingaAgentServiceTest() { - # Allow us to parse the framework global data to this thread - param ( - $IcingaDaemonData - ); - # Import the framework library components and initialise it # as daemon Use-Icinga -LibOnly -Daemon; - # Add a synchronized hashtable to the global data background + # Add a hashtable to the public data background # daemon hashtable to write data to. In addition it will # allow to share data collected from this daemon with others - $IcingaDaemonData.BackgroundDaemon.Add( - 'TestIcingaAgentService', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.Add('TestIcingaAgentService', @{ }); + # This will add another hashtable to our previous # TestIcingaAgentService hashtable to store actual service # information - $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.Add( - 'ServiceState', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.TestIcingaAgentService.Add('ServiceState', @{ }); # Keep our code executed as long as the PowerShell service is # being executed. This is required to ensure we will execute @@ -243,29 +203,19 @@ This is basically the foundation of every single daemon you will write. Now we w ```powershell function Add-IcingaAgentServiceTest() { - # Allow us to parse the framework global data to this thread - param ( - $IcingaDaemonData - ); - # Import the framework library components and initialise it # as daemon Use-Icinga -LibOnly -Daemon; - # Add a synchronized hashtable to the global data background + # Add a hashtable to the public data background # daemon hashtable to write data to. In addition it will # allow to share data collected from this daemon with others - $IcingaDaemonData.BackgroundDaemon.Add( - 'TestIcingaAgentService', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.Add('TestIcingaAgentService', @{ }); + # This will add another hashtable to our previous # TestIcingaAgentService hashtable to store actual service # information - $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.Add( - 'ServiceState', - [hashtable]::Synchronized(@{ }) - ); + $Global:Icinga.Public.Daemons.TestIcingaAgentService.Add('ServiceState', @{ }); # Initialise our error counter variable [int]$RestartErrors = 0; @@ -283,7 +233,7 @@ function Add-IcingaAgentServiceTest() if ($null -ne $ServiceState) { # Add the current service state to our hashtable. Add-IcingaHashtableItem ` - -Hashtable $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.ServiceState ` + -Hashtable $Global:Icinga.Public.Daemons.TestIcingaAgentService.ServiceState ` -Key 'value' ` -Value $ServiceState.Status ` -Override | Out-Null; @@ -295,7 +245,7 @@ function Add-IcingaAgentServiceTest() Restart-Service 'icinga2' -ErrorAction Stop; Add-IcingaHashtableItem ` - -Hashtable $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.ServiceState ` + -Hashtable $Global:Icinga.Public.Daemons.TestIcingaAgentService.ServiceState ` -Key 'restart_error' ` -Value 0 ` -Override | Out-Null; @@ -303,7 +253,7 @@ function Add-IcingaAgentServiceTest() # Add an error counter in case we failed $RestartErrors += 1; Add-IcingaHashtableItem ` - -Hashtable $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.ServiceState ` + -Hashtable $Global:Icinga.Public.Daemons.TestIcingaAgentService.ServiceState ` -Key 'restart_error' ` -Value $RestartErrors ` -Override | Out-Null; @@ -322,7 +272,7 @@ function Add-IcingaAgentServiceTest() Once our function is completed we only require to call it once our daemon is registered. Do to so, we will use the Cmdlet `New-IcingaThreadInstance`. -As arguments we will have to add a unique `name` to use for this thread as well as a `thread pool`, on which the function will be added to. In our case we will use the Frameworks default pool. Last but not least we require to parse possible `Arguments` to our function and tell the thread to `Start` right after being created. For the arguments we will parse the frameworks `global` `IcingaDaemonData` we also use inside our function to store data in. +As arguments we will have to add a unique `name` to use for this thread as well as a `thread pool`, on which the function will be added to. The name of the thread is automatically constructed based on the caller function, the function being executed and the given name. If you create a thread which is used as a `main` thread for several sub-threads, you could call it `Main`. For our example, the constructed thread name will then internally be `Start-IcingaAgentServiceTest::IcingaAgentServiceTest::Main::0`. The last added digit will auto increment, in case you are adding the identical thread multiple times, allowing you to access certain threads again by their index id. For the thread pool, we will use the default thread pool `MainPool` of Icinga for Windows. To customize this, you can use `Add-IcingaThreadPool` with a unique name and the amount if allowed instances. Last but not least we require to parse possible `Arguments` to our function and tell the thread to `Start` right after being created. This call will be added inside the `Start-IcingaAgentServiceTest` we created earlier and didn't touch so far yet. @@ -333,12 +283,10 @@ function Start-IcingaAgentServiceTest() # function as command to call it and parse all our # arguments to it New-IcingaThreadInstance ` - -Name 'Icinga_PowerShell_IcingaAgent_StateCheck' ` - -ThreadPool $global:IcingaDaemonData.IcingaThreadPool.BackgroundPool ` + -Name 'Main' ` + -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') ` -Command 'Add-IcingaAgentServiceTest' ` - -CmdParameters @{ - 'IcingaDaemonData' = $global:IcingaDaemonData; - } ` + -CmdParameters @{ } ` -Start; ``` @@ -368,13 +316,13 @@ Once the service is stopped and your `administrative PowerShell` is open, we wil ```powershell Use-Icinga; -Start-IcingaPowerShellDaemon; +Start-IcingaForWindowsDaemon; ``` Once done you will receive back your prompt, however all registered background daemons are running. To access the collected data from daemons, you can print the content of the `global` framework data. If you wish to check if your daemon was loaded properly and data is actually written, we can access our created hashtable and get the current service state of it ```powershell -$global:IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.ServiceState['value']; +$Global:Icinga.Public.Daemons.TestIcingaAgentService.ServiceState['value']; ``` In case your Icinga Agent service is installed and your daemon is running properly, this should print the current state of the service. diff --git a/doc/900-Developer-Guide/12-Custom-API-Endpoints.md b/doc/900-Developer-Guide/12-Custom-API-Endpoints.md index 5b0f58e..a0e225f 100644 --- a/doc/900-Developer-Guide/12-Custom-API-Endpoints.md +++ b/doc/900-Developer-Guide/12-Custom-API-Endpoints.md @@ -110,7 +110,6 @@ function Invoke-IcingaAPITutorialRESTCall() param ( [Hashtable]$Request = @{ }, [Hashtable]$Connection = @{ }, - $IcingaGlobals, [string]$ApiVersion = $null ); } @@ -187,10 +186,6 @@ This only applies to any request which can send data as body and tells you how m This argument is containing the connection details of the client including the TCP stream object. You only require this for sending data back to the client or for troubleshooting. In general you only have to parse this object to other functions without modifying it. -#### IcingaGlobals Argument - -This argument contains all global data and content of the REST-Api background daemon. This will then come in handy to share data between API endpoints and to access some global configuration data. - ### Sending Data to the Client Now we are basically ready to process data. To do so, we will fetch the current folder content of our PowerShell module with `Get-ChildItem` and send this content to our client. For sending data to the client, we can use `Send-IcingaTCPClientMessage`. This Cmdlet will use a `Message` as `New-IcingaTCPClientRESTMessage` object which itself contains the `HTTPResponse` and our `ContentBody`. In addition to `Send-IcingaTCPClientMessage` we also have to specify the `Stream` to write to. The stream object is part of our `Connection` argument. @@ -204,7 +199,6 @@ function Invoke-IcingaAPITutorialRESTCall() param ( [Hashtable]$Request = @{ }, [Hashtable]$Connection = @{ }, - $IcingaGlobals, [string]$ApiVersion = $null ); diff --git a/icinga-powershell-framework.psm1 b/icinga-powershell-framework.psm1 index 12e0f6b..676c504 100644 --- a/icinga-powershell-framework.psm1 +++ b/icinga-powershell-framework.psm1 @@ -31,15 +31,10 @@ function Use-Icinga() } Disable-IcingaProgressPreference; + New-IcingaEnvironmentVariable; if ($Minimal) { - if ($null -eq $global:Icinga) { - $global:Icinga = @{ }; - } - - if ($global:Icinga.ContainsKey('Minimal') -eq $FALSE) { - $global:Icinga.Add('Minimal', $TRUE); - } + $Global:Icinga.Protected.Minimal = $TRUE; } # Ensure we autoload the Icinga Plugin collection, provided by the external @@ -48,50 +43,23 @@ function Use-Icinga() Use-IcingaPlugins; } - if ($LibOnly -eq $FALSE) { - $global:IcingaThreads = [hashtable]::Synchronized(@{ }); - $global:IcingaThreadContent = [hashtable]::Synchronized(@{ }); - $global:IcingaThreadPool = [hashtable]::Synchronized(@{ }); - $global:IcingaTimers = [hashtable]::Synchronized(@{ }); - $global:IcingaDaemonData = [hashtable]::Synchronized( - @{ - 'IcingaThreads' = $global:IcingaThreads; - 'IcingaThreadContent' = $global:IcingaThreadContent; - 'IcingaThreadPool' = $global:IcingaThreadPool; - 'IcingaTimers' = $global:IcingaTimers; - 'FrameworkRunningAsDaemon' = $Daemon; - 'JEAContext' = $FALSE; - 'DebugMode' = $DebugMode; - } - ); - } else { - # This will fix the debug mode in case we are only using Libs - # without any other variable content and daemon handling - if ($null -eq $global:IcingaDaemonData) { - $global:IcingaDaemonData = [hashtable]::Synchronized(@{ }); - } - if ($global:IcingaDaemonData.ContainsKey('DebugMode') -eq $FALSE) { - $global:IcingaDaemonData.DebugMode = $DebugMode; - } - if ($global:IcingaDaemonData.ContainsKey('JEAContext') -eq $FALSE) { - $global:IcingaDaemonData.JEAContext = $FALSE; - } - if ($global:IcingaDaemonData.ContainsKey('FrameworkRunningAsDaemon') -eq $FALSE) { - $global:IcingaDaemonData.FrameworkRunningAsDaemon = $Daemon; - } + if ($Daemon) { + $Global:Icinga.Protected.RunAsDaemon = $TRUE; + } + + if ($DebugMode) { + $Global:Icinga.Protected.DebugMode = $TRUE; } - New-IcingaPerformanceCounterCache; # Enable DebugMode in case it is enabled in our config if (Get-IcingaFrameworkDebugMode) { Enable-IcingaFrameworkDebugMode; - $DebugMode = $TRUE; } $EventLogMessages = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaEventLogMessages*'; foreach ($entry in $EventLogMessages.Values) { foreach ($event in $entry.Keys) { - if ($LibOnly -eq $FALSE) { + if ($LibOnly -eq $FALSE -And $Daemon -eq $FALSE) { Register-IcingaEventLog -LogName $event; } Add-IcingaHashtableItem -Hashtable $global:IcingaEventLogEnums ` @@ -100,7 +68,7 @@ function Use-Icinga() } } - if ($LibOnly -eq $FALSE) { + if ($LibOnly -eq $FALSE -And $Daemon -eq $FALSE) { Register-IcingaEventLog; } } diff --git a/lib/config/Get-IcingaPowerShellConfig.psm1 b/lib/config/Get-IcingaPowerShellConfig.psm1 index bb014ec..d98836f 100644 --- a/lib/config/Get-IcingaPowerShellConfig.psm1 +++ b/lib/config/Get-IcingaPowerShellConfig.psm1 @@ -19,7 +19,7 @@ function Get-IcingaPowerShellConfig() { - param( + param ( $Path = '' ); diff --git a/lib/config/Read-IcingaPowerShellConfig.psm1 b/lib/config/Read-IcingaPowerShellConfig.psm1 index 370b0c4..a18f19a 100644 --- a/lib/config/Read-IcingaPowerShellConfig.psm1 +++ b/lib/config/Read-IcingaPowerShellConfig.psm1 @@ -29,7 +29,7 @@ function Read-IcingaPowerShellConfig() Move-Item -Path $ConfigFile -Destination $NewConfigFile -ErrorAction SilentlyContinue; New-Item -ItemType File -Path $ConfigFile -ErrorAction SilentlyContinue; - Write-IcingaEventMessage -EventId 1100 -Namespace 'Framework' -Objects $ConfigFile, $Content; + Write-IcingaEventMessage -EventId 1100 -Namespace 'Framework' -ExceptionObject $_ -Objects $ConfigFile, $Content; Write-IcingaConsoleError -Message 'Your configuration file "{0}" was corrupt and could not be read. It was moved to "{1}" for review and a new plain file has been created' -Objects $ConfigFile, $NewConfigFile; $ConfigObject = (New-Object -TypeName PSObject); diff --git a/lib/core/dev/New-IcingaForWindowsComponent.psm1 b/lib/core/dev/New-IcingaForWindowsComponent.psm1 index 8e272f9..6d58e5d 100644 --- a/lib/core/dev/New-IcingaForWindowsComponent.psm1 +++ b/lib/core/dev/New-IcingaForWindowsComponent.psm1 @@ -101,14 +101,11 @@ function New-IcingaForWindowsComponent() Add-Content -Path $InvokeFunctionFile -Value '{'; Add-Content -Path $InvokeFunctionFile -Value ' # Do not modify the param section'; Add-Content -Path $InvokeFunctionFile -Value ' param ('; - Add-Content -Path $InvokeFunctionFile -Value ' [Hashtable]$Request = @{ },'; - Add-Content -Path $InvokeFunctionFile -Value ' [Hashtable]$Connection = @{ },'; - Add-Content -Path $InvokeFunctionFile -Value ' $IcingaGlobals,'; + Add-Content -Path $InvokeFunctionFile -Value ' [Hashtable]$Request = @{},'; + Add-Content -Path $InvokeFunctionFile -Value ' [Hashtable]$Connection = @{},'; Add-Content -Path $InvokeFunctionFile -Value ' [string]$ApiVersion = $null'; Add-Content -Path $InvokeFunctionFile -Value ' );' Add-Content -Path $InvokeFunctionFile -Value ''; - Add-Content -Path $InvokeFunctionFile -Value ' $Global:IcingaDaemonData = $IcingaGlobals;'; - Add-Content -Path $InvokeFunctionFile -Value ''; Add-Content -Path $InvokeFunctionFile -Value ' # This is the main function for your API endpoint.'; Add-Content -Path $InvokeFunctionFile -Value ' # Also check the developer guide for further details: https://icinga.com/docs/icinga-for-windows/latest/doc/900-Developer-Guide/12-Custom-API-Endpoints/'; Add-Content -Path $InvokeFunctionFile -Value ''; @@ -147,7 +144,12 @@ function New-IcingaForWindowsComponent() "'" ) ); - Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonFunction))) -Value ' -ThreadPool $IcingaDaemonData.IcingaThreadPool.BackgroundPool `'; + Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonFunction))) -Value ( + [string]::Format( + ' -ThreadPool (Get-IcingaThreadPool -Name {0}MainPool{0}) `', + "'" + ) + ); Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonFunction))) -Value ( [string]::Format( ' -Command {0}{1}{0} `', @@ -157,7 +159,7 @@ function New-IcingaForWindowsComponent() ); Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonFunction))) -Value ( [string]::Format( - ' -CmdParameters @{{ {0}IcingaDaemonData{0} = $global:IcingaDaemonData }} `', + ' -CmdParameters @{{ }} `', "'" ) ); @@ -166,9 +168,6 @@ function New-IcingaForWindowsComponent() Set-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ([string]::Format('function {0}()', $DaemonEntry)); Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value '{'; - Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' param ('; - Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' $IcingaDaemonData'; - Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' );'; Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ''; Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' # This is your main daemon function. Add your code inside the WHILE() loop which is executed once the daemon is loaded.'; Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' # Also check the developer guide for further details: https://icinga.com/docs/icinga-for-windows/latest/doc/900-Developer-Guide/10-Custom-Daemons/'; diff --git a/lib/core/framework/Clear-IcingaCheckSchedulerCheckData.psm1 b/lib/core/framework/Clear-IcingaCheckSchedulerCheckData.psm1 index 065caaa..ce58dfb 100644 --- a/lib/core/framework/Clear-IcingaCheckSchedulerCheckData.psm1 +++ b/lib/core/framework/Clear-IcingaCheckSchedulerCheckData.psm1 @@ -16,13 +16,5 @@ function Clear-IcingaCheckSchedulerCheckData() { - if ($null -eq $global:Icinga) { - return; - } - - if ($global:Icinga.ContainsKey('CheckData') -eq $FALSE) { - return; - } - - $global:Icinga.CheckData.Clear(); + $global:Icinga.Private.Scheduler.CheckData.Clear(); } diff --git a/lib/core/framework/Clear-IcingaCheckSchedulerEnvironment.psm1 b/lib/core/framework/Clear-IcingaCheckSchedulerEnvironment.psm1 index 1b71a6c..0f3dd5a 100644 --- a/lib/core/framework/Clear-IcingaCheckSchedulerEnvironment.psm1 +++ b/lib/core/framework/Clear-IcingaCheckSchedulerEnvironment.psm1 @@ -16,11 +16,18 @@ function Clear-IcingaCheckSchedulerEnvironment() { - if ($null -eq $global:Icinga) { - return; - } + param ( + [switch]$ClearCheckData = $FALSE + ); Get-IcingaCheckSchedulerPluginOutput | Out-Null; Get-IcingaCheckSchedulerPerfData | Out-Null; - Clear-IcingaCheckSchedulerCheckData; + + if ($ClearCheckData) { + Clear-IcingaCheckSchedulerCheckData; + } + + $Global:Icinga.Private.Scheduler.PluginException = $null; + $Global:Icinga.Private.Scheduler.CheckResults = $null; + $Global:Icinga.Private.Scheduler.ExitCode = $null; } diff --git a/lib/core/framework/Disable-IcingaFrameworkDebugMode.psm1 b/lib/core/framework/Disable-IcingaFrameworkDebugMode.psm1 index fa8f153..74e0e10 100644 --- a/lib/core/framework/Disable-IcingaFrameworkDebugMode.psm1 +++ b/lib/core/framework/Disable-IcingaFrameworkDebugMode.psm1 @@ -1,18 +1,18 @@ <# .SYNOPSIS - Disables the debug mode of the Framework + Disables the debug mode of the Framework .DESCRIPTION - Disables the debug mode of the Framework + Disables the debug mode of the Framework .FUNCTIONALITY - Disables the Icinga for Windows Debug-Log + Disables the Icinga for Windows Debug-Log .EXAMPLE - PS>Disable-IcingaFrameworkDebugMode; + PS>Disable-IcingaFrameworkDebugMode; .LINK - https://github.com/Icinga/icinga-powershell-framework + https://github.com/Icinga/icinga-powershell-framework #> function Disable-IcingaFrameworkDebugMode() { - $global:IcingaDaemonData.DebugMode = $FALSE; + $Global:Icinga.Protected.DebugMode = $FALSE; Set-IcingaPowerShellConfig -Path 'Framework.DebugMode' -Value $FALSE; } diff --git a/lib/core/framework/Enable-IcingaFrameworkDebugMode.psm1 b/lib/core/framework/Enable-IcingaFrameworkDebugMode.psm1 index 2e65fc6..1c9deb4 100644 --- a/lib/core/framework/Enable-IcingaFrameworkDebugMode.psm1 +++ b/lib/core/framework/Enable-IcingaFrameworkDebugMode.psm1 @@ -1,20 +1,20 @@ <# .SYNOPSIS - Enables the debug mode of the Framework to print additional details into - the Windows Event Log with Id 1000 + Enables the debug mode of the Framework to print additional details into + the Windows Event Log with Id 1000 .DESCRIPTION - Enables the debug mode of the Framework to print additional details into - the Windows Event Log with Id 1000 + Enables the debug mode of the Framework to print additional details into + the Windows Event Log with Id 1000 .FUNCTIONALITY - Enables the Icinga for Windows Debug-Log + Enables the Icinga for Windows Debug-Log .EXAMPLE - PS>Enable-IcingaFrameworkDebugMode; + PS>Enable-IcingaFrameworkDebugMode; .LINK - https://github.com/Icinga/icinga-powershell-framework + https://github.com/Icinga/icinga-powershell-framework #> function Enable-IcingaFrameworkDebugMode() { - $global:IcingaDaemonData.DebugMode = $TRUE; + $Global:Icinga.Protected.DebugMode = $TRUE; Set-IcingaPowerShellConfig -Path 'Framework.DebugMode' -Value $TRUE; } diff --git a/lib/core/framework/Get-IcingaCheckSchedulerCheckData.psm1 b/lib/core/framework/Get-IcingaCheckSchedulerCheckData.psm1 index 6c0b5b8..fc9de7a 100644 --- a/lib/core/framework/Get-IcingaCheckSchedulerCheckData.psm1 +++ b/lib/core/framework/Get-IcingaCheckSchedulerCheckData.psm1 @@ -16,13 +16,5 @@ function Get-IcingaCheckSchedulerCheckData() { - if ($null -eq $global:Icinga) { - return $null; - } - - if ($global:Icinga.ContainsKey('CheckData') -eq $FALSE) { - return @{ }; - } - - return $global:Icinga.CheckData; + return $global:Icinga.Private.Scheduler.CheckData; } diff --git a/lib/core/framework/Get-IcingaCheckSchedulerPerfData.psm1 b/lib/core/framework/Get-IcingaCheckSchedulerPerfData.psm1 index d3e4276..c522df1 100644 --- a/lib/core/framework/Get-IcingaCheckSchedulerPerfData.psm1 +++ b/lib/core/framework/Get-IcingaCheckSchedulerPerfData.psm1 @@ -1,28 +1,24 @@ <# .SYNOPSIS - Function to fetch the last executed plugin peformance data - from an internal memory cache in case the Framework is running as daemon. + Function to fetch the last executed plugin performance data + from an internal memory cache in case the Framework is running as daemon. .DESCRIPTION - While running the Framework as daemon, checkresults for plugins are not - printed into the console but written into an internal memory cache. Once - a plugin was executed, use this function to fetch the plugin performance data + While running the Framework as daemon, check results for plugins are not + printed into the console but written into an internal memory cache. Once + a plugin was executed, use this function to fetch the plugin performance data .FUNCTIONALITY - Returns the last performance data output for executed plugins while the - Framework is running as daemon + Returns the last performance data output for executed plugins while the + Framework is running as daemon .OUTPUTS - System.Object + System.Object .LINK - https://github.com/Icinga/icinga-powershell-framework + https://github.com/Icinga/icinga-powershell-framework #> function Get-IcingaCheckSchedulerPerfData() { - if ($null -eq $global:Icinga) { - return $null; - } - - $PerfData = $global:Icinga.PerfData; - $global:Icinga.PerfData = @(); + $PerfData = $Global:Icinga.Private.Scheduler.PerformanceData; + $Global:Icinga.Private.Scheduler.PerformanceData = @(); return $PerfData; } diff --git a/lib/core/framework/Get-IcingaCheckSchedulerPluginOutput.psm1 b/lib/core/framework/Get-IcingaCheckSchedulerPluginOutput.psm1 index 5a96bab..0d7945f 100644 --- a/lib/core/framework/Get-IcingaCheckSchedulerPluginOutput.psm1 +++ b/lib/core/framework/Get-IcingaCheckSchedulerPluginOutput.psm1 @@ -17,12 +17,8 @@ function Get-IcingaCheckSchedulerPluginOutput() { - if ($null -eq $global:Icinga) { - return $null; - } - - $CheckResult = [string]::Join("`r`n", $global:Icinga.CheckResults); - $global:Icinga.CheckResults = @(); + $CheckResult = [string]::Join("`r`n", $Global:Icinga.Private.Scheduler.CheckResults); + $Global:Icinga.Private.Scheduler.CheckResults = @(); return $CheckResult; } diff --git a/lib/core/framework/Get-IcingaPrivateEnvironmentVariable.psm1 b/lib/core/framework/Get-IcingaPrivateEnvironmentVariable.psm1 index 4bce893..8c2d9b7 100644 --- a/lib/core/framework/Get-IcingaPrivateEnvironmentVariable.psm1 +++ b/lib/core/framework/Get-IcingaPrivateEnvironmentVariable.psm1 @@ -22,9 +22,6 @@ function Get-IcingaPrivateEnvironmentVariable() return $null; } - # Setup the environments in case not present already - New-IcingaEnvironmentVariable; - if ($global:Icinga.Private.ContainsKey($Name) -eq $FALSE) { return $null; } diff --git a/lib/core/framework/Get-IcingaTimer.psm1 b/lib/core/framework/Get-IcingaTimer.psm1 index 960594f..6949081 100644 --- a/lib/core/framework/Get-IcingaTimer.psm1 +++ b/lib/core/framework/Get-IcingaTimer.psm1 @@ -25,7 +25,7 @@ function Get-IcingaTimer() [string]$Name = 'DefaultTimer' ); - $TimerData = Get-IcingaHashtableItem -Key $Name -Hashtable $global:IcingaDaemonData.IcingaTimers; + $TimerData = Get-IcingaHashtableItem -Key $Name -Hashtable $Global:Icinga.Private.Timers; if ($null -eq $TimerData) { return $null; diff --git a/lib/core/framework/Invoke-IcingaInternalServiceCall.psm1 b/lib/core/framework/Invoke-IcingaInternalServiceCall.psm1 index 75fb7b2..0432b9b 100644 --- a/lib/core/framework/Invoke-IcingaInternalServiceCall.psm1 +++ b/lib/core/framework/Invoke-IcingaInternalServiceCall.psm1 @@ -6,7 +6,7 @@ function Invoke-IcingaInternalServiceCall() ); # If our Framework is running as daemon, never call our api - if ($global:IcingaDaemonData.FrameworkRunningAsDaemon) { + if ($Global:Icinga.Protected.RunAsDaemon) { return; } @@ -83,10 +83,8 @@ function Invoke-IcingaInternalServiceCall() try { $ApiResult = Invoke-WebRequest -Method POST -UseBasicParsing -Uri ([string]::Format('https://localhost:{0}/v1/checker?command={1}', $RestApiPort, $Command)) -Body (ConvertTo-JsonUTF8Bytes -InputObject $CommandArguments -Depth 100 -Compress) -ContentType 'application/json' -TimeoutSec $Timeout; } catch { - # Something went wrong -> fallback to local execution - $ExMsg = $_.Exception.message; # Fallback to execute plugin locally - Write-IcingaEventMessage -Namespace 'Framework' -EventId 1553 -Objects $ExMsg, $Command, $CommandArguments; + Write-IcingaEventMessage -Namespace 'Framework' -EventId 1553 -ExceptionObject $_ -Objects $Command, $CommandArguments; return; } diff --git a/lib/core/framework/Invoke-IcingaNamespaceCmdlets.psm1 b/lib/core/framework/Invoke-IcingaNamespaceCmdlets.psm1 index d6821ec..8ef68b2 100644 --- a/lib/core/framework/Invoke-IcingaNamespaceCmdlets.psm1 +++ b/lib/core/framework/Invoke-IcingaNamespaceCmdlets.psm1 @@ -22,7 +22,7 @@ function Invoke-IcingaNamespaceCmdlets() -Key $Cmdlet.Name ` -Value $Content | Out-Null; } catch { - Write-IcingaEventMessage -EventId 1103 -Namespace 'Framework' -Objects $CommandName, $_.Exception.Message; + Write-IcingaEventMessage -EventId 1103 -Namespace 'Framework' -ExceptionObject $_ -Objects $CommandName; } } diff --git a/lib/core/framework/New-IcingaCheckSchedulerEnvironment.psm1 b/lib/core/framework/New-IcingaCheckSchedulerEnvironment.psm1 deleted file mode 100644 index 03007ab..0000000 --- a/lib/core/framework/New-IcingaCheckSchedulerEnvironment.psm1 +++ /dev/null @@ -1,48 +0,0 @@ -<# -.SYNOPSIS - Create a new environment in which we can store check results, performance data - and values over time or executed plugins. - - Usage: - - Access the string plugin output by calling `Get-IcingaCheckSchedulerPluginOutput` - Access possible performance data with `Get-IcingaCheckSchedulerPerfData` - - If you execute check plugins, ensure you read both of these functions to fetch the - result of the plugin call and to clear the stack and memory of the check data. - - If you do not require the output, you can write them to Null - - Get-IcingaCheckSchedulerPluginOutput | Out-Null; - Get-IcingaCheckSchedulerPerfData | Out-Null; - - IMPORTANT: - In addition each value for each object created with `New-IcingaCheck` is stored - with a timestamp for the check command inside a hashtable. If you do not require - these data, you MUST call `Clear-IcingaCheckSchedulerCheckData` to free memory - and clear data from the stack! - - If you are finished with all data processing and do not require anything within - memory anyway, you can safely call `Clear-IcingaCheckSchedulerEnvironment` to - do the same thing in one call. -.DESCRIPTION - Fetch the raw output values for a check command for each single object - processed by New-IcingaCheck -.FUNCTIONALITY - Fetch the raw output values for a check command for each single object - processed by New-IcingaCheck -.OUTPUTS - System.Object -.LINK - https://github.com/Icinga/icinga-powershell-framework -#> - -function New-IcingaCheckSchedulerEnvironment() -{ - # Legacy code - if ($IcingaDaemonData.IcingaThreadContent.ContainsKey('Scheduler') -eq $FALSE) { - $IcingaDaemonData.IcingaThreadContent.Add('Scheduler', @{ }); - } - - New-IcingaEnvironmentVariable; -} diff --git a/lib/core/framework/New-IcingaEnvironmentVariable.psm1 b/lib/core/framework/New-IcingaEnvironmentVariable.psm1 index 7da7989..6c51587 100644 --- a/lib/core/framework/New-IcingaEnvironmentVariable.psm1 +++ b/lib/core/framework/New-IcingaEnvironmentVariable.psm1 @@ -11,27 +11,52 @@ function New-IcingaEnvironmentVariable() { - if ($null -eq $global:Icinga) { - $global:Icinga = @{ }; + if ($null -eq $Global:Icinga) { + $Global:Icinga = @{ }; } # Session specific configuration for this shell - if ($global:Icinga.ContainsKey('Private') -eq $FALSE) { - $global:Icinga.Add('Private', @{ }); + if ($Global:Icinga.ContainsKey('Private') -eq $FALSE) { + $Global:Icinga.Add('Private', @{ }); + + $Global:Icinga.Private.Add('Daemons', @{ }); + $Global:Icinga.Private.Add('Timers', @{ }); + + $Global:Icinga.Private.Add( + 'Scheduler', + @{ + 'CheckData' = @{ }; + 'ThresholdCache' = @{ }; + 'CheckResults' = @(); + 'PerformanceData' = @(); + 'PluginException' = $null; + 'ExitCode' = $null; + } + ); } # Shared configuration for all threads - if ($global:Icinga.ContainsKey('Public') -eq $FALSE) { - $global:Icinga.Add('Public', [hashtable]::Synchronized(@{ })); + if ($Global:Icinga.ContainsKey('Public') -eq $FALSE) { + $Global:Icinga.Add('Public', [hashtable]::Synchronized(@{ })); + + $Global:Icinga.Public.Add('Daemons', @{ }); + $Global:Icinga.Public.Add('Threads', @{ }); + $Global:Icinga.Public.Add('ThreadPools', @{ }); + $Global:Icinga.Public.Add( + 'PerformanceCounter', + @{ + 'Cache' = @{ }; + } + ); } - if ($global:Icinga.ContainsKey('CheckResults') -eq $FALSE) { - $global:Icinga.Add('CheckResults', @()); - } - if ($global:Icinga.ContainsKey('PerfData') -eq $FALSE) { - $global:Icinga.Add('PerfData', @()); - } - if ($global:Icinga.ContainsKey('CheckData') -eq $FALSE) { - $global:Icinga.Add('CheckData', @{ }); + # Session specific configuration which should never be modified by users! + if ($Global:Icinga.ContainsKey('Protected') -eq $FALSE) { + $Global:Icinga.Add('Protected', @{ }); + + $Global:Icinga.Protected.Add('DebugMode', $FALSE); + $Global:Icinga.Protected.Add('JEAContext', $FALSE); + $Global:Icinga.Protected.Add('RunAsDaemon', $FALSE); + $Global:Icinga.Protected.Add('Minimal', $FALSE); } } diff --git a/lib/core/framework/Set-IcingaPrivateEnvironmentVariable.psm1 b/lib/core/framework/Set-IcingaPrivateEnvironmentVariable.psm1 index 55ee4bd..fb4dff2 100644 --- a/lib/core/framework/Set-IcingaPrivateEnvironmentVariable.psm1 +++ b/lib/core/framework/Set-IcingaPrivateEnvironmentVariable.psm1 @@ -24,9 +24,6 @@ function Set-IcingaPrivateEnvironmentVariable() return; } - # Setup the environments in case not present already - New-IcingaEnvironmentVariable; - if ($global:Icinga.Private.ContainsKey($Name) -eq $FALSE) { $global:Icinga.Private.Add($Name, $Value); return; diff --git a/lib/core/framework/Show-IcingaTimer.psm1 b/lib/core/framework/Show-IcingaTimer.psm1 index ed0be28..b925df3 100644 --- a/lib/core/framework/Show-IcingaTimer.psm1 +++ b/lib/core/framework/Show-IcingaTimer.psm1 @@ -1,25 +1,25 @@ <# .SYNOPSIS - Returns the spent time since Start-IcingaTimer was executed in seconds for - a specific timer name + Returns the spent time since Start-IcingaTimer was executed in seconds for + a specific timer name .DESCRIPTION - Returns the spent time since Start-IcingaTimer was executed in seconds for - a specific timer name + Returns the spent time since Start-IcingaTimer was executed in seconds for + a specific timer name .FUNCTIONALITY - Returns the spent time since Start-IcingaTimer was executed in seconds for - a specific timer name + Returns the spent time since Start-IcingaTimer was executed in seconds for + a specific timer name .EXAMPLE - PS>Show-IcingaTimer; + PS>Show-IcingaTimer; .EXAMPLE - PS>Show-IcingaTimer -Name 'My Test Timer'; + PS>Show-IcingaTimer -Name 'My Test Timer'; .PARAMETER Name - The name of a custom identifier to run mutliple timers at once + The name of a custom identifier to run multiple timers at once .INPUTS - System.String + System.String .OUTPUTS - Single + Single .LINK - https://github.com/Icinga/icinga-powershell-framework + https://github.com/Icinga/icinga-powershell-framework #> function Show-IcingaTimer() @@ -32,8 +32,8 @@ function Show-IcingaTimer() $TimerObject = Get-IcingaTimer -Name $Name; if (-Not $ShowAll) { - if ($null -eq $TimerObject) { - Write-IcingaConsoleNotice 'A timer with the name "{0}" does not exist' -Objects $Name; + if ($null -eq $TimerObject) { + Write-IcingaConsoleNotice 'A timer with the name "{0}" does not exist' -Objects $Name; return; } @@ -43,17 +43,17 @@ function Show-IcingaTimer() $TimerOutput | Format-Table -AutoSize; } else { - $TimerObjects = Get-IcingaHashtableItem -Key 'IcingaTimers' -Hashtable $global:IcingaDaemonData; + $TimerObjects = Get-IcingaHashtableItem -Key 'Timers' -Hashtable $Global:Icinga.Private; [array]$MultiOutput = @(); foreach ($TimerName in $TimerObjects.Keys) { - $TimerObject = $TimerObjects[$TimerName].Timer; + $TimerObject = $TimerObjects[$TimerName].Timer; - $TimerOutput = New-Object -TypeName PSObject; - $TimerOutput | Add-Member -MemberType NoteProperty -Name 'Timer Name' -Value $TimerName; - $TimerOutput | Add-Member -MemberType NoteProperty -Name 'Elapsed Seconds' -Value $TimerObject.Elapsed.TotalSeconds; - $MultiOutput += $TimerOutput; + $TimerOutput = New-Object -TypeName PSObject; + $TimerOutput | Add-Member -MemberType NoteProperty -Name 'Timer Name' -Value $TimerName; + $TimerOutput | Add-Member -MemberType NoteProperty -Name 'Elapsed Seconds' -Value $TimerObject.Elapsed.TotalSeconds; + $MultiOutput += $TimerOutput; } $MultiOutput | Format-Table -AutoSize; diff --git a/lib/core/framework/Start-IcingaTimer.psm1 b/lib/core/framework/Start-IcingaTimer.psm1 index 36f211a..8eb8e24 100644 --- a/lib/core/framework/Start-IcingaTimer.psm1 +++ b/lib/core/framework/Start-IcingaTimer.psm1 @@ -37,11 +37,9 @@ function Start-IcingaTimer() $TimerObject.Start(); Add-IcingaHashtableItem -Key $Name -Value ( - [hashtable]::Synchronized( - @{ - 'Active' = $TRUE; - 'Timer' = $TimerObject; - } - ) - ) -Hashtable $global:IcingaDaemonData.IcingaTimers -Override | Out-Null; + @{ + 'Active' = $TRUE; + 'Timer' = $TimerObject; + } + ) -Hashtable $Global:Icinga.Private.Timers -Override | Out-Null; } diff --git a/lib/core/framework/Stop-IcingaTimer.psm1 b/lib/core/framework/Stop-IcingaTimer.psm1 index 7e402bd..c5c3a10 100644 --- a/lib/core/framework/Stop-IcingaTimer.psm1 +++ b/lib/core/framework/Stop-IcingaTimer.psm1 @@ -36,11 +36,9 @@ function Stop-IcingaTimer() $TimerObject.Stop(); } Add-IcingaHashtableItem -Key $Name -Value ( - [hashtable]::Synchronized( - @{ - 'Active' = $FALSE; - 'Timer' = $TimerObject; - } - ) - ) -Hashtable $global:IcingaDaemonData.IcingaTimers -Override | Out-Null; + @{ + 'Active' = $FALSE; + 'Timer' = $TimerObject; + } + ) -Hashtable $Global:Icinga.Private.Timers -Override | Out-Null; } diff --git a/lib/core/framework/Test-IcingaTimer.psm1 b/lib/core/framework/Test-IcingaTimer.psm1 index 113c386..1023b0e 100644 --- a/lib/core/framework/Test-IcingaTimer.psm1 +++ b/lib/core/framework/Test-IcingaTimer.psm1 @@ -1,22 +1,22 @@ <# .SYNOPSIS - Tests if a specific timer object is already present and started with Start-IcingaTimer + Tests if a specific timer object is already present and started with Start-IcingaTimer .DESCRIPTION - Tests if a specific timer object is already present and started with Start-IcingaTimer + Tests if a specific timer object is already present and started with Start-IcingaTimer .FUNCTIONALITY - Tests if a specific timer object is already present and started with Start-IcingaTimer + Tests if a specific timer object is already present and started with Start-IcingaTimer .EXAMPLE - PS>Test-IcingaTimer; + PS>Test-IcingaTimer; .EXAMPLE - PS>Test-IcingaTimer -Name 'My Test Timer'; + PS>Test-IcingaTimer -Name 'My Test Timer'; .PARAMETER Name - The name of a custom identifier to run mutliple timers at once + The name of a custom identifier to run mutliple timers at once .INPUTS - System.String + System.String .OUTPUTS - Boolean + Boolean .LINK - https://github.com/Icinga/icinga-powershell-framework + https://github.com/Icinga/icinga-powershell-framework #> function Test-IcingaTimer() @@ -25,7 +25,7 @@ function Test-IcingaTimer() [string]$Name = 'DefaultTimer' ); - $TimerData = Get-IcingaHashtableItem -Key $Name -Hashtable $global:IcingaDaemonData.IcingaTimers; + $TimerData = Get-IcingaHashtableItem -Key $Name -Hashtable $Global:Icinga.Private.Timers; if ($null -eq $TimerData) { return $FALSE; diff --git a/lib/core/jea/Get-IcingaJEAConfiguration.psm1 b/lib/core/jea/Get-IcingaJEAConfiguration.psm1 index 1175769..e845e75 100644 --- a/lib/core/jea/Get-IcingaJEAConfiguration.psm1 +++ b/lib/core/jea/Get-IcingaJEAConfiguration.psm1 @@ -134,7 +134,7 @@ function Get-IcingaJEAConfiguration() -CmdName 'Exit-IcingaExecutePlugin' ` -CmdType 'Function'; - # We need to add this function for our background daemon we start with 'Start-IcingaPowerShellDaemon', + # We need to add this function for our background daemon we start with 'Start-IcingaForWindowsDaemon', # as this function is called outside the JEA context $UsedCmdlets = Get-IcingaCommandDependency ` -DependencyList $DependencyList ` diff --git a/lib/core/logging/Icinga_EventLog_Enums.psm1 b/lib/core/logging/Icinga_EventLog_Enums.psm1 index 28ca8e9..a11cac8 100644 --- a/lib/core/logging/Icinga_EventLog_Enums.psm1 +++ b/lib/core/logging/Icinga_EventLog_Enums.psm1 @@ -44,6 +44,30 @@ if ($null -eq $IcingaEventLogEnums -Or $IcingaEventLogEnums.ContainsKey('Framewo 'Details' = 'Icinga for Windows could not find the Function or Cmdlet for the specified background daemon. The daemon was not loaded.'; 'EventId' = 1400; }; + 1401 = @{ + 'EntryType' = 'Error'; + 'Message' = 'Icinga for Windows thread pool not found'; + 'Details' = 'Icinga for Windows was unable to find a specified thread pool with [Get-IcingaThreadPool] for a background daemon. To keep the daemon running, it defaulted to a basic pool but this issue should be addressed. The name of the inquired pool is:'; + 'EventId' = 1401; + }; + 1450 = @{ + 'EntryType' = 'Error'; + 'Message' = 'Icinga for Windows service check daemon invalid index'; + 'Details' = 'Icinga for Windows is unable to process the provided time index for a background service check task, as a given index is not numeric'; + 'EventId' = 1450; + }; + 1451 = @{ + 'EntryType' = 'Error'; + 'Message' = 'Icinga for Windows service check daemon exception on plugin execution'; + 'Details' = 'Icinga for Windows failed to execute a plugin within the background service check daemon with an exception'; + 'EventId' = 1451; + }; + 1452 = @{ + 'EntryType' = 'Error'; + 'Message' = 'Icinga for Windows service check daemon failed with exception'; + 'Details' = 'Icinga for Windows failed to properly execute a task within the background service check daemon with a given exception'; + 'EventId' = 1452; + }; 1500 = @{ 'EntryType' = 'Error'; 'Message' = 'Failed to securely establish a communication between this server and the client'; diff --git a/lib/core/logging/Write-IcingaConsoleOutput.psm1 b/lib/core/logging/Write-IcingaConsoleOutput.psm1 index d9988f7..8cc9211 100644 --- a/lib/core/logging/Write-IcingaConsoleOutput.psm1 +++ b/lib/core/logging/Write-IcingaConsoleOutput.psm1 @@ -52,7 +52,7 @@ function Write-IcingaConsoleOutput() } # Never write console output in case the Framework is running as daemon - if ($null -ne $global:IcingaDaemonData -And $null -ne $global:IcingaDaemonData.FrameworkRunningAsDaemon -And $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $TRUE) { + if ($Global:Icinga.Protected.RunAsDaemon -eq $TRUE) { return; } diff --git a/lib/core/logging/Write-IcingaDebugMessage.psm1 b/lib/core/logging/Write-IcingaDebugMessage.psm1 index 1d28e33..fbb2796 100644 --- a/lib/core/logging/Write-IcingaDebugMessage.psm1 +++ b/lib/core/logging/Write-IcingaDebugMessage.psm1 @@ -10,7 +10,7 @@ function Write-IcingaDebugMessage() return; } - if ($null -eq $global:IcingaDaemonData -Or $global:IcingaDaemonData.DebugMode -eq $FALSE) { + if ($Global:Icinga.Protected.DebugMode -eq $FALSE) { return; } diff --git a/lib/core/perfcounter/Add-IcingaPerformanceCounterCache.psm1 b/lib/core/perfcounter/Add-IcingaPerformanceCounterCache.psm1 index 6de6b94..f47cb39 100644 --- a/lib/core/perfcounter/Add-IcingaPerformanceCounterCache.psm1 +++ b/lib/core/perfcounter/Add-IcingaPerformanceCounterCache.psm1 @@ -27,10 +27,10 @@ function Add-IcingaPerformanceCounterCache() $Instances ); - if ($global:Icinga_PerfCounterCache.ContainsKey($Counter)) { - $global:Icinga_PerfCounterCache[$Counter] = $Instances; + if ($Global:Icinga.Public.PerformanceCounter.Cache.ContainsKey($Counter)) { + $Global:Icinga.Public.PerformanceCounter.Cache[$Counter] = $Instances; } else { - $global:Icinga_PerfCounterCache.Add( + $Global:Icinga.Public.PerformanceCounter.Cache.Add( $Counter, $Instances ); } diff --git a/lib/core/perfcounter/Get-IcingaPerformanceCounterCacheItem.psm1 b/lib/core/perfcounter/Get-IcingaPerformanceCounterCacheItem.psm1 index d14ac35..673cbec 100644 --- a/lib/core/perfcounter/Get-IcingaPerformanceCounterCacheItem.psm1 +++ b/lib/core/perfcounter/Get-IcingaPerformanceCounterCacheItem.psm1 @@ -24,8 +24,8 @@ function Get-IcingaPerformanceCounterCacheItem() $Counter ); - if ($global:Icinga_PerfCounterCache.ContainsKey($Counter)) { - return $global:Icinga_PerfCounterCache[$Counter]; + if ($Global:Icinga.Public.PerformanceCounter.Cache.ContainsKey($Counter)) { + return $Global:Icinga.Public.PerformanceCounter.Cache[$Counter]; } return $null; diff --git a/lib/core/perfcounter/New-IcingaPerformanceCounterArray.psm1 b/lib/core/perfcounter/New-IcingaPerformanceCounterArray.psm1 index 367391a..77323b4 100644 --- a/lib/core/perfcounter/New-IcingaPerformanceCounterArray.psm1 +++ b/lib/core/perfcounter/New-IcingaPerformanceCounterArray.psm1 @@ -55,9 +55,8 @@ function New-IcingaPerformanceCounterArray() # TODO: Add a cache for our Performance Counters to only fetch them once # for each session to speed up the loading. This cold be something like # this: - # New-IcingaPerformanceCounterCache $CounterResult; - # Internally we could do something like this - # $global:Icinga_PerfCounterCache += $CounterResult; + # + # $Global:Icinga.Public.PerformanceCounter.Cache += $CounterResult; # Above we initialise ever single counter and we only require a sleep once # in case a new, yet unknown counter was added diff --git a/lib/core/perfcounter/New-IcingaPerformanceCounterCache.psm1 b/lib/core/perfcounter/New-IcingaPerformanceCounterCache.psm1 deleted file mode 100644 index 998186e..0000000 --- a/lib/core/perfcounter/New-IcingaPerformanceCounterCache.psm1 +++ /dev/null @@ -1,23 +0,0 @@ -<# -.SYNOPSIS - Initialises the internal cache storage for Performance Counters -.DESCRIPTION - Initialises the internal cache storage for Performance Counters -.FUNCTIONALITY - Initialises the internal cache storage for Performance Counters -.EXAMPLE - PS>New-IcingaPerformanceCounterCache; -.LINK - https://github.com/Icinga/icinga-powershell-framework -#> - -function New-IcingaPerformanceCounterCache() -{ - if ($null -eq $global:Icinga_PerfCounterCache) { - $global:Icinga_PerfCounterCache = ( - [hashtable]::Synchronized( - @{ } - ) - ); - } -} diff --git a/lib/core/thread/Add-IcingaThreadPool.psm1 b/lib/core/thread/Add-IcingaThreadPool.psm1 new file mode 100644 index 0000000..222a05f --- /dev/null +++ b/lib/core/thread/Add-IcingaThreadPool.psm1 @@ -0,0 +1,17 @@ +function Add-IcingaThreadPool() +{ + param ( + [string]$Name = '', + [int]$MinInstances = 1, + [int]$MaxInstances = 5 + ); + + if ($Global:Icinga.Public.ThreadPools.ContainsKey($Name)) { + return; + } + + $Global:Icinga.Public.ThreadPools.Add( + $Name, + (New-IcingaThreadPool -MinInstances $MinInstances -MaxInstances $MaxInstances) + ); +} diff --git a/lib/core/thread/Get-IcingaThreadPool.psm1 b/lib/core/thread/Get-IcingaThreadPool.psm1 new file mode 100644 index 0000000..498cf6d --- /dev/null +++ b/lib/core/thread/Get-IcingaThreadPool.psm1 @@ -0,0 +1,14 @@ +function Get-IcingaThreadPool() +{ + param ( + [string]$Name + ); + + if ($Global:Icinga.Public.ThreadPools.ContainsKey($Name)) { + return $Global:Icinga.Public.ThreadPools[$Name]; + } + + Write-IcingaEventMessage -Namespace 'Framework' -EventId 1401 -Objects $Name; + + return (New-IcingaThreadPool); +} diff --git a/lib/core/thread/New-IcingaThreadInstance.psm1 b/lib/core/thread/New-IcingaThreadInstance.psm1 index 040edc2..e9ee6db 100644 --- a/lib/core/thread/New-IcingaThreadInstance.psm1 +++ b/lib/core/thread/New-IcingaThreadInstance.psm1 @@ -10,14 +10,19 @@ function New-IcingaThreadInstance() [Switch]$Start ); + $CallStack = Get-PSCallStack; + $SourceCommand = $CallStack[1].Command; + if ([string]::IsNullOrEmpty($Name)) { $Name = New-IcingaThreadHash -ShellScript $ScriptBlock -Arguments $Arguments; } + $ThreadName = [string]::Format('{0}::{1}::{2}::0', $SourceCommand, $Command, $Name); + Write-IcingaDebugMessage -Message ( [string]::Format( 'Creating new thread instance {0}{1}Arguments:{1}{2}', - $Name, + $ThreadName, "`r`n", ($Arguments | Out-String) ) @@ -29,10 +34,17 @@ function New-IcingaThreadInstance() if ([string]::IsNullOrEmpty($Command) -eq $FALSE) { + # Initialize the Icinga for Windows environment in each thread [void]$Shell.AddCommand('Use-Icinga'); [void]$Shell.AddParameter('-LibOnly', $TRUE); [void]$Shell.AddParameter('-Daemon', $TRUE); + # Share our public data between all threads + if ($null -ne $Global:Icinga -And $Global:Icinga.ContainsKey('Public')) { + [void]$Shell.AddCommand('Set-IcingaEnvironmentGlobal'); + [void]$Shell.AddParameter('GlobalEnvironment', $Global:Icinga.Public); + } + [void]$Shell.AddCommand($Command); $CodeHash = $Command; @@ -76,12 +88,16 @@ function New-IcingaThreadInstance() Add-Member -InputObject $Thread -MemberType NoteProperty -Name Started -Value $FALSE; } - if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Name) -eq $FALSE) { - $global:IcingaDaemonData.IcingaThreads.Add($Name, $Thread); - } else { - $global:IcingaDaemonData.IcingaThreads.Add( - (New-IcingaThreadHash -ShellScript $CodeHash -Arguments $Arguments), - $Thread - ); + [int]$ThreadIndex = 0; + + while ($TRUE) { + + if ($Global:Icinga.Public.Threads.ContainsKey($ThreadName) -eq $FALSE) { + $Global:Icinga.Public.Threads.Add($ThreadName, $Thread); + break; + } + + $ThreadIndex += 1; + $ThreadName = [string]::Format('{0}::{1}::{2}::{3}', $SourceCommand, $Command, $Name, $ThreadIndex); } } diff --git a/lib/core/thread/Remove-IcingaThread.psm1 b/lib/core/thread/Remove-IcingaThread.psm1 index 60f48c5..4dc7e1a 100644 --- a/lib/core/thread/Remove-IcingaThread.psm1 +++ b/lib/core/thread/Remove-IcingaThread.psm1 @@ -10,8 +10,10 @@ function Remove-IcingaThread() Stop-IcingaThread -Thread $Thread; - if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread)) { - $global:IcingaDaemonData.IcingaThreads[$Thread].Shell.Dispose(); - $global:IcingaDaemonData.IcingaThreads.Remove($Thread); + if ($Global:Icinga.Public.Threads.ContainsKey($Thread)) { + $Global:Icinga.Public.Threads[$Thread].Shell.Dispose(); + $Global:Icinga.Public.Threads.Remove($Thread); + + Write-IcingaDebugMessage 'Removing Thread: {0}' -Objects $Thread; } } diff --git a/lib/core/thread/Set-IcingaEnvironmentGlobal.psm1 b/lib/core/thread/Set-IcingaEnvironmentGlobal.psm1 new file mode 100644 index 0000000..e881cd3 --- /dev/null +++ b/lib/core/thread/Set-IcingaEnvironmentGlobal.psm1 @@ -0,0 +1,16 @@ +function Set-IcingaEnvironmentGlobal() +{ + param ( + $GlobalEnvironment = $null + ); + + if ($null -eq $GlobalEnvironment -Or $null -eq $Global:Icinga) { + return; + } + + if ($Global:Icinga.ContainsKey('Public') -eq $FALSE) { + return; + } + + $Global:Icinga.Public = $GlobalEnvironment; +} diff --git a/lib/core/thread/Start-IcingaThread.psm1 b/lib/core/thread/Start-IcingaThread.psm1 index 09eb6ba..7bd6c7f 100644 --- a/lib/core/thread/Start-IcingaThread.psm1 +++ b/lib/core/thread/Start-IcingaThread.psm1 @@ -8,10 +8,10 @@ function Start-IcingaThread() return; } - if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread)) { - if ($global:IcingaDaemonData.IcingaThreads[$Thread].Started -eq $FALSE) { - $global:IcingaDaemonData.IcingaThreads[$Thread].Handle = $global:IcingaDaemonData.IcingaThreads[$Thread].Shell.BeginInvoke(); - $global:IcingaDaemonData.IcingaThreads[$Thread].Started = $TRUE; + if ($Global:Icinga.Public.Threads.ContainsKey($Thread)) { + if ($Global:Icinga.Public.Threads[$Thread].Started -eq $FALSE) { + $Global:Icinga.Public.Threads[$Thread].Handle = $Global:Icinga.Public.Threads[$Thread].Shell.BeginInvoke(); + $Global:Icinga.Public.Threads[$Thread].Started = $TRUE; } } } diff --git a/lib/core/thread/Stop-IcingaThread.psm1 b/lib/core/thread/Stop-IcingaThread.psm1 index e78f4a0..e934b74 100644 --- a/lib/core/thread/Stop-IcingaThread.psm1 +++ b/lib/core/thread/Stop-IcingaThread.psm1 @@ -8,11 +8,11 @@ function Stop-IcingaThread() return; } - if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread)) { - if ($global:IcingaDaemonData.IcingaThreads[$Thread].Started -eq $TRUE) { - $global:IcingaDaemonData.IcingaThreads[$Thread].Shell.Stop(); - $global:IcingaDaemonData.IcingaThreads[$Thread].Handle = $null; - $global:IcingaDaemonData.IcingaThreads[$Thread].Started = $FALSE; + if ($Global:Icinga.Public.Threads.ContainsKey($Thread)) { + if ($Global:Icinga.Public.Threads[$Thread].Started -eq $TRUE) { + $Global:Icinga.Public.Threads[$Thread].Shell.Stop(); + $Global:Icinga.Public.Threads[$Thread].Handle = $null; + $Global:Icinga.Public.Threads[$Thread].Started = $FALSE; } } } diff --git a/lib/core/thread/Test-IcingaThread.psm1 b/lib/core/thread/Test-IcingaThread.psm1 index 1ff7d23..addbf3e 100644 --- a/lib/core/thread/Test-IcingaThread.psm1 +++ b/lib/core/thread/Test-IcingaThread.psm1 @@ -8,5 +8,5 @@ function Test-IcingaThread() return $FALSE; } - return $global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread); + return $Global:Icinga.Public.Threads.ContainsKey($Thread); } diff --git a/lib/daemon/Add-IcingaForWindowsDaemon.psm1 b/lib/daemon/Add-IcingaForWindowsDaemon.psm1 index 895bc95..1933359 100644 --- a/lib/daemon/Add-IcingaForWindowsDaemon.psm1 +++ b/lib/daemon/Add-IcingaForWindowsDaemon.psm1 @@ -1,12 +1,5 @@ function Add-IcingaForWindowsDaemon() { - param ( - $IcingaDaemonData - ); - - Use-Icinga -LibOnly -Daemon; - $Global:IcingaDaemonData = $IcingaDaemonData; - try { $EnabledDaemons = Get-IcingaBackgroundDaemons; diff --git a/lib/daemon/Start-IcingaPowerShellDaemon.psm1 b/lib/daemon/Start-IcingaPowerShellDaemon.psm1 index 5da3754..565f65c 100644 --- a/lib/daemon/Start-IcingaPowerShellDaemon.psm1 +++ b/lib/daemon/Start-IcingaPowerShellDaemon.psm1 @@ -5,8 +5,17 @@ function Start-IcingaPowerShellDaemon() [switch]$JEARestart = $FALSE ); - $global:IcingaDaemonData.FrameworkRunningAsDaemon = $TRUE; + Start-IcingaForWindowsDaemon -RunAsService:$RunAsService -JEARestart:$JEARestart; +} +function Start-IcingaForWindowsDaemon() +{ + param ( + [switch]$RunAsService = $FALSE, + [switch]$JEARestart = $FALSE + ); + + $Global:Icinga.Protected.RunAsDaemon = $TRUE; [string]$MainServicePidFile = (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'service.pid'); [string]$JeaPidFile = (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'jea.pid'); [string]$JeaProfile = Get-IcingaPowerShellConfig -Path 'Framework.JEAProfile'; @@ -23,13 +32,13 @@ function Start-IcingaPowerShellDaemon() if ([string]::IsNullOrEmpty($JeaProfile)) { Write-IcingaDebugMessage -Message 'Starting Icinga for Windows service without JEA context' -Objects $RunAsService, $JEARestart, $JeaProfile; - $global:IcingaDaemonData.FrameworkRunningAsDaemon = $TRUE; - $global:IcingaDaemonData.Add('BackgroundDaemon', [hashtable]::Synchronized(@{ })); + $Global:Icinga.Protected.RunAsDaemon = $TRUE; # Todo: Add config for active background tasks. Set it to 20 for the moment - $global:IcingaDaemonData.IcingaThreadPool.Add('BackgroundPool', (New-IcingaThreadPool -MaxInstances 20)); - $global:IcingaDaemonData.Add('SSLCertificate', $Certificate); + Add-IcingaThreadPool -Name 'MainPool' -MaxInstances 20; + $Global:Icinga.Public.Add('SSLCertificate', $Certificate); - New-IcingaThreadInstance -Name "Icinga_PowerShell_Background_Daemon" -ThreadPool $IcingaDaemonData.IcingaThreadPool.BackgroundPool -Command 'Add-IcingaForWindowsDaemon' -CmdParameters @{ 'IcingaDaemonData' = $global:IcingaDaemonData } -Start; + + New-IcingaThreadInstance -Name "Main" -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') -Command 'Add-IcingaForWindowsDaemon' -Start; } else { Write-IcingaDebugMessage -Message 'Starting Icinga for Windows service inside JEA context' -Objects $RunAsService, $JEARestart, $JeaProfile; & powershell.exe -NoProfile -NoLogo -ConfigurationName $JeaProfile -Command { @@ -38,24 +47,19 @@ function Start-IcingaPowerShellDaemon() Write-IcingaFileSecure -File ($args[1]) -Value $PID; - $Global:IcingaDaemonData.JEAContext = $TRUE; - $global:IcingaDaemonData.FrameworkRunningAsDaemon = $TRUE; - $global:IcingaDaemonData.Add('BackgroundDaemon', [hashtable]::Synchronized(@{ })); + $Global:Icinga.Protected.JEAContext = $TRUE; + $Global:Icinga.Protected.RunAsDaemon = $TRUE; # Todo: Add config for active background tasks. Set it to 20 for the moment - $global:IcingaDaemonData.IcingaThreadPool.Add('BackgroundPool', (New-IcingaThreadPool -MaxInstances 20)); - $global:IcingaDaemonData.Add('SSLCertificate', ($args[0])); + Add-IcingaThreadPool -Name 'MainPool' -MaxInstances 20; + $Global:Icinga.Public.Add('SSLCertificate', $args[0]); - New-IcingaThreadInstance -Name "Icinga_PowerShell_Background_Daemon" -ThreadPool $IcingaDaemonData.IcingaThreadPool.BackgroundPool -Command 'Add-IcingaForWindowsDaemon' -CmdParameters @{ 'IcingaDaemonData' = $global:IcingaDaemonData } -Start; + New-IcingaThreadInstance -Name "Main" -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') -Command 'Add-IcingaForWindowsDaemon' -Start; while ($TRUE) { Start-Sleep -Seconds 100; } } catch { - $CallStack = @(); - foreach ($entry in (Get-PSCallStack)) { - $CallStack += [string]::Format('{0} => Line {1}', $entry.FunctionName, $entry.ScriptLineNumber); - } - Write-IcingaEventMessage -EventId 1600 -Namespace Framework -Objects $_.Exception.Message, $_.Exception.StackTrace, $CallStack; + Write-IcingaEventMessage -EventId 1600 -Namespace 'Framework' -ExceptionObject $_; } } -Args $Certificate, $JeaPidFile; } @@ -80,7 +84,7 @@ function Start-IcingaPowerShellDaemon() Write-IcingaFileSecure -File $JeaPidFile -Value ''; Write-IcingaEventMessage -EventId 1505 -Namespace Framework -Objects ([string]::Format('{0}/5', $JeaRestartCounter)); - Start-IcingaPowerShellDaemon -RunAsService:$RunAsService -JEARestart; + Start-IcingaForWindowsDaemon -RunAsService:$RunAsService -JEARestart; $JeaRestartCounter += 1; $JeaPid = ''; diff --git a/lib/daemons/RestAPI/client/Invoke-IcingaRESTAPIv1Calls.psm1 b/lib/daemons/RestAPI/client/Invoke-IcingaRESTAPIv1Calls.psm1 index f757abb..8f57680 100644 --- a/lib/daemons/RestAPI/client/Invoke-IcingaRESTAPIv1Calls.psm1 +++ b/lib/daemons/RestAPI/client/Invoke-IcingaRESTAPIv1Calls.psm1 @@ -6,8 +6,6 @@ function Invoke-IcingaRESTAPIv1Calls() ); [string]$ModuleToLoad = Get-IcingaRESTPathElement -Request $Request -Index 1; - # Map our Icinga globals to a shorter variable - $RestDaemon = $IcingaDaemonData.BackgroundDaemon.IcingaPowerShellRestApi; if ([string]::IsNullOrEmpty($ModuleToLoad)) { Send-IcingaTCPClientMessage -Message ( @@ -15,14 +13,14 @@ function Invoke-IcingaRESTAPIv1Calls() -HTTPResponse ($IcingaHTTPEnums.HTTPResponseType.Ok) ` -ContentBody @{ 'Endpoints' = @( - $RestDaemon.RegisteredEndpoints.Keys + $Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints.Keys ) } ) -Stream $Connection.Stream; return; } - if ($RestDaemon.RegisteredEndpoints.ContainsKey($ModuleToLoad) -eq $FALSE) { + if ($Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints.ContainsKey($ModuleToLoad) -eq $FALSE) { Send-IcingaTCPClientMessage -Message ( New-IcingaTCPClientRESTMessage ` -HTTPResponse ($IcingaHTTPEnums.HTTPResponseType.'Not Found') ` @@ -31,7 +29,7 @@ function Invoke-IcingaRESTAPIv1Calls() return; } - [string]$Command = $RestDaemon.RegisteredEndpoints[$ModuleToLoad]; + [string]$Command = $Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints[$ModuleToLoad]; Write-IcingaDebugMessage -Message 'Executing REST-Module' -Objects $Command; @@ -47,7 +45,6 @@ function Invoke-IcingaRESTAPIv1Calls() [hashtable]$CommandArguments = @{ '-Request' = $Request; '-Connection' = $Connection; - '-IcingaGlobals' = $IcingaDaemonData; '-ApiVersion' = 'v1'; }; diff --git a/lib/daemons/RestAPI/client/Test-IcingaRESTClientConnection.psm1 b/lib/daemons/RestAPI/client/Test-IcingaRESTClientConnection.psm1 index 8f96402..828902e 100644 --- a/lib/daemons/RestAPI/client/Test-IcingaRESTClientConnection.psm1 +++ b/lib/daemons/RestAPI/client/Test-IcingaRESTClientConnection.psm1 @@ -9,7 +9,7 @@ function Test-IcingaRESTClientConnection() if ($null -eq $Connection.Stream) { Add-IcingaRESTClientBlacklistCount ` -Client $Connection.Client ` - -ClientList $IcingaDaemonData.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist; + -ClientList $Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist; Write-IcingaEventMessage -EventId 1501 -Namespace 'Framework' -Objects $Connection.Client.Client; Close-IcingaTCPConnection -Client $Connection.Client; $Connection = $null; diff --git a/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 b/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 index 3b85641..1bb9b70 100644 --- a/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 +++ b/lib/daemons/RestAPI/daemon/New-IcingaForWindowsRESTApi.psm1 @@ -2,10 +2,8 @@ function New-IcingaForWindowsRESTApi() { # Allow us to parse the framework global data to this thread param ( - $IcingaDaemonData, [string]$Address = '', $Port, - $RootFolder, $CertFile, $CertThumbprint, $RequireAuth @@ -15,49 +13,6 @@ function New-IcingaForWindowsRESTApi() # as daemon Use-Icinga -LibOnly -Daemon; - $Global:IcingaDaemonData = $IcingaDaemonData; - - # Add a synchronized hashtable to the global data background - # daemon hashtable to write data to. In addition it will - # allow to share data collected from this daemon with others - $IcingaDaemonData.BackgroundDaemon.Add( - 'IcingaPowerShellRestApi', - [hashtable]::Synchronized(@{ }) - ); - - # Map our Icinga globals to a shorter variable - $RestDaemon = $IcingaDaemonData.BackgroundDaemon.IcingaPowerShellRestApi; - - # This will add another hashtable to our previous - # IcingaPowerShellRestApi hashtable to store actual - # endpoint configurations for the API - $RestDaemon.Add( - 'RegisteredEndpoints', - [hashtable]::Synchronized(@{ }) - ); - - # This will add another hashtable to our previous - # IcingaPowerShellRestApi hashtable to store actual - # command aliases for execution for the API - $RestDaemon.Add( - 'CommandAliases', - [hashtable]::Synchronized(@{ }) - ); - - # This will add another hashtable to our previous - # IcingaPowerShellRestApi hashtable to store actual - # command aliases for execution for the API - $RestDaemon.Add( - 'ClientBlacklist', - [hashtable]::Synchronized(@{ }) - ); - - # Make the root folder of our rest daemon module available - # for every possible thread we require - $RestDaemon.Add( - 'RootFolder', $RootFolder - ); - $RESTEndpoints = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaRESTAPIEndpoint*'; Write-IcingaDebugMessage -Message ( [string]::Format( @@ -67,12 +22,13 @@ function New-IcingaForWindowsRESTApi() ) ); - Write-IcingaDebugMessage -Message ($RestDaemon | Out-String); + Write-IcingaDebugMessage -Message ($Global:Icinga.Public.Daemons.RESTApi | Out-String); foreach ($entry in $RESTEndpoints.Values) { - [bool]$Success = Add-IcingaHashtableItem -Hashtable $RestDaemon.RegisteredEndpoints ` - -Key $entry.Alias ` - -Value $entry.Command; + [bool]$Success = Add-IcingaHashtableItem ` + -Hashtable $Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints ` + -Key $entry.Alias ` + -Value $entry.Command; if ($Success -eq $FALSE) { Write-IcingaEventMessage ` @@ -86,9 +42,10 @@ function New-IcingaForWindowsRESTApi() foreach ($entry in $CommandAliases.Values) { foreach ($component in $entry.Keys) { - [bool]$Success = Add-IcingaHashtableItem -Hashtable $RestDaemon.CommandAliases ` - -Key $component ` - -Value $entry[$component]; + [bool]$Success = Add-IcingaHashtableItem ` + -Hashtable $Global:Icinga.Public.Daemons.RESTApi.CommandAliases ` + -Key $component ` + -Value $entry[$component]; if ($Success -eq $FALSE) { Write-IcingaEventMessage ` @@ -99,15 +56,15 @@ function New-IcingaForWindowsRESTApi() } } - Write-IcingaDebugMessage -Message ($RestDaemon.RegisteredEndpoints | Out-String); + Write-IcingaDebugMessage -Message ($Global:Icinga.Public.Daemons.RESTApi.RegisteredEndpoints | Out-String); - if ($Global:IcingaDaemonData.JEAContext) { - if ($global:IcingaDaemonData.ContainsKey('SSLCertificate') -eq $FALSE -Or $null -eq $global:IcingaDaemonData.SSLCertificate) { + if ($Global:Icinga.Protected.JEAContext) { + if ($Global:Icinga.Public.ContainsKey('SSLCertificate') -eq $FALSE -Or $null -eq $Global:Icinga.Public.SSLCertificate) { Write-IcingaEventMessage -EventId 2001 -Namespace 'RESTApi'; return; } - $Certificate = $global:IcingaDaemonData.SSLCertificate; + $Certificate = $Global:Icinga.Public.SSLCertificate; } else { $Certificate = Get-IcingaSSLCertForSocket -CertFile $CertFile -CertThumbprint $CertThumbprint; } @@ -131,7 +88,7 @@ function New-IcingaForWindowsRESTApi() -Client (New-IcingaTCPClient -Socket $Socket) ` -Certificate $Certificate; - if (Test-IcingaRESTClientBlacklisted -Client $Connection.Client -ClientList $RestDaemon.ClientBlacklist) { + if (Test-IcingaRESTClientBlacklisted -Client $Connection.Client -ClientList $Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist) { Write-IcingaDebugMessage -Message 'A remote client which is trying to connect was blacklisted' -Objects $Connection.Client.Client; Close-IcingaTCPConnection -Client $Connection.Client; continue; @@ -142,7 +99,7 @@ function New-IcingaForWindowsRESTApi() } # API not yet ready - if ($IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.Count -eq 0) { + if ($Global:Icinga.Public.Daemons.RESTApi.ApiRequests.Count -eq 0) { Close-IcingaTCPConnection -Client $Connection.Client; continue; } @@ -150,15 +107,14 @@ function New-IcingaForWindowsRESTApi() try { $NextRESTApiThreadId = (Get-IcingaNextRESTApiThreadId); - if ($IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.ContainsKey($NextRESTApiThreadId) -eq $FALSE) { + if ($Global:Icinga.Public.Daemons.RESTApi.ApiRequests.ContainsKey($NextRESTApiThreadId) -eq $FALSE) { Close-IcingaTCPConnection -Client $Connection.Client; continue; } - $IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.$NextRESTApiThreadId.Enqueue($Connection); + $Global:Icinga.Public.Daemons.RESTApi.ApiRequests.$NextRESTApiThreadId.Enqueue($Connection); } catch { - $ExMsg = $_.Exception.Message; - Write-IcingaEventMessage -Namespace 'RESTApi' -EvenId 2050 -Objects $ExMsg; + Write-IcingaEventMessage -Namespace 'RESTApi' -EvenId 2050 -ExceptionObject $_; } } } diff --git a/lib/daemons/RestAPI/daemon/Start-IcingaWindowsRESTApi.psm1 b/lib/daemons/RestAPI/daemon/Start-IcingaWindowsRESTApi.psm1 index 182d79d..e3fb782 100644 --- a/lib/daemons/RestAPI/daemon/Start-IcingaWindowsRESTApi.psm1 +++ b/lib/daemons/RestAPI/daemon/Start-IcingaWindowsRESTApi.psm1 @@ -54,29 +54,20 @@ function Start-IcingaWindowsRESTApi() [int]$Timeout = 30 ); - $RootFolder = $PSScriptRoot; - - $global:IcingaDaemonData.IcingaThreadContent.Add('RESTApi', ([hashtable]::Synchronized(@{ }))); - $global:IcingaDaemonData.IcingaThreadPool.Add('IcingaRESTApi', (New-IcingaThreadPool -MaxInstances ($ThreadId + 3))); - $global:IcingaDaemonData.IcingaThreadContent.RESTApi.Add('ApiRequests', ([hashtable]::Synchronized(@{ }))); - $global:IcingaDaemonData.IcingaThreadContent.RESTApi.Add('ApiCallThreadAssignment', ([hashtable]::Synchronized(@{ }))); - $global:IcingaDaemonData.IcingaThreadContent.RESTApi.Add('TotalThreads', $ConcurrentThreads); - $global:IcingaDaemonData.IcingaThreadContent.RESTApi.Add('LastThreadId', 0); + New-IcingaForWindowsRESTEnvironment -ThreadCount $ConcurrentThreads; # Now create a new thread for our REST-Api, assign a name and parse all required arguments to it. # Last but not least start it directly New-IcingaThreadInstance ` - -Name 'Icinga_for_Windows_REST_Api' ` - -ThreadPool $global:IcingaDaemonData.IcingaThreadPool.IcingaRESTApi ` + -Name 'Main' ` + -ThreadPool (Get-IcingaThreadPool -Name 'RESTApiPool') ` -Command 'New-IcingaForWindowsRESTApi' ` -CmdParameters @{ - 'IcingaDaemonData' = $global:IcingaDaemonData; - 'Address' = $Address; - 'Port' = $Port; - 'RootFolder' = $RootFolder; - 'CertFile' = $CertFile; - 'CertThumbprint' = $CertThumbprint; - 'RequireAuth' = $RequireAuth; + 'Address' = $Address; + 'Port' = $Port; + 'CertFile' = $CertFile; + 'CertThumbprint' = $CertThumbprint; + 'RequireAuth' = $RequireAuth; } ` -Start; @@ -85,7 +76,7 @@ function Start-IcingaWindowsRESTApi() while ($ConcurrentThreads -gt 0) { $ConcurrentThreads = $ConcurrentThreads - 1; [System.Collections.Queue]$RESTThreadQueue = @(); - $global:IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.Add($ThreadId, [System.Collections.Queue]::Synchronized($RESTThreadQueue)); + $Global:Icinga.Public.Daemons.RESTApi.ApiRequests.Add($ThreadId, [System.Collections.Queue]::Synchronized($RESTThreadQueue)); Start-IcingaForWindowsRESTThread -ThreadId $ThreadId -RequireAuth:$RequireAuth; $ThreadId += 1; diff --git a/lib/daemons/RestAPI/threads/Get-IcingaNextRESTApiThreadId.psm1 b/lib/daemons/RestAPI/threads/Get-IcingaNextRESTApiThreadId.psm1 index 00132ca..0895009 100644 --- a/lib/daemons/RestAPI/threads/Get-IcingaNextRESTApiThreadId.psm1 +++ b/lib/daemons/RestAPI/threads/Get-IcingaNextRESTApiThreadId.psm1 @@ -1,13 +1,13 @@ function Get-IcingaNextRESTApiThreadId() { - [int]$ConcurrentThreads = $IcingaDaemonData.IcingaThreadContent.RESTApi.TotalThreads - 1; - [int]$LastThreadId = $IcingaDaemonData.IcingaThreadContent.RESTApi.LastThreadId + 1; + [int]$ConcurrentThreads = $Global:Icinga.Public.Daemons.RESTApi.TotalThreads - 1; + [int]$LastThreadId = $Global:Icinga.Public.Daemons.RESTApi.LastThreadId + 1; if ($LastThreadId -gt $ConcurrentThreads) { $LastThreadId = 0; } - $IcingaDaemonData.IcingaThreadContent.RESTApi.LastThreadId = $LastThreadId; + $Global:Icinga.Public.Daemons.RESTApi.LastThreadId = $LastThreadId; return $LastThreadId; } diff --git a/lib/daemons/RestAPI/threads/New-IcingaForWindowsRESTThread.psm1 b/lib/daemons/RestAPI/threads/New-IcingaForWindowsRESTThread.psm1 index c1ae195..0775cf6 100644 --- a/lib/daemons/RestAPI/threads/New-IcingaForWindowsRESTThread.psm1 +++ b/lib/daemons/RestAPI/threads/New-IcingaForWindowsRESTThread.psm1 @@ -1,7 +1,6 @@ function New-IcingaForWindowsRESTThread() { param( - $IcingaDaemonData, $RequireAuth, $ThreadId ); @@ -9,7 +8,6 @@ function New-IcingaForWindowsRESTThread() # Import the framework library components and initialise it # as daemon Use-Icinga -LibOnly -Daemon; - $Global:IcingaDaemonData = $IcingaDaemonData; # Initialise our performance counter categories Show-IcingaPerformanceCounterCategories | Out-Null; @@ -17,17 +15,17 @@ function New-IcingaForWindowsRESTThread() while ($TRUE) { try { - if ($IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.ContainsKey($ThreadId) -eq $FALSE) { + if ($Global:Icinga.Public.Daemons.RESTApi.ApiRequests.ContainsKey($ThreadId) -eq $FALSE) { Start-Sleep -Milliseconds 10; continue; } - if ($IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.$ThreadId.Count -eq 0) { + if ($Global:Icinga.Public.Daemons.RESTApi.ApiRequests.$ThreadId.Count -eq 0) { Start-Sleep -Milliseconds 10; continue; } - $Connection = $IcingaDaemonData.IcingaThreadContent.RESTApi.ApiRequests.$ThreadId.Dequeue(); + $Connection = $Global:Icinga.Public.Daemons.RESTApi.ApiRequests.$ThreadId.Dequeue(); if ($null -eq $Connection) { Start-Sleep -Milliseconds 10; @@ -49,7 +47,7 @@ function New-IcingaForWindowsRESTThread() # to ensure we are not spammed and "attacked" by a client with useless requests Add-IcingaRESTClientBlacklistCount ` -Client $Connection.Client ` - -ClientList $IcingaDaemonData.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist; + -ClientList $Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist; # Send the authentication prompt Send-IcingaWebAuthMessage -Connection $Connection; # Close the connection @@ -66,7 +64,7 @@ function New-IcingaForWindowsRESTThread() # Failed attempts should increase the blacklist counter Add-IcingaRESTClientBlacklistCount ` -Client $Connection.Client ` - -ClientList $IcingaDaemonData.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist; + -ClientList $Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist; # Re-send the authentication prompt Send-IcingaWebAuthMessage -Connection $Connection; # Close the connection @@ -76,7 +74,7 @@ function New-IcingaForWindowsRESTThread() } # We should remove clients from the blacklist who are sending valid requests - Remove-IcingaRESTClientBlacklist -Client $Connection.Client -ClientList $IcingaDaemonData.BackgroundDaemon.IcingaPowerShellRestApi.ClientBlacklist; + Remove-IcingaRESTClientBlacklist -Client $Connection.Client -ClientList $Global:Icinga.Public.Daemons.RESTApi.ClientBlacklist; switch (Get-IcingaRESTPathElement -Request $RESTRequest -Index 0) { 'v1' { Invoke-IcingaRESTAPIv1Calls -Request $RESTRequest -Connection $Connection; @@ -101,7 +99,7 @@ function New-IcingaForWindowsRESTThread() -ContentBody $ExMsg ) -Stream $Connection.Stream; - Write-IcingaEventMessage -Namespace 'RESTApi' -EventId 2051 -Objects $ExMsg; + Write-IcingaEventMessage -Namespace 'RESTApi' -EventId 2051 -ExceptionObject $_; } # Finally close the clients connection as we are done here and diff --git a/lib/daemons/RestAPI/threads/Start-IcingaForWindowsRESTThread.psm1 b/lib/daemons/RestAPI/threads/Start-IcingaForWindowsRESTThread.psm1 index 03cdbbc..8921c34 100644 --- a/lib/daemons/RestAPI/threads/Start-IcingaForWindowsRESTThread.psm1 +++ b/lib/daemons/RestAPI/threads/Start-IcingaForWindowsRESTThread.psm1 @@ -8,13 +8,12 @@ function Start-IcingaForWindowsRESTThread() # Now create a new thread, assign a name and parse all required arguments to it. # Last but not least start it directly New-IcingaThreadInstance ` - -Name ([string]::Format("Icinga_Windows_REST_Api_Thread_{0}", $ThreadId)) ` + -Name 'CheckThread' ` -ThreadPool (New-IcingaThreadPool -MaxInstances 1) ` -Command 'New-IcingaForWindowsRESTThread' ` -CmdParameters @{ - 'IcingaDaemonData' = $global:IcingaDaemonData; - 'RequireAuth' = $RequireAuth; - 'ThreadId' = $ThreadId; + 'RequireAuth' = $RequireAuth; + 'ThreadId' = $ThreadId; } ` -Start; } diff --git a/lib/daemons/RestAPI/tools/New-IcingaForWindowsRESTEnvironment.psm1 b/lib/daemons/RestAPI/tools/New-IcingaForWindowsRESTEnvironment.psm1 new file mode 100644 index 0000000..2836636 --- /dev/null +++ b/lib/daemons/RestAPI/tools/New-IcingaForWindowsRESTEnvironment.psm1 @@ -0,0 +1,30 @@ +function New-IcingaForWindowsRESTEnvironment() +{ + param ( + [int]$ThreadCount = 5 + ); + + $Global:Icinga.Public.Daemons.Add( + 'RESTApi', + @{ + 'ApiRequests' = @{ }; + 'ApiCallThreadAssignment' = @{ }; + 'TotalThreads' = $ThreadCount; + 'LastThreadId' = 0; + # This will add another hashtable to our previous + # IcingaPowerShellRestApi hashtable to store actual + # endpoint configurations for the API + 'RegisteredEndpoints' = @{ }; + # This will add another hashtable to our previous + # IcingaPowerShellRestApi hashtable to store actual + # command aliases for execution for the API + 'CommandAliases' = @{ }; + # This will add another hashtable to our previous + # IcingaPowerShellRestApi hashtable to store actual + # command aliases for execution for the API + 'ClientBlacklist' = @{ }; + } + ); + + Add-IcingaThreadPool -Name 'RESTApiPool' -MaxInstances ($ThreadCount * 2); +} diff --git a/lib/daemons/ServiceCheckDaemon/Add-IcingaServiceCheckTask.psm1 b/lib/daemons/ServiceCheckDaemon/Add-IcingaServiceCheckTask.psm1 deleted file mode 100644 index 33fc4f8..0000000 --- a/lib/daemons/ServiceCheckDaemon/Add-IcingaServiceCheckTask.psm1 +++ /dev/null @@ -1,161 +0,0 @@ -function Add-IcingaServiceCheckTask() -{ - param ( - $IcingaDaemonData, - $CheckCommand, - $Arguments, - $Interval, - $TimeIndexes, - $CheckId - ); - - Use-Icinga -LibOnly -Daemon; - - $PassedTime = 0; - $SortedResult = $null; - $PerfCache = @{ }; - $AverageCalc = @{ }; - [int]$MaxTime = 0; - - # Initialise some global variables we use to actually store check result data from - # plugins properly. This is doable from each thread instance as this part isn't - # shared between daemons - New-IcingaCheckSchedulerEnvironment; - - foreach ($index in $TimeIndexes) { - # Only allow numeric index values - if ((Test-Numeric $index) -eq $FALSE) { - continue; - } - if ($AverageCalc.ContainsKey([string]$index) -eq $FALSE) { - $AverageCalc.Add( - [string]$index, - @{ - 'Interval' = ([int]$index); - 'Time' = ([int]$index * 60); - 'Sum' = 0; - 'Count' = 0; - } - ); - } - if ($MaxTime -le [int]$index) { - $MaxTime = [int]$index; - } - } - - [int]$MaxTimeInSeconds = $MaxTime * 60; - - if (-Not ($global:Icinga.CheckData.ContainsKey($CheckCommand))) { - $global:Icinga.CheckData.Add($CheckCommand, @{ }); - $global:Icinga.CheckData[$CheckCommand].Add('results', @{ }); - $global:Icinga.CheckData[$CheckCommand].Add('average', @{ }); - } - - $LoadedCacheData = Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName $CheckCommand; - - if ($null -ne $LoadedCacheData) { - foreach ($entry in $LoadedCacheData.PSObject.Properties) { - $global:Icinga.CheckData[$CheckCommand]['results'].Add( - $entry.name, - @{ } - ); - foreach ($item in $entry.Value.PSObject.Properties) { - $global:Icinga.CheckData[$CheckCommand]['results'][$entry.name].Add( - $item.Name, - $item.Value - ); - } - } - } - - while ($TRUE) { - if ($PassedTime -ge $Interval) { - try { - & $CheckCommand @Arguments | Out-Null; - } catch { - # Just for debugging. Not required in production or usable at all - $ErrMsg = $_.Exception.Message; - Write-IcingaConsoleError $ErrMsg; - } - - try { - $UnixTime = Get-IcingaUnixTime; - - foreach ($result in $global:Icinga.CheckData[$CheckCommand]['results'].Keys) { - [string]$HashIndex = $result; - $SortedResult = $global:Icinga.CheckData[$CheckCommand]['results'][$HashIndex].GetEnumerator() | Sort-Object name -Descending; - Add-IcingaHashtableItem -Hashtable $PerfCache -Key $HashIndex -Value @{ } | Out-Null; - - foreach ($timeEntry in $SortedResult) { - - if ((Test-Numeric $timeEntry.Value) -eq $FALSE) { - continue; - } - - foreach ($calc in $AverageCalc.Keys) { - if (($UnixTime - $AverageCalc[$calc].Time) -le [int]$timeEntry.Key) { - $AverageCalc[$calc].Sum += $timeEntry.Value; - $AverageCalc[$calc].Count += 1; - } - } - if (($UnixTime - $MaxTimeInSeconds) -le [int]$timeEntry.Key) { - Add-IcingaHashtableItem -Hashtable $PerfCache[$HashIndex] -Key ([string]$timeEntry.Key) -Value ([string]$timeEntry.Value) | Out-Null; - } - } - - foreach ($calc in $AverageCalc.Keys) { - if ($AverageCalc[$calc].Count -ne 0) { - $AverageValue = ($AverageCalc[$calc].Sum / $AverageCalc[$calc].Count); - [string]$MetricName = Format-IcingaPerfDataLabel ( - [string]::Format('{0}_{1}', $HashIndex, $AverageCalc[$calc].Interval) - ); - - Add-IcingaHashtableItem ` - -Hashtable $global:Icinga.CheckData[$CheckCommand]['average'] ` - -Key $MetricName -Value $AverageValue -Override | Out-Null; - } - - $AverageCalc[$calc].Sum = 0; - $AverageCalc[$calc].Count = 0; - } - } - - # Flush data we no longer require in our cache to free memory - [array]$CheckStores = $global:Icinga.CheckData[$CheckCommand]['results'].Keys; - - foreach ($CheckStore in $CheckStores) { - [string]$CheckKey = $CheckStore; - [array]$CheckTimeStamps = $global:Icinga.CheckData[$CheckCommand]['results'][$CheckKey].Keys; - - foreach ($TimeSample in $CheckTimeStamps) { - if (($UnixTime - $MaxTimeInSeconds) -gt [int]$TimeSample) { - Remove-IcingaHashtableItem -Hashtable $global:Icinga.CheckData[$CheckCommand]['results'][$CheckKey] -Key ([string]$TimeSample); - } - } - } - - Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $CheckCommand -Value $global:Icinga.CheckData[$CheckCommand]['average']; - # Write collected metrics to disk in case we reload the daemon. We will load them back into the module after reload then - Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName $CheckCommand -Value $PerfCache; - } catch { - # Just for debugging. Not required in production or usable at all - $ErrMsg = $_.Exception.Message; - Write-IcingaConsoleError 'Failed to handle check result processing: {0}' -Objects $ErrMsg; - } - - # Always ensure our check data is cleared regardless of possible - # exceptions which might occur - Get-IcingaCheckSchedulerPerfData | Out-Null; - Get-IcingaCheckSchedulerPluginOutput | Out-Null; - - $PassedTime = 0; - $SortedResult.Clear(); - $PerfCache.Clear(); - } - - $PassedTime += 1; - Start-Sleep -Seconds 1; - # Force Icinga for Windows Garbage Collection - Optimize-IcingaForWindowsMemory -ClearErrorStack; - } -} diff --git a/lib/daemons/ServiceCheckDaemon/Start-IcingaServiceCheckDaemon.psm1 b/lib/daemons/ServiceCheckDaemon/Start-IcingaServiceCheckDaemon.psm1 deleted file mode 100644 index 3dc127d..0000000 --- a/lib/daemons/ServiceCheckDaemon/Start-IcingaServiceCheckDaemon.psm1 +++ /dev/null @@ -1,86 +0,0 @@ -<# -.SYNOPSIS - A background daemon executing registered service checks in the background to fetch - metrics for certain checks over time. Time frames are configurable individual -.DESCRIPTION - This background daemon will execute checks registered with "Register-IcingaServiceCheck" - for the given time interval and store the collected metrics for a defined period of time - inside a JSON file. Check values collected by this daemon are then automatically added - to regular check executions for additional performance metrics. - - Example: Register-IcingaServiceCheck -CheckCommand 'Invoke-IcingaCheckCPU' -Interval 30 -TimeIndexes 1,3,5,15; - - This will execute the CPU check every 30 seconds and calculate the average of 1, 3, 5 and 15 minutes - - More Information on - https://icinga.com/docs/icinga-for-windows/latest/doc/service/02-Register-Daemons/ - https://icinga.com/docs/icinga-for-windows/latest/doc/service/10-Register-Service-Checks/ -.LINK - https://github.com/Icinga/icinga-powershell-framework -.NOTES -#> - -function Start-IcingaServiceCheckDaemon() -{ - New-IcingaThreadInstance -Name "Icinga_PowerShell_ServiceCheck_Scheduler" -ThreadPool $IcingaDaemonData.IcingaThreadPool.BackgroundPool -Command 'Add-IcingaServiceCheckDaemon' -CmdParameters @{ 'IcingaDaemonData' = $global:IcingaDaemonData } -Start; -} - -function Add-IcingaServiceCheckDaemon() -{ - param ( - $IcingaDaemonData - ); - - Use-Icinga -LibOnly -Daemon; - - $IcingaDaemonData.IcingaThreadPool.Add('ServiceCheckPool', (New-IcingaThreadPool -MaxInstances (Get-IcingaConfigTreeCount -Path 'BackgroundDaemon.RegisteredServices'))); - - while ($TRUE) { - - $RegisteredServices = Get-IcingaRegisteredServiceChecks; - - foreach ($service in $RegisteredServices.Keys) { - [string]$ThreadName = [string]::Format('Icinga_Background_Service_Check_{0}', $service); - if ((Test-IcingaThread $ThreadName)) { - continue; - } - - [hashtable]$ServiceArgs = @{ }; - - if ($null -ne $RegisteredServices[$service].Arguments) { - foreach ($property in $RegisteredServices[$service].Arguments.PSObject.Properties) { - if ($ServiceArgs.ContainsKey($property.Name)) { - continue; - } - - $ServiceArgs.Add($property.Name, $property.Value) - } - } - - Start-IcingaServiceCheckTask -CheckId $service -CheckCommand $RegisteredServices[$service].CheckCommand -Arguments $ServiceArgs -Interval $RegisteredServices[$service].Interval -TimeIndexes $RegisteredServices[$service].TimeIndexes; - } - Start-Sleep -Seconds 1; - } -} - -function Start-IcingaServiceCheckTask() -{ - param( - $CheckId, - $CheckCommand, - $Arguments, - $Interval, - $TimeIndexes - ); - - [string]$ThreadName = [string]::Format('Icinga_Background_Service_Check_{0}', $CheckId); - - New-IcingaThreadInstance -Name $ThreadName -ThreadPool $IcingaDaemonData.IcingaThreadPool.ServiceCheckPool -Command 'Add-IcingaServiceCheckTask' -CmdParameters @{ - 'IcingaDaemonData' = $global:IcingaDaemonData; - 'CheckCommand' = $CheckCommand; - 'Arguments' = $Arguments; - 'Interval' = $Interval; - 'TimeIndexes' = $TimeIndexes - 'CheckId' = $CheckId; - } -Start; -} diff --git a/lib/daemons/ServiceCheckDaemon/daemon/Add-IcingaServiceCheckDaemon.psm1 b/lib/daemons/ServiceCheckDaemon/daemon/Add-IcingaServiceCheckDaemon.psm1 new file mode 100644 index 0000000..f06dd13 --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/daemon/Add-IcingaServiceCheckDaemon.psm1 @@ -0,0 +1,85 @@ +function Add-IcingaServiceCheckDaemon() +{ + Add-IcingaThreadPool -Name 'ServiceCheckPool' -MaxInstances 100; + + [hashtable]$KnownChecks = @{ }; + + $Global:Icinga.Public.Daemons.Add( + 'ServiceCheck', + @{ + 'PerformanceDataCache' = @{ } + } + ); + + while ($TRUE) { + + # Load the configuration file to be aware of service check changes + $RegisteredServices = Get-IcingaRegisteredServiceChecks; + + # Debugging message + Write-IcingaDebugMessage 'Found these service checks to load within service check daemon: {0}' -Objects ($RegisteredServices.Keys | Out-String); + + # Loop all found background services and create a new thread for each check + foreach ($service in $RegisteredServices.Keys) { + [string]$ThreadName = [string]::Format('Start-IcingaServiceCheckTask::Add-IcingaServiceCheckTask::{0}::0', $service); + + # In case the check is already being executed, continue + if ((Test-IcingaThread -Thread $ThreadName)) { + continue; + } + + # Get all possible arguments for this check + [hashtable]$ServiceArgs = @{ }; + + if ($null -ne $RegisteredServices[$service].Arguments) { + foreach ($property in $RegisteredServices[$service].Arguments.PSObject.Properties) { + if ($ServiceArgs.ContainsKey($property.Name)) { + continue; + } + + $ServiceArgs.Add($property.Name, $property.Value) + } + } + + # Add the check to our cache, ensuring that we are aware of modifications during runtime + if ($KnownChecks.ContainsKey($service) -eq $FALSE) { + $KnownChecks.Add($service, $TRUE); + } else { + $KnownChecks[$service] = $TRUE; + } + + # Start a new thread for executing the check + Start-IcingaServiceCheckTask ` + -CheckId $service ` + -CheckCommand $RegisteredServices[$service].CheckCommand ` + -Arguments $ServiceArgs ` + -Interval $RegisteredServices[$service].Interval ` + -TimeIndexes $RegisteredServices[$service].TimeIndexes; + } + + # Cleanup + [array]$KnownCheckIds = $KnownChecks.Keys; + + foreach ($entry in $KnownCheckIds) { + if ($RegisteredServices.ContainsKey($entry)) { + continue; + } + + $KnownChecks[$entry] = $FALSE; + } + + foreach ($entry in $KnownCheckIds) { + if ($KnownChecks[$entry] -eq $FALSE) { + $KnownChecks.Remove($entry); + + [string]$ThreadName = [string]::Format('Start-IcingaServiceCheckTask::Add-IcingaServiceCheckTask::{0}::0', $entry); + + Remove-IcingaThread -Thread $ThreadName; + } + } + + Optimize-IcingaForWindowsMemory; + + Start-Sleep -Seconds 10; + } +} diff --git a/lib/daemons/ServiceCheckDaemon/daemon/Start-IcingaServiceCheckDaemon.psm1 b/lib/daemons/ServiceCheckDaemon/daemon/Start-IcingaServiceCheckDaemon.psm1 new file mode 100644 index 0000000..c51639d --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/daemon/Start-IcingaServiceCheckDaemon.psm1 @@ -0,0 +1,30 @@ +<# +.SYNOPSIS + A background daemon executing registered service checks in the background to fetch + metrics for certain checks over time. Time frames are configurable individual +.DESCRIPTION + This background daemon will execute checks registered with "Register-IcingaServiceCheck" + for the given time interval and store the collected metrics for a defined period of time + inside a JSON file. Check values collected by this daemon are then automatically added + to regular check executions for additional performance metrics. + + Example: Register-IcingaServiceCheck -CheckCommand 'Invoke-IcingaCheckCPU' -Interval 30 -TimeIndexes 1,3,5,15; + + This will execute the CPU check every 30 seconds and calculate the average of 1, 3, 5 and 15 minutes + + More Information on + https://icinga.com/docs/icinga-for-windows/latest/doc/service/02-Register-Daemons/ + https://icinga.com/docs/icinga-for-windows/latest/doc/service/10-Register-Service-Checks/ +.LINK + https://github.com/Icinga/icinga-powershell-framework +.NOTES +#> + +function Start-IcingaServiceCheckDaemon() +{ + New-IcingaThreadInstance ` + -Name 'Main' ` + -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') ` + -Command 'Add-IcingaServiceCheckDaemon' ` + -Start; +} diff --git a/lib/daemons/ServiceCheckDaemon/task/Add-IcingaServiceCheckTask.psm1 b/lib/daemons/ServiceCheckDaemon/task/Add-IcingaServiceCheckTask.psm1 new file mode 100644 index 0000000..a551fe2 --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/task/Add-IcingaServiceCheckTask.psm1 @@ -0,0 +1,138 @@ +function Add-IcingaServiceCheckTask() +{ + param ( + $CheckCommand, + $Arguments, + $Interval, + $TimeIndexes, + $CheckId + ); + + # $Global:Icinga.Private.Daemons.ServiceCheck + New-IcingaServiceCheckDaemonEnvironment ` + -CheckCommand $CheckCommand ` + -Arguments $Arguments ` + -TimeIndexes $TimeIndexes; + + # Read our check result store data from disk for this service check + Read-IcingaCheckResultStore -CheckCommand $CheckCommand; + + while ($TRUE) { + if ($Global:Icinga.Private.Daemons.ServiceCheck.PassedTime -lt $Interval) { + $Global:Icinga.Private.Daemons.ServiceCheck.PassedTime += 1; + Start-Sleep -Seconds 1; + + continue; + } + + $Global:Icinga.Private.Daemons.ServiceCheck.PassedTime = 0; + + # Execute our check with possible arguments + try { + & $CheckCommand @Arguments | Out-Null; + } catch { + Write-IcingaEventMessage -EventId 1451 -Namespace 'Framework' -ExceptionObject $_ -Objects $CheckCommand, ($Arguments | Out-String), (Get-IcingaInternalPluginOutput); + + Clear-IcingaCheckSchedulerEnvironment; + + # Force Icinga for Windows Garbage Collection + Optimize-IcingaForWindowsMemory -ClearErrorStack; + + continue; + } + + $UnixTime = Get-IcingaUnixTime; + + try { + foreach ($result in $global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'].Keys) { + [string]$HashIndex = $result; + $Global:Icinga.Private.Daemons.ServiceCheck.SortedResult = $global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'][$HashIndex].GetEnumerator() | Sort-Object name -Descending; + + Add-IcingaHashtableItem ` + -Hashtable $Global:Icinga.Private.Daemons.ServiceCheck.PerformanceCache ` + -Key $HashIndex ` + -Value @{ } | Out-Null; + + foreach ($timeEntry in $Global:Icinga.Private.Daemons.ServiceCheck.SortedResult) { + + if ((Test-Numeric $timeEntry.Value) -eq $FALSE) { + continue; + } + + foreach ($calc in $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation.Keys) { + if (($UnixTime - $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Time) -le [int]$timeEntry.Key) { + $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Sum += $timeEntry.Value; + $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Count += 1; + } + } + if (($UnixTime - $Global:Icinga.Private.Daemons.ServiceCheck.MaxTimeInSeconds) -le [int]$timeEntry.Key) { + Add-IcingaHashtableItem ` + -Hashtable $Global:Icinga.Private.Daemons.ServiceCheck.PerformanceCache[$HashIndex] ` + -Key ([string]$timeEntry.Key) ` + -Value ([string]$timeEntry.Value) | Out-Null; + } + } + + foreach ($calc in $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation.Keys) { + if ($Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Count -ne 0) { + $AverageValue = ($Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Sum / $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Count); + [string]$MetricName = Format-IcingaPerfDataLabel ( + [string]::Format('{0}_{1}', $HashIndex, $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Interval) + ); + + $Global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['average'] | Add-Member -MemberType NoteProperty -Name $MetricName -Value $AverageValue -Force; + } + + $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Sum = 0; + $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation[$calc].Count = 0; + } + } + + Write-IcingaDebugMessage ` + -Message 'Object dump of service check daemon' ` + -Objects @( + $CheckCommand, + 'Average Calc', + ($Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation | Out-String), + 'PerformanceCache', + $Global:Icinga.Private.Daemons.ServiceCheck.PerformanceCache, + 'Max Time in Seconds', + $Global:Icinga.Private.Daemons.ServiceCheck.MaxTimeInSeconds, + 'Unix Time', + $UnixTime + ); + + # Flush data we no longer require in our cache to free memory + [array]$CheckStores = $Global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'].Keys; + + foreach ($CheckStore in $CheckStores) { + [string]$CheckKey = $CheckStore; + [array]$CheckTimeStamps = $global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'][$CheckKey].Keys; + + foreach ($TimeSample in $CheckTimeStamps) { + if (($UnixTime - $Global:Icinga.Private.Daemons.ServiceCheck.MaxTimeInSeconds) -gt [int]$TimeSample) { + Remove-IcingaHashtableItem -Hashtable $global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'][$CheckKey] -Key ([string]$TimeSample); + } + } + } + + Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $CheckCommand -Value $global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['average']; + + # Make the performance data available for all threads + $Global:Icinga.Public.Daemons.ServiceCheck.PerformanceDataCache[$CheckCommand] = $global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['average']; + # Write collected metrics to disk in case we reload the daemon. We will load them back into the module after reload then + Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName $CheckCommand -Value $Global:Icinga.Private.Daemons.ServiceCheck.PerformanceCache; + + } catch { + Write-IcingaEventMessage -EventId 1452 -Namespace 'Framework' -ExceptionObject $_ -Objects $CheckCommand, ($Arguments | Out-String), (Get-IcingaInternalPluginOutput); + } + + # Always ensure our check data is cleared regardless of possible + # exceptions which might occur + Clear-IcingaCheckSchedulerEnvironment; + # Reset certain values from the scheduler environment + Clear-IcingaServiceCheckDaemonEnvironment; + # Force Icinga for Windows Garbage Collection + Optimize-IcingaForWindowsMemory -ClearErrorStack; + } +} diff --git a/lib/daemons/ServiceCheckDaemon/task/Start-IcingaServiceCheckTask.psm1 b/lib/daemons/ServiceCheckDaemon/task/Start-IcingaServiceCheckTask.psm1 new file mode 100644 index 0000000..eeba988 --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/task/Start-IcingaServiceCheckTask.psm1 @@ -0,0 +1,18 @@ +function Start-IcingaServiceCheckTask() +{ + param ( + $CheckId, + $CheckCommand, + $Arguments, + $Interval, + $TimeIndexes + ); + + New-IcingaThreadInstance -Name $CheckId -ThreadPool (Get-IcingaThreadPool -Name 'ServiceCheckPool') -Command 'Add-IcingaServiceCheckTask' -CmdParameters @{ + 'CheckCommand' = $CheckCommand; + 'Arguments' = $Arguments; + 'Interval' = $Interval; + 'TimeIndexes' = $TimeIndexes + 'CheckId' = $CheckId; + } -Start; +} diff --git a/lib/daemons/ServiceCheckDaemon/tools/Clear-IcingaServiceCheckDaemonEnvironment.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Clear-IcingaServiceCheckDaemonEnvironment.psm1 new file mode 100644 index 0000000..9dacf5a --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/tools/Clear-IcingaServiceCheckDaemonEnvironment.psm1 @@ -0,0 +1,6 @@ +function Clear-IcingaServiceCheckDaemonEnvironment() +{ + $Global:Icinga.Private.Daemons.ServiceCheck.PassedTime = 0; + $Global:Icinga.Private.Daemons.ServiceCheck.SortedResult.Clear(); + $Global:Icinga.Private.Daemons.ServiceCheck.PerformanceCache.Clear(); +} diff --git a/lib/daemons/ServiceCheckDaemon/Get-IcingaRegisteredServiceChecks.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Get-IcingaRegisteredServiceChecks.psm1 similarity index 100% rename from lib/daemons/ServiceCheckDaemon/Get-IcingaRegisteredServiceChecks.psm1 rename to lib/daemons/ServiceCheckDaemon/tools/Get-IcingaRegisteredServiceChecks.psm1 diff --git a/lib/daemons/ServiceCheckDaemon/tools/New-IcingaServiceCheckDaemonEnvironment.psm1 b/lib/daemons/ServiceCheckDaemon/tools/New-IcingaServiceCheckDaemonEnvironment.psm1 new file mode 100644 index 0000000..51d6818 --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/tools/New-IcingaServiceCheckDaemonEnvironment.psm1 @@ -0,0 +1,60 @@ +function New-IcingaServiceCheckDaemonEnvironment() +{ + param ( + $CheckCommand, + $Arguments, + $TimeIndexes + ); + + if ($Global:Icinga.Public.Daemons.ServiceCheck.PerformanceDataCache.ContainsKey($CheckCommand) -eq $FALSE) { + $Global:Icinga.Public.Daemons.ServiceCheck.PerformanceDataCache.Add( + $CheckCommand, @{ } + ); + } + + $Global:Icinga.Private.Daemons.Add( + 'ServiceCheck', + @{ + 'PassedTime' = 0; + 'SortedResult' = $null; + 'PerformanceCache' = @{ }; + 'AverageCalculation' = @{ }; + 'MaxTime' = 0; + 'MaxTimeInSeconds' = 0; + } + ); + + foreach ($index in $TimeIndexes) { + # Only allow numeric index values + if ((Test-Numeric $index) -eq $FALSE) { + Write-IcingaEventMessage -EventId 1450 -Namespace 'Framework' -Objects $CheckCommand, ($Arguments | Out-String), ($TimeIndexes | Out-String), $index; + continue; + } + if ($Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation.ContainsKey([string]$index) -eq $FALSE) { + $Global:Icinga.Private.Daemons.ServiceCheck.AverageCalculation.Add( + [string]$index, + @{ + 'Interval' = ([int]$index); + 'Time' = ([int]$index * 60); + 'Sum' = 0; + 'Count' = 0; + } + ); + } + if ($Global:Icinga.Private.Daemons.ServiceCheck.MaxTime -le [int]$index) { + $Global:Icinga.Private.Daemons.ServiceCheck.MaxTime = [int]$index; + } + } + + $Global:Icinga.Private.Daemons.ServiceCheck.MaxTimeInSeconds = $Global:Icinga.Private.Daemons.ServiceCheck.MaxTime * 60; + + if ($Global:Icinga.Private.Scheduler.CheckData.ContainsKey($CheckCommand) -eq $FALSE) { + $Global:Icinga.Private.Scheduler.CheckData.Add( + $CheckCommand, + @{ + 'results' = @{ }; + 'average' = (New-Object -TypeName PSObject); + } + ); + } +} diff --git a/lib/daemons/ServiceCheckDaemon/tools/Read-IcingaCheckResultStore.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Read-IcingaCheckResultStore.psm1 new file mode 100644 index 0000000..4c2a538 --- /dev/null +++ b/lib/daemons/ServiceCheckDaemon/tools/Read-IcingaCheckResultStore.psm1 @@ -0,0 +1,23 @@ +function Read-IcingaCheckResultStore() +{ + param ( + $CheckCommand + ); + + $LoadedCacheData = Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName $CheckCommand; + + if ($null -ne $LoadedCacheData) { + foreach ($entry in $LoadedCacheData.PSObject.Properties) { + $Global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'].Add( + $entry.name, + @{ } + ); + foreach ($item in $entry.Value.PSObject.Properties) { + $Global:Icinga.Private.Scheduler.CheckData[$CheckCommand]['results'][$entry.name].Add( + $item.Name, + $item.Value + ); + } + } + } +} diff --git a/lib/daemons/ServiceCheckDaemon/Register-IcingaServiceCheck.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Register-IcingaServiceCheck.psm1 similarity index 100% rename from lib/daemons/ServiceCheckDaemon/Register-IcingaServiceCheck.psm1 rename to lib/daemons/ServiceCheckDaemon/tools/Register-IcingaServiceCheck.psm1 diff --git a/lib/daemons/ServiceCheckDaemon/Set-IcingaRegisteredServiceCheckConfig.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Set-IcingaRegisteredServiceCheckConfig.psm1 similarity index 100% rename from lib/daemons/ServiceCheckDaemon/Set-IcingaRegisteredServiceCheckConfig.psm1 rename to lib/daemons/ServiceCheckDaemon/tools/Set-IcingaRegisteredServiceCheckConfig.psm1 diff --git a/lib/daemons/ServiceCheckDaemon/Show-IcingaRegisteredServiceChecks.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Show-IcingaRegisteredServiceChecks.psm1 similarity index 100% rename from lib/daemons/ServiceCheckDaemon/Show-IcingaRegisteredServiceChecks.psm1 rename to lib/daemons/ServiceCheckDaemon/tools/Show-IcingaRegisteredServiceChecks.psm1 diff --git a/lib/daemons/ServiceCheckDaemon/Unregister-IcingaServiceCheck.psm1 b/lib/daemons/ServiceCheckDaemon/tools/Unregister-IcingaServiceCheck.psm1 similarity index 100% rename from lib/daemons/ServiceCheckDaemon/Unregister-IcingaServiceCheck.psm1 rename to lib/daemons/ServiceCheckDaemon/tools/Unregister-IcingaServiceCheck.psm1 diff --git a/lib/daemons/modules/ApiChecks/Invoke-IcingaApiChecksRESTCall.psm1 b/lib/daemons/modules/ApiChecks/Invoke-IcingaApiChecksRESTCall.psm1 index 18a0f22..2c22891 100644 --- a/lib/daemons/modules/ApiChecks/Invoke-IcingaApiChecksRESTCall.psm1 +++ b/lib/daemons/modules/ApiChecks/Invoke-IcingaApiChecksRESTCall.psm1 @@ -3,21 +3,13 @@ function Invoke-IcingaApiChecksRESTCall() param ( [Hashtable]$Request = @{ }, [Hashtable]$Connection = @{ }, - $IcingaGlobals, [string]$ApiVersion = $null ); - $Global:IcingaDaemonData = $IcingaGlobals; - - # Initialise some global variables we use to actually store check result data from - # plugins properly. This is doable from each thread instance as this part isn't - # shared between daemons - New-IcingaCheckSchedulerEnvironment; - [Hashtable]$ContentResponse = @{ }; # Short our call - $CheckerAliases = $IcingaGlobals.BackgroundDaemon.IcingaPowerShellRestApi.CommandAliases.checker; + $CheckerAliases = $Global:Icinga.Public.Daemons.RESTApi.CommandAliases.checker; $CheckConfig = $Request.Body; [int]$ExitCode = 3; #Unknown @@ -117,7 +109,7 @@ function Invoke-IcingaApiChecksRESTCall() } # Free our memory again - Clear-IcingaCheckSchedulerEnvironment; + Clear-IcingaCheckSchedulerEnvironment -ClearCheckData; Write-IcingaDebugMessage -Message 'Check Executed. Result below' -Objects $ExecuteCommand, $CheckResult, $PerfData, $ExitCode; diff --git a/lib/icinga/exception/Exit-IcingaThrowCritical.psm1 b/lib/icinga/exception/Exit-IcingaThrowCritical.psm1 index c1f5883..33ff956 100644 --- a/lib/icinga/exception/Exit-IcingaThrowCritical.psm1 +++ b/lib/icinga/exception/Exit-IcingaThrowCritical.psm1 @@ -25,7 +25,7 @@ function Exit-IcingaThrowCritical() Set-IcingaInternalPluginExitCode -ExitCode $IcingaEnums.IcingaExitCode.Critical; Set-IcingaInternalPluginException -PluginException $OutputMessage; - if ($null -eq $global:IcingaDaemonData -Or ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE -And $global:IcingaDaemonData.JEAContext -eq $FALSE)) { + if ($Global:Icinga.Protected.RunAsDaemon -eq $FALSE -And $Global:Icinga.Protected.JEAContext -eq $FALSE) { Write-IcingaConsolePlain $OutputMessage; exit $IcingaEnums.IcingaExitCode.Critical; } diff --git a/lib/icinga/exception/Exit-IcingaThrowException.psm1 b/lib/icinga/exception/Exit-IcingaThrowException.psm1 index 41922b9..11aa8cd 100644 --- a/lib/icinga/exception/Exit-IcingaThrowException.psm1 +++ b/lib/icinga/exception/Exit-IcingaThrowException.psm1 @@ -110,7 +110,7 @@ function Exit-IcingaThrowException() Set-IcingaInternalPluginExitCode -ExitCode $IcingaEnums.IcingaExitCode.Unknown; Set-IcingaInternalPluginException -PluginException $OutputMessage; - if ($null -eq $global:IcingaDaemonData -Or ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE -And $global:IcingaDaemonData.JEAContext -eq $FALSE)) { + if ($Global:Icinga.Protected.RunAsDaemon -eq $FALSE -And $Global:Icinga.Protected.JEAContext -eq $FALSE) { Write-IcingaConsolePlain $OutputMessage; exit $IcingaEnums.IcingaExitCode.Unknown; } diff --git a/lib/icinga/plugin/Exit-IcingaExecutePlugin.psm1 b/lib/icinga/plugin/Exit-IcingaExecutePlugin.psm1 index 098a907..2b2634a 100644 --- a/lib/icinga/plugin/Exit-IcingaExecutePlugin.psm1 +++ b/lib/icinga/plugin/Exit-IcingaExecutePlugin.psm1 @@ -17,7 +17,7 @@ function Exit-IcingaExecutePlugin() & powershell.exe -ConfigurationName $JEAProfile -NoLogo -NoProfile -Command { Use-Icinga; - $global:IcingaDaemonData.JEAContext = $TRUE; + $Global:Icinga.Protected.JEAContext = $TRUE; $Command = $args[0]; $Arguments = $args[1]; diff --git a/lib/icinga/plugin/Get-IcingaInternalPluginExitCode.psm1 b/lib/icinga/plugin/Get-IcingaInternalPluginExitCode.psm1 index 2a19843..9067a91 100644 --- a/lib/icinga/plugin/Get-IcingaInternalPluginExitCode.psm1 +++ b/lib/icinga/plugin/Get-IcingaInternalPluginExitCode.psm1 @@ -1,4 +1,4 @@ function Get-IcingaInternalPluginExitCode() { - return $Global:Icinga.PluginExecution.LastExitCode; + return $Global:Icinga.Private.Scheduler.ExitCode; } diff --git a/lib/icinga/plugin/Get-IcingaInternalPluginOutput.psm1 b/lib/icinga/plugin/Get-IcingaInternalPluginOutput.psm1 index fbde917..e73a2f1 100644 --- a/lib/icinga/plugin/Get-IcingaInternalPluginOutput.psm1 +++ b/lib/icinga/plugin/Get-IcingaInternalPluginOutput.psm1 @@ -1,8 +1,8 @@ function Get-IcingaInternalPluginOutput() { - if ([string]::IsNullOrEmpty($Global:Icinga.PluginExecution.PluginException) -eq $FALSE) { - return $Global:Icinga.PluginExecution.PluginException; + if ([string]::IsNullOrEmpty($Global:Icinga.Private.Scheduler.PluginException) -eq $FALSE) { + return $Global:Icinga.Private.Scheduler.PluginException; } - return $Global:Icinga.CheckResults; + return $Global:Icinga.Private.Scheduler.CheckResults; } diff --git a/lib/icinga/plugin/Get-IcingaThresholdCache.psm1 b/lib/icinga/plugin/Get-IcingaThresholdCache.psm1 index 3cb0898..8e6ce34 100644 --- a/lib/icinga/plugin/Get-IcingaThresholdCache.psm1 +++ b/lib/icinga/plugin/Get-IcingaThresholdCache.psm1 @@ -8,17 +8,9 @@ function Get-IcingaThresholdCache() return $null; } - if ($null -eq $Global:Icinga) { + if ($Global:Icinga.Private.Scheduler.ThresholdCache.ContainsKey($CheckCommand) -eq $FALSE) { return $null; } - if ($Global:Icinga.ContainsKey('ThresholdCache') -eq $FALSE) { - return $null; - } - - if ($Global:Icinga.ThresholdCache.ContainsKey($CheckCommand) -eq $FALSE) { - return $null; - } - - return $Global:Icinga.ThresholdCache[$CheckCommand]; + return $Global:Icinga.Private.Scheduler.ThresholdCache[$CheckCommand]; } diff --git a/lib/icinga/plugin/New-IcingaCheck.psm1 b/lib/icinga/plugin/New-IcingaCheck.psm1 index e76ba18..c330483 100644 --- a/lib/icinga/plugin/New-IcingaCheck.psm1 +++ b/lib/icinga/plugin/New-IcingaCheck.psm1 @@ -287,16 +287,11 @@ function New-IcingaCheck() $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) { + if ([string]::IsNullOrEmpty($this.__CheckCommand) -Or $Global:Icinga.Protected.RunAsDaemon -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) { + if ($global:Icinga.Private.Scheduler.CheckData.ContainsKey($this.__CheckCommand) -eq $FALSE) { return; } @@ -304,8 +299,8 @@ function New-IcingaCheck() # 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; + Add-IcingaHashtableItem -Hashtable $global:Icinga.Private.Scheduler.CheckData[$this.__CheckCommand]['results'] -Key $this.Name -Value @{ } | Out-Null; + Add-IcingaHashtableItem -Hashtable $global:Icinga.Private.Scheduler.CheckData[$this.__CheckCommand]['results'][$this.Name] -Key $TimeIndex -Value $this.Value -Override | Out-Null; } $IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetOk' -Value { diff --git a/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 b/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 index 76faf06..555a655 100644 --- a/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 +++ b/lib/icinga/plugin/New-IcingaCheckBaseObject.psm1 @@ -29,23 +29,20 @@ function New-IcingaCheckBaseObject() return; } - if ($null -eq $Global:Icinga) { - $Global:Icinga = @{ }; + if ($Global:Icinga.Private.Scheduler.ThresholdCache.ContainsKey($this.__CheckCommand) -eq $FALSE) { + $Global:Icinga.Private.Scheduler.ThresholdCache.Add($this.__CheckCommand, $null); } - if ($Global:Icinga.ContainsKey('ThresholdCache') -eq $FALSE) { - $Global:Icinga.Add('ThresholdCache', @{ }); - } - - if ($Global:Icinga.ThresholdCache.ContainsKey($this.__CheckCommand) -eq $FALSE) { - $Global:Icinga.ThresholdCache.Add($this.__CheckCommand, $null); - } - - if ($null -ne $Global:Icinga.ThresholdCache[$this.__CheckCommand]) { + if ($null -ne $Global:Icinga.Private.Scheduler.ThresholdCache[$this.__CheckCommand]) { return; } - $Global:Icinga.ThresholdCache[$this.__CheckCommand] = (Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $this.__CheckCommand); + if ($Global:Icinga.Public.Daemons.ContainsKey('ServiceCheck') -And $Global:Icinga.Public.Daemons.ServiceCheck.PerformanceDataCache.ContainsKey($this.__CheckCommand) -And $Global:Icinga.Public.Daemons.ServiceCheck.PerformanceDataCache[$CheckCommand].Count -ne 0) { + $Global:Icinga.Private.Scheduler.ThresholdCache[$this.__CheckCommand] = $Global:Icinga.Public.Daemons.ServiceCheck.PerformanceDataCache[$CheckCommand]; + } else { + # Fallback in case the service is not registered within the daemon or we are running a plugin from without the daemon environment + $Global:Icinga.Private.Scheduler.ThresholdCache[$this.__CheckCommand] = (Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $this.__CheckCommand); + } } $IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetParent' -Value { diff --git a/lib/icinga/plugin/New-IcingaCheckResult.psm1 b/lib/icinga/plugin/New-IcingaCheckResult.psm1 index d511df2..fe6d18c 100644 --- a/lib/icinga/plugin/New-IcingaCheckResult.psm1 +++ b/lib/icinga/plugin/New-IcingaCheckResult.psm1 @@ -26,8 +26,8 @@ function New-IcingaCheckResult() # Ensure we reset our internal cache once the plugin was executed $CheckCommand = $this.Check.__GetCheckCommand(); - if ([string]::IsNullOrEmpty($CheckCommand) -eq $FALSE -And $Global:Icinga.ThresholdCache.ContainsKey($CheckCommand)) { - $Global:Icinga.ThresholdCache[$CheckCommand] = $null; + if ([string]::IsNullOrEmpty($CheckCommand) -eq $FALSE -And $Global:Icinga.Private.Scheduler.ThresholdCache.ContainsKey($CheckCommand)) { + $Global:Icinga.Private.Scheduler.ThresholdCache[$CheckCommand] = $null; } # Reset the current execution date $Global:Icinga.CurrentDate = $null; diff --git a/lib/icinga/plugin/Set-IcingaInternalPluginException.psm1 b/lib/icinga/plugin/Set-IcingaInternalPluginException.psm1 index 906e5f2..33f3cd6 100644 --- a/lib/icinga/plugin/Set-IcingaInternalPluginException.psm1 +++ b/lib/icinga/plugin/Set-IcingaInternalPluginException.psm1 @@ -4,26 +4,8 @@ function Set-IcingaInternalPluginException() [string]$PluginException = '' ); - if ($null -eq $Global:Icinga) { - $Global:Icinga = @{ }; - } - - if ($Global:Icinga.ContainsKey('PluginExecution') -eq $FALSE) { - $Global:Icinga.Add( - 'PluginExecution', - @{ - 'PluginException' = $PluginException; - } - ) - } else { - if ($Global:Icinga.PluginExecution.ContainsKey('PluginException') -eq $FALSE) { - $Global:Icinga.PluginExecution.Add('PluginException', $PluginException); - return; - } - - # Only catch the first exception - if ([string]::IsNullOrEmpty($Global:Icinga.PluginExecution.PluginException)) { - $Global:Icinga.PluginExecution.PluginException = $PluginException; - } + # Only catch the first exception + if ([string]::IsNullOrEmpty($Global:Icinga.Private.Scheduler.PluginException)) { + $Global:Icinga.Private.Scheduler.PluginException = $PluginException; } } diff --git a/lib/icinga/plugin/Set-IcingaInternalPluginExitCode.psm1 b/lib/icinga/plugin/Set-IcingaInternalPluginExitCode.psm1 index 6e20468..02d4ad2 100644 --- a/lib/icinga/plugin/Set-IcingaInternalPluginExitCode.psm1 +++ b/lib/icinga/plugin/Set-IcingaInternalPluginExitCode.psm1 @@ -4,26 +4,8 @@ function Set-IcingaInternalPluginExitCode() $ExitCode = 0 ); - if ($null -eq $Global:Icinga) { - $Global:Icinga = @{ }; - } - - if ($Global:Icinga.ContainsKey('PluginExecution') -eq $FALSE) { - $Global:Icinga.Add( - 'PluginExecution', - @{ - 'LastExitCode' = $ExitCode; - } - ) - } else { - if ($Global:Icinga.PluginExecution.ContainsKey('LastExitCode') -eq $FALSE) { - $Global:Icinga.PluginExecution.Add('LastExitCode', $ExitCode); - return; - } - - # Only add the first exit code we should cover during one runtime - if ($null -eq $Global:Icinga.PluginExecution.LastExitCode) { - $Global:Icinga.PluginExecution.LastExitCode = $ExitCode; - } + # Only add the first exit code we should cover during one runtime + if ($null -eq $Global:Icinga.Private.Scheduler.ExitCode) { + $Global:Icinga.Private.Scheduler.ExitCode = $ExitCode; } } diff --git a/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 b/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 index 2beffb1..e7447b0 100644 --- a/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 +++ b/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 @@ -4,13 +4,13 @@ function Write-IcingaPluginOutput() $Output ); - if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE -And $global:IcingaDaemonData.JEAContext -eq $FALSE) { - if ($null -ne $global:Icinga -And $global:Icinga.Minimal) { + if ($Global:Icinga.Protected.RunAsDaemon -eq $FALSE -And $Global:Icinga.Protected.JEAContext -eq $FALSE) { + if ($Global:Icinga.Protected.Minimal) { Clear-Host; } Write-IcingaConsolePlain $Output; } else { # New behavior with local thread separated results - $global:Icinga.CheckResults += $Output; + $global:Icinga.Private.Scheduler.CheckResults += $Output; } } diff --git a/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 b/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 index 312b6b8..2ac4e12 100644 --- a/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 +++ b/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 @@ -19,13 +19,13 @@ function Write-IcingaPluginPerfData() $PerformanceData = $PerformanceData.perfdata; } - if ([string]::IsNullOrEmpty($CheckCommand) -eq $FALSE -And $Global:Icinga.ThresholdCache.ContainsKey($CheckCommand)) { - $CheckResultCache = $Global:Icinga.ThresholdCache[$CheckCommand]; + if ([string]::IsNullOrEmpty($CheckCommand) -eq $FALSE -And $Global:Icinga.Private.Scheduler.ThresholdCache.ContainsKey($CheckCommand)) { + $CheckResultCache = $Global:Icinga.Private.Scheduler.ThresholdCache[$CheckCommand]; } else { $CheckResultCache = New-Object PSCustomObject; } - if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE -And $global:IcingaDaemonData.JEAContext -eq $FALSE) { + if ($Global:Icinga.Protected.RunAsDaemon -eq $FALSE -And $Global:Icinga.Protected.JEAContext -eq $FALSE) { [string]$PerfDataOutput = (Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -IcingaCheck $IcingaCheck); Write-IcingaConsolePlain ([string]::Format('| {0}', $PerfDataOutput)); } else { @@ -60,7 +60,7 @@ function Get-IcingaPluginPerfDataContent() if ($AsObject) { # New behavior with local thread separated results - $global:Icinga.PerfData += $cachedresult; + $global:Icinga.Private.Scheduler.PerformanceData += $cachedresult; } $PerfDataOutput += $cachedresult; } @@ -70,7 +70,7 @@ function Get-IcingaPluginPerfDataContent() if ($AsObject) { # New behavior with local thread separated results - $global:Icinga.PerfData += $compiledPerfData; + $global:Icinga.Private.Scheduler.PerformanceData += $compiledPerfData; } $PerfDataOutput += $compiledPerfData; } diff --git a/lib/webserver/Convert-Base64ToCredentials.psm1 b/lib/webserver/Convert-Base64ToCredentials.psm1 index e96d30a..734bdd0 100644 --- a/lib/webserver/Convert-Base64ToCredentials.psm1 +++ b/lib/webserver/Convert-Base64ToCredentials.psm1 @@ -92,8 +92,8 @@ function Convert-Base64ToCredentials() $UserData = $null; } catch { - Write-IcingaEventMessage -EventId 1552 -Namespace 'Framework' -Objects $_.Exception; - return @{ }; + Write-IcingaEventMessage -EventId 1552 -Namespace 'Framework' -ExceptionObject $_; + return @{}; } return $Credentials; diff --git a/lib/webserver/New-IcingaSSLStream.psm1 b/lib/webserver/New-IcingaSSLStream.psm1 index 250566a..05d13a0 100644 --- a/lib/webserver/New-IcingaSSLStream.psm1 +++ b/lib/webserver/New-IcingaSSLStream.psm1 @@ -13,7 +13,7 @@ function New-IcingaSSLStream() $SSLStream = New-Object System.Net.Security.SslStream($Client.GetStream(), $false) $SSLStream.AuthenticateAsServer($Certificate, $false, [System.Security.Authentication.SslProtocols]::Tls12, $true) | Out-Null; } catch { - Write-IcingaEventMessage -EventId 1500 -Namespace 'Framework' -Objects $Client.Client; + Write-IcingaEventMessage -EventId 1500 -Namespace 'Framework' -ExceptionObject $_ -Objects $Client.Client; return $null; } diff --git a/lib/webserver/Test-IcingaRESTCredentials.psm1 b/lib/webserver/Test-IcingaRESTCredentials.psm1 index 71d1f5f..bbc6c68 100644 --- a/lib/webserver/Test-IcingaRESTCredentials.psm1 +++ b/lib/webserver/Test-IcingaRESTCredentials.psm1 @@ -52,7 +52,7 @@ function Test-IcingaRESTCredentials() ); } catch { # Regardless of the error, print the message and return false to prevent further execution - Write-IcingaEventMessage -EventId 1560 -Namespace 'Framework' -Objects $_.Exception; + Write-IcingaEventMessage -EventId 1560 -Namespace 'Framework' -ExceptionObject $_; return $FALSE; } @@ -71,7 +71,7 @@ function Test-IcingaRESTCredentials() return $AuthResult; } catch { - Write-IcingaEventMessage -EventId 1561 -Namespace 'Framework' -Objects $_.Exception; + Write-IcingaEventMessage -EventId 1561 -Namespace 'Framework' -ExceptionObject $_; } return $FALSE;