mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-20 23:00:35 -05:00
Merge pull request #142 from Icinga/feature/add_code_cache_for_faster_framework_loading
Experimental: Adds code caching for faster framework loading ## Current Situation Currently the entire Framework is taking a huge amount of time to load the files. This causes several issues: * Slow loading increases the runtime of checks * High CPU usage for the initial loading of the Framework * High CPU usage over a longer period of time, cause more impcact on the systems ## Possible solutions ### Add caching To reduce the impact for the Framework loading, we could add a cache file containing all Cmdlets, Enums and Functions allowing us to import file on initialization instead of having of to search for all `.psm1` files and load them one by one ### Use Nested Modules for PowerShell Plugins PowerShell plugins right now are using `Use-IcingaPlugins` which searchs for all `.psm1` files inside the plugin folder to load them. We should use `NestedModules` here, as the overall impact is lower. On Framework side we can't do this how ever without loading times to explode. Plugins are tracked [at issue #87 here](https://github.com/Icinga/icinga-powershell-plugins/pull/87) ## Current Status **Mitigated** ## Usage You can enable/disable this feature by using `Enable-IcingaFrameworkCodeCache` and `Disable-IcingaFrameworkCodeCache`. Updating the cache is done with `Write-IcingaFrameworkCodeCache`
This commit is contained in:
commit
2deeb83d38
8 changed files with 153 additions and 10 deletions
|
|
@ -18,6 +18,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
|
||||||
* [#139](https://github.com/Icinga/icinga-powershell-framework/pull/139) Add Cmdlet `Start-IcingaShellAsUser` to open an Icinga Shell as different user for testing
|
* [#139](https://github.com/Icinga/icinga-powershell-framework/pull/139) Add Cmdlet `Start-IcingaShellAsUser` to open an Icinga Shell as different user for testing
|
||||||
* [#141](https://github.com/Icinga/icinga-powershell-framework/pull/141) Adds Cmdlet `Convert-IcingaPluginThresholds` as generic approach to convert Icinga Thresholds with units to the lowest unit of this type.
|
* [#141](https://github.com/Icinga/icinga-powershell-framework/pull/141) Adds Cmdlet `Convert-IcingaPluginThresholds` as generic approach to convert Icinga Thresholds with units to the lowest unit of this type.
|
||||||
* [#134](https://github.com/Icinga/icinga-powershell-framework/pull/134) Adds Cmdlet `Test-IcingaWindowsInformation` to check if a WMI class exist and if we can fetch data from it. In addition we add support for binary value comparison with the new Cmdlet `Test-IcingaBinaryOperator`
|
* [#134](https://github.com/Icinga/icinga-powershell-framework/pull/134) Adds Cmdlet `Test-IcingaWindowsInformation` to check if a WMI class exist and if we can fetch data from it. In addition we add support for binary value comparison with the new Cmdlet `Test-IcingaBinaryOperator`
|
||||||
|
* [#142](https://github.com/Icinga/icinga-powershell-framework/pull/142) **Experimental:** Adds feature to cache the Framework code into a single file to speed up the entire loading process, mitigating the impact on performance on systems with few CPU cores. You enable disables this feature by using `Enable-IcingaFrameworkCodeCache` and `Disable-IcingaFrameworkCodeCache`. Updating the cache is done with `Write-IcingaFrameworkCodeCache`
|
||||||
* [#149](https://github.com/Icinga/icinga-powershell-framework/pull/149) Adds support to add Wmi permissions for a specific user and namespace with `Add-IcingaWmiPermissions`. In addition you can remove users from Wmi namespaces by using `Remove-IcingaWmiPermissions`
|
* [#149](https://github.com/Icinga/icinga-powershell-framework/pull/149) Adds support to add Wmi permissions for a specific user and namespace with `Add-IcingaWmiPermissions`. In addition you can remove users from Wmi namespaces by using `Remove-IcingaWmiPermissions`
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,21 @@
|
||||||
Copyright = '(c) 2020 Icinga GmbH | MIT'
|
Copyright = '(c) 2020 Icinga GmbH | MIT'
|
||||||
Description = 'Icinga for Windows module which allows to entirely monitor the Windows Host system.'
|
Description = 'Icinga for Windows module which allows to entirely monitor the Windows Host system.'
|
||||||
PowerShellVersion = '4.0'
|
PowerShellVersion = '4.0'
|
||||||
|
NestedModules = @(
|
||||||
|
'.\lib\core\framework\Get-IcingaFrameworkCodeCache.psm1',
|
||||||
|
'.\lib\config\Get-IcingaPowerShellConfig.psm1',
|
||||||
|
'.\lib\config\Read-IcingaPowerShellConfig.psm1',
|
||||||
|
'.\lib\config\Test-IcingaPowerShellConfigItem.psm1',
|
||||||
|
'.\lib\core\logging\Write-IcingaConsoleOutput.psm1',
|
||||||
|
'.\lib\core\logging\Write-IcingaConsoleNotice.psm1',
|
||||||
|
'.\lib\core\logging\Write-IcingaConsoleWarning.psm1'
|
||||||
|
)
|
||||||
FunctionsToExport = @(
|
FunctionsToExport = @(
|
||||||
'Use-Icinga',
|
'Use-Icinga',
|
||||||
'Invoke-IcingaCommand',
|
'Invoke-IcingaCommand',
|
||||||
'Import-IcingaLib',
|
'Import-IcingaLib',
|
||||||
|
'Get-IcingaFrameworkCodeCacheFile',
|
||||||
|
'Write-IcingaFrameworkCodeCache',
|
||||||
'Publish-IcingaModuleManifest',
|
'Publish-IcingaModuleManifest',
|
||||||
'Publish-IcingaEventlogDocumentation',
|
'Publish-IcingaEventlogDocumentation',
|
||||||
'Get-IcingaPluginDir',
|
'Get-IcingaPluginDir',
|
||||||
|
|
@ -19,9 +30,16 @@
|
||||||
'Get-IcingaPowerShellConfigDir',
|
'Get-IcingaPowerShellConfigDir',
|
||||||
'Get-IcingaFrameworkRootPath',
|
'Get-IcingaFrameworkRootPath',
|
||||||
'Get-IcingaPowerShellModuleFile',
|
'Get-IcingaPowerShellModuleFile',
|
||||||
'Start-IcingaShellAsUser'
|
'Start-IcingaShellAsUser',
|
||||||
|
'Get-IcingaPowerShellConfig',
|
||||||
|
'Get-IcingaFrameworkCodeCache',
|
||||||
|
'Read-IcingaPowerShellConfig',
|
||||||
|
'Test-IcingaPowerShellConfigItem',
|
||||||
|
'Write-IcingaConsoleOutput',
|
||||||
|
'Write-IcingaConsoleNotice',
|
||||||
|
'Write-IcingaConsoleWarning'
|
||||||
)
|
)
|
||||||
CmdletsToExport = @()
|
CmdletsToExport = @('*')
|
||||||
VariablesToExport = '*'
|
VariablesToExport = '*'
|
||||||
AliasesToExport = @( 'icinga' )
|
AliasesToExport = @( 'icinga' )
|
||||||
PrivateData = @{
|
PrivateData = @{
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ function Use-Icinga()
|
||||||
Use-IcingaPlugins;
|
Use-IcingaPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((Test-Path (Get-IcingaFrameworkCodeCacheFile)) -eq $FALSE -And (Get-IcingaFrameworkCodeCache)) {
|
||||||
|
Write-IcingaFrameworkCodeCache;
|
||||||
|
}
|
||||||
|
|
||||||
# This function will allow us to load this entire module including possible
|
# This function will allow us to load this entire module including possible
|
||||||
# actions, making it available within our shell environment
|
# actions, making it available within our shell environment
|
||||||
# First load our custom modules
|
# First load our custom modules
|
||||||
|
|
@ -78,6 +82,20 @@ function Use-Icinga()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Get-IcingaFrameworkCodeCacheFile()
|
||||||
|
{
|
||||||
|
return (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'framework_cache.psm1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-IcingaFrameworkCodeCache()
|
||||||
|
{
|
||||||
|
if (Get-IcingaFrameworkCodeCache) {
|
||||||
|
Import-IcingaLib '\' -Init -CompileCache;
|
||||||
|
} else {
|
||||||
|
Write-IcingaConsoleNotice 'The experimental code caching feature is currently not enabled. You can enable it with "Enable-IcingaFrameworkCodeCache"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Import-IcingaLib()
|
function Import-IcingaLib()
|
||||||
{
|
{
|
||||||
param(
|
param(
|
||||||
|
|
@ -87,15 +105,27 @@ function Import-IcingaLib()
|
||||||
[Switch]$ForceReload,
|
[Switch]$ForceReload,
|
||||||
[switch]$Init,
|
[switch]$Init,
|
||||||
[switch]$Custom,
|
[switch]$Custom,
|
||||||
[switch]$WriteManifests
|
[switch]$WriteManifests,
|
||||||
|
[switch]$CompileCache
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# This is just to only allow a global loading of the module. Import-IcingaLib is ignored on every other
|
# This is just to only allow a global loading of the module. Import-IcingaLib is ignored on every other
|
||||||
# location. It is just there to give a basic idea within commands, of which functions are used
|
# location. It is just there to give a basic idea within commands, of which functions are used
|
||||||
if ($Init -eq $FALSE) {
|
if ($Init -eq $FALSE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$CacheFile = Get-IcingaFrameworkCodeCacheFile;
|
||||||
|
|
||||||
|
if ($Custom -eq $FALSE -And $CompileCache -eq $FALSE -And (Test-Path $CacheFile) -And (Get-IcingaFrameworkCodeCache)) {
|
||||||
|
Import-Module $CacheFile -Global;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[array]$ImportModules = @();
|
||||||
|
[array]$RemoveModules = @();
|
||||||
|
|
||||||
if ($Custom) {
|
if ($Custom) {
|
||||||
[string]$directory = Join-Path -Path $PSScriptRoot -ChildPath 'custom\';
|
[string]$directory = Join-Path -Path $PSScriptRoot -ChildPath 'custom\';
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -116,11 +146,11 @@ function Import-IcingaLib()
|
||||||
|
|
||||||
if ($ListOfLoadedModules -like "*$moduleName*") {
|
if ($ListOfLoadedModules -like "*$moduleName*") {
|
||||||
if ($ForceReload) {
|
if ($ForceReload) {
|
||||||
Remove-Module -Name $moduleName
|
$RemoveModules += $moduleName;
|
||||||
Import-Module ([string]::Format('{0}', $modulePath)) -Global;
|
|
||||||
}
|
}
|
||||||
|
$ImportModules += $modulePath;
|
||||||
} else {
|
} else {
|
||||||
Import-Module ([string]::Format('{0}', $modulePath)) -Global;
|
$ImportModules += $modulePath;
|
||||||
if ($WriteManifests) {
|
if ($WriteManifests) {
|
||||||
Publish-IcingaModuleManifest -Module $moduleName;
|
Publish-IcingaModuleManifest -Module $moduleName;
|
||||||
}
|
}
|
||||||
|
|
@ -132,15 +162,35 @@ function Import-IcingaLib()
|
||||||
|
|
||||||
if ($ForceReload) {
|
if ($ForceReload) {
|
||||||
if ($ListOfLoadedModules -Like "*$moduleName*") {
|
if ($ListOfLoadedModules -Like "*$moduleName*") {
|
||||||
Remove-Module -Name $moduleName;
|
$RemoveModules += $moduleName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Import-Module ([string]::Format('{0}.psm1', $module)) -Global;
|
$ImportModules += ([string]::Format('{0}.psm1', $module));
|
||||||
if ($WriteManifests) {
|
if ($WriteManifests) {
|
||||||
Publish-IcingaModuleManifest -Module $moduleName;
|
Publish-IcingaModuleManifest -Module $moduleName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($RemoveModules.Count -ne 0) {
|
||||||
|
Remove-Module $RemoveModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ImportModules.Count -ne 0) {
|
||||||
|
|
||||||
|
if ($CompileCache) {
|
||||||
|
$CacheContent = '';
|
||||||
|
foreach ($module in $ImportModules) {
|
||||||
|
$Content = Get-Content $module -Raw;
|
||||||
|
$CacheContent += $Content + "`r`n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$CacheContent += $Content + "Export-ModuleMember -Function @( '*' )";
|
||||||
|
Set-Content -Path $CacheFile -Value $CacheContent;
|
||||||
|
} else {
|
||||||
|
Import-Module $ImportModules -Global;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Publish-IcingaModuleManifest()
|
function Publish-IcingaModuleManifest()
|
||||||
|
|
@ -279,6 +329,9 @@ function Invoke-IcingaCommand()
|
||||||
Write-Output ([string]::Format('** Icinga PowerShell Framework {0}', $IcingaFrameworkData.PrivateData.Version));
|
Write-Output ([string]::Format('** Icinga PowerShell Framework {0}', $IcingaFrameworkData.PrivateData.Version));
|
||||||
Write-Output ([string]::Format('** Copyright {0}', $IcingaFrameworkData.Copyright));
|
Write-Output ([string]::Format('** Copyright {0}', $IcingaFrameworkData.Copyright));
|
||||||
Write-Output ([string]::Format('** User environment {0}\{1}', $env:USERDOMAIN, $env:USERNAME));
|
Write-Output ([string]::Format('** User environment {0}\{1}', $env:USERDOMAIN, $env:USERNAME));
|
||||||
|
if (Get-IcingaFrameworkCodeCache) {
|
||||||
|
Write-Output ([string]::Format('** Warning: Icinga Framework Code Caching is enabled'));
|
||||||
|
}
|
||||||
Write-Output '******************************************************';
|
Write-Output '******************************************************';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ function Read-IcingaPowerShellConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-Not (Test-Path $ConfigFile)) {
|
if (-Not (Test-Path $ConfigFile)) {
|
||||||
return (New-Object -TypeName PSOBject);
|
return (New-Object -TypeName PSObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
[string]$Content = Get-Content -Path $ConfigFile;
|
[string]$Content = Get-Content -Path $ConfigFile;
|
||||||
|
|
||||||
if ([string]::IsNullOrEmpty($Content)) {
|
if ([string]::IsNullOrEmpty($Content)) {
|
||||||
return (New-Object -TypeName PSOBject);
|
return (New-Object -TypeName PSObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ConvertFrom-Json -InputObject $Content);
|
return (ConvertFrom-Json -InputObject $Content);
|
||||||
|
|
|
||||||
19
lib/core/framework/Disable-IcingaFrameworkCodeCache.psm1
Normal file
19
lib/core/framework/Disable-IcingaFrameworkCodeCache.psm1
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Disables the experimental feature to cache all functions into a single file,
|
||||||
|
allowing quicker loading times of the Icinga PowerShell Framework
|
||||||
|
.DESCRIPTION
|
||||||
|
Disables the experimental feature to cache all functions into a single file,
|
||||||
|
allowing quicker loading times of the Icinga PowerShell Framework
|
||||||
|
.FUNCTIONALITY
|
||||||
|
Experimental: Disables the Icinga for Windows code caching
|
||||||
|
.EXAMPLE
|
||||||
|
PS>Disable-IcingaFrameworkCodeCache;
|
||||||
|
.LINK
|
||||||
|
https://github.com/Icinga/icinga-powershell-framework
|
||||||
|
#>
|
||||||
|
|
||||||
|
function Disable-IcingaFrameworkCodeCache()
|
||||||
|
{
|
||||||
|
Set-IcingaPowerShellConfig -Path 'Framework.Experimental.CodeCaching' -Value $FALSE;
|
||||||
|
}
|
||||||
21
lib/core/framework/Enable-IcingaFrameworkCodeCache.psm1
Normal file
21
lib/core/framework/Enable-IcingaFrameworkCodeCache.psm1
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Enables the experimental feature to cache all functions into a single file,
|
||||||
|
allowing quicker loading times of the Icinga PowerShell Framework
|
||||||
|
.DESCRIPTION
|
||||||
|
Enables the experimental feature to cache all functions into a single file,
|
||||||
|
allowing quicker loading times of the Icinga PowerShell Framework
|
||||||
|
.FUNCTIONALITY
|
||||||
|
Experimental: Enables the Icinga for Windows code caching
|
||||||
|
.EXAMPLE
|
||||||
|
PS>Enable-IcingaFrameworkCodeCache;
|
||||||
|
.LINK
|
||||||
|
https://github.com/Icinga/icinga-powershell-framework
|
||||||
|
#>
|
||||||
|
|
||||||
|
function Enable-IcingaFrameworkCodeCache()
|
||||||
|
{
|
||||||
|
Set-IcingaPowerShellConfig -Path 'Framework.Experimental.CodeCaching' -Value $TRUE;
|
||||||
|
|
||||||
|
Write-IcingaConsoleWarning 'This is an experimental feature and might cause some side effects during usage. Please use this function with caution. Please run "Write-IcingaFrameworkCodeCache" in addition to ensure your cache is updated. This should be done after each update of the Framework in case the feature was disabled during the update run.';
|
||||||
|
}
|
||||||
28
lib/core/framework/Get-IcingaFrameworkCodeCache.psm1
Normal file
28
lib/core/framework/Get-IcingaFrameworkCodeCache.psm1
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Fetches the current enable/disable state of the experimental feature
|
||||||
|
for caching the Icinga PowerShell Framework code
|
||||||
|
.DESCRIPTION
|
||||||
|
Fetches the current enable/disable state of the experimental feature
|
||||||
|
for caching the Icinga PowerShell Framework code
|
||||||
|
.FUNCTIONALITY
|
||||||
|
Experimental: Get the current code caching configuration of the
|
||||||
|
Icinga PowerShell Framework
|
||||||
|
.EXAMPLE
|
||||||
|
PS>Get-IcingaFrameworkCodeCache;
|
||||||
|
.LINK
|
||||||
|
https://github.com/Icinga/icinga-powershell-framework
|
||||||
|
.OUTPUTS
|
||||||
|
System.Boolean
|
||||||
|
#>
|
||||||
|
|
||||||
|
function Get-IcingaFrameworkCodeCache()
|
||||||
|
{
|
||||||
|
$CodeCaching = Get-IcingaPowerShellConfig -Path 'Framework.Experimental.CodeCaching';
|
||||||
|
|
||||||
|
if ($null -eq $CodeCaching) {
|
||||||
|
return $FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $CodeCaching;
|
||||||
|
}
|
||||||
|
|
@ -91,6 +91,9 @@ function Install-IcingaFrameworkUpdate()
|
||||||
Start-Sleep -Seconds 1;
|
Start-Sleep -Seconds 1;
|
||||||
Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null;
|
Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null;
|
||||||
|
|
||||||
|
Write-IcingaConsoleNotice 'Updating Framework cache file';
|
||||||
|
Write-IcingaFrameworkCodeCache;
|
||||||
|
|
||||||
Write-IcingaConsoleNotice 'Framework update has been completed. Please start a new PowerShell instance now to complete the update';
|
Write-IcingaConsoleNotice 'Framework update has been completed. Please start a new PowerShell instance now to complete the update';
|
||||||
|
|
||||||
Test-IcingaAgent;
|
Test-IcingaAgent;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue