diff --git a/doc/100-General/10-Changelog.md b/doc/100-General/10-Changelog.md index 0765d00..954c772 100644 --- a/doc/100-General/10-Changelog.md +++ b/doc/100-General/10-Changelog.md @@ -30,6 +30,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#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 * [#439](https://github.com/Icinga/icinga-powershell-framework/pull/439) Moves PerformanceCounter to private space from previous public, which caused some problems * [#441](https://github.com/Icinga/icinga-powershell-framework/pull/441) Fixes an exception while loading the Framework, caused by a race condition for missing environment variables which are accessed by some plugins before the Framework is loaded properly +* [#446](https://github.com/Icinga/icinga-powershell-framework/pull/446) Fixes Icinga for Windows progress preference, which sometimes caused UI glitches ### Enhancements diff --git a/doc/900-Developer-Guide/00-General.md b/doc/900-Developer-Guide/00-General.md index f7c5d68..759f131 100644 --- a/doc/900-Developer-Guide/00-General.md +++ b/doc/900-Developer-Guide/00-General.md @@ -62,6 +62,7 @@ The following entries are set by default within the `Private` space: | 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 | | PerformanceCounter | A space to share all PerformanceCounter information between threads, which counters are already created for internal usage | +| ProgressStatus | A list of all created progress status bars from Icinga for Windows | #### Example Data diff --git a/lib/core/framework/New-IcingaEnvironmentVariable.psm1 b/lib/core/framework/New-IcingaEnvironmentVariable.psm1 index df885b2..a47ec3d 100644 --- a/lib/core/framework/New-IcingaEnvironmentVariable.psm1 +++ b/lib/core/framework/New-IcingaEnvironmentVariable.psm1 @@ -21,6 +21,7 @@ function New-IcingaEnvironmentVariable() $Global:Icinga.Private.Add('Daemons', @{ }); $Global:Icinga.Private.Add('Timers', @{ }); + $Global:Icinga.Private.Add('ProgressStatus', @{ }); $Global:Icinga.Private.Add( 'Scheduler', diff --git a/lib/core/jea/Get-IcingaJEAConfiguration.psm1 b/lib/core/jea/Get-IcingaJEAConfiguration.psm1 index e845e75..49b6f93 100644 --- a/lib/core/jea/Get-IcingaJEAConfiguration.psm1 +++ b/lib/core/jea/Get-IcingaJEAConfiguration.psm1 @@ -27,8 +27,10 @@ function Get-IcingaJEAConfiguration() # Lookup all PowerShell modules installed for Icinga for Windows inside the same folder as the Framework # and fetch each single module file to list the used Cmdlets and Functions # Add each file content to a big string file for better parsing + + New-IcingaProgressStatus -Name 'Icinga for Windows Components' -Message 'Fetching Icinga for Windows Components' -MaxValue $PowerShellModules.Count -Details; foreach ($module in $PowerShellModules) { - $Progress = Write-IcingaProgressStatus -Message 'Fetching Icinga for Windows Components' -CurrentValue $Progress -MaxValue $PowerShellModules.Count -Details; + Write-IcingaProgressStatus -Name 'Icinga for Windows Components'; if ($module.Name.ToLower() -eq 'icinga-powershell-framework') { continue; } @@ -78,12 +80,16 @@ function Get-IcingaJEAConfiguration() $ModuleContent += $ModuleFileContent; } + Complete-IcingaProgressStatus -Name 'Icinga for Windows Components'; + if ($DependencyCache -eq $FALSE) { # Now lets lookup every single Framework file and get all used Cmdlets and Functions so we know our dependencies $FrameworkFiles = Get-ChildItem -Path (Get-IcingaFrameworkRootPath) -Recurse -Filter '*.psm1'; + New-IcingaProgressStatus -Name 'Icinga for Windows Files' -Message 'Compiling Icinga PowerShell Framework Dependency List' -MaxValue $FrameworkFiles.Count -Details; + foreach ($ModuleFile in $FrameworkFiles) { - $Progress = Write-IcingaProgressStatus -Message 'Compiling Icinga PowerShell Framework Dependency List' -CurrentValue $Progress -MaxValue $FrameworkFiles.Count -Details; + Write-IcingaProgressStatus -Name 'Icinga for Windows Files'; # Just ignore our cache file if ($ModuleFile.FullName -eq (Get-IcingaFrameworkCodeCacheFile)) { @@ -99,6 +105,8 @@ function Get-IcingaJEAConfiguration() } } + Complete-IcingaProgressStatus -Name 'Icinga for Windows Files'; + Write-IcingaFileSecure -File (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'framework_dependencies.json') -Value $DependencyList; } @@ -107,8 +115,10 @@ function Get-IcingaJEAConfiguration() # Check all our configured background daemons and ensure we get all Cmdlets and Functions including the dependency list $BackgroundDaemons = (Get-IcingaBackgroundDaemons).Keys; + New-IcingaProgressStatus -Name 'Compiling Icinga for Windows Daemons' -Message 'Compiling Background Daemon Dependency List' -MaxValue $BackgroundDaemons.Count -Details; + foreach ($daemon in $BackgroundDaemons) { - $Progress = Write-IcingaProgressStatus -Message 'Compiling Background Daemon Dependency List' -CurrentValue $Progress -MaxValue $BackgroundDaemons.Count -Details; + Write-IcingaProgressStatus -Name 'Compiling Icinga for Windows Daemons'; $DaemonCmd = (Get-Command $daemon); @@ -127,6 +137,8 @@ function Get-IcingaJEAConfiguration() -CmdType $CommandType; } + Complete-IcingaProgressStatus -Name 'Compiling Icinga for Windows Daemons'; + # We need to add this function which is not used anywhere else and should still add the entire dependency tree $UsedCmdlets = Get-IcingaCommandDependency ` -DependencyList $DependencyList ` @@ -146,8 +158,10 @@ function Get-IcingaJEAConfiguration() $DeserializedFile = Read-IcingaPowerShellModuleFile -FileContent $ModuleContent; [array]$JeaCmds = $DeserializedFile.CommandList + $DeserializedFile.FunctionList; + New-IcingaProgressStatus -Name 'Compiling JEA' -Message 'Compiling JEA Profile Catalog' -MaxValue $JeaCmds.Count -Details; + foreach ($cmd in $JeaCmds) { - $Progress = Write-IcingaProgressStatus -Message 'Compiling JEA Profile Catalog' -CurrentValue $Progress -MaxValue $JeaCmds.Count -Details; + Write-IcingaProgressStatus -Name 'Compiling JEA'; $CmdData = Get-Command $cmd -ErrorAction SilentlyContinue; if ($null -eq $CmdData) { @@ -163,6 +177,8 @@ function Get-IcingaJEAConfiguration() -CmdType $CommandType; } + Complete-IcingaProgressStatus -Name 'Compiling JEA'; + Disable-IcingaProgressPreference; return $UsedCmdlets; diff --git a/lib/core/progress/Complete-IcingaProgressStatus.psm1 b/lib/core/progress/Complete-IcingaProgressStatus.psm1 new file mode 100644 index 0000000..098e953 --- /dev/null +++ b/lib/core/progress/Complete-IcingaProgressStatus.psm1 @@ -0,0 +1,28 @@ +function Complete-IcingaProgressStatus() +{ + param ( + [string]$Name = '' + ); + + if ([string]::IsNullOrEmpty($Name)) { + Write-IcingaConsoleError -Message 'Failed to complete progress status. You have to specify a name.'; + return; + } + + if ($Global:Icinga.Private.ProgressStatus.ContainsKey($Name) -eq $FALSE) { + return; + } + + if ($Global:Icinga.Private.ProgressStatus[$Name].Details) { + $Message = [string]::Format('{0}: {1}/{2}', $Global:Icinga.Private.ProgressStatus[$Name].Message, $Global:Icinga.Private.ProgressStatus[$Name].MaxValue, $Global:Icinga.Private.ProgressStatus[$Name].MaxValue); + } else { + $Message = $Global:Icinga.Private.ProgressStatus[$Name].Message; + } + + $ProgressPreference = 'Continue'; + Write-Progress -Activity $Message -Status ([string]::Format($Global:Icinga.Private.ProgressStatus[$Name].Status, 100)) -PercentComplete 100 -Completed; + + $Global:Icinga.Private.ProgressStatus.Remove($Name); + + $ProgressPreference = 'SilentlyContinue'; +} diff --git a/lib/core/progress/New-IcingaProgressStatus.psm1 b/lib/core/progress/New-IcingaProgressStatus.psm1 new file mode 100644 index 0000000..8c7cab4 --- /dev/null +++ b/lib/core/progress/New-IcingaProgressStatus.psm1 @@ -0,0 +1,39 @@ +function New-IcingaProgressStatus() +{ + param ( + [string]$Name = '', + [int]$CurrentValue = 0, + [int]$MaxValue = 1, + [string]$Message = 'Processing Icinga for Windows', + [string]$Status = '{0}% Complete', + [switch]$Details = $FALSE + ); + + if ([string]::IsNullOrEmpty($Name)) { + Write-IcingaConsoleError -Message 'Failed to create new progress status. You have to specify a name.'; + return; + } + + if ($MaxValue -le 0) { + Write-IcingaConsoleError -Message 'Failed to create new progress status. The maximum value has to be larger than 0.'; + return; + } + + if ($Global:Icinga.Private.ProgressStatus.ContainsKey($Name)) { + Write-IcingaConsoleError -Message 'Failed to create new progress status. A progress status with this name is already active. Use "Complete-IcingaProgressStatus" to remove it.'; + return; + } + + $Global:Icinga.Private.ProgressStatus.Add( + $Name, + @{ + 'CurrentValue' = $CurrentValue; + 'MaxValue' = $MaxValue; + 'Message' = $Message; + 'Status' = $Status; + 'Details' = ([bool]$Details); + } + ); + + $ProgressPreference = 'Continue'; +} diff --git a/lib/core/progress/Write-IcingaProgressStatus.psm1 b/lib/core/progress/Write-IcingaProgressStatus.psm1 new file mode 100644 index 0000000..2f86818 --- /dev/null +++ b/lib/core/progress/Write-IcingaProgressStatus.psm1 @@ -0,0 +1,37 @@ +function Write-IcingaProgressStatus() +{ + param ( + [string]$Name = '', + [int]$AddValue = 1, + [switch]$PrintErrors = $FALSE + ); + + if ([string]::IsNullOrEmpty($Name)) { + Write-IcingaConsoleError -Message 'Failed to write progress status. You have to specify a name.' -DropMessage:$(-Not $PrintErrors); + return; + } + + if ($Global:Icinga.Private.ProgressStatus.ContainsKey($Name) -eq $FALSE) { + Write-IcingaConsoleError -Message 'Failed to write progress status. A progress status with the name "{0}" does not exist. You have to create it first with "New-IcingaProgressStatus".' -Objects $Name -DropMessage:$(-Not $PrintErrors); + return; + } + + $Global:Icinga.Private.ProgressStatus[$Name].CurrentValue += $AddValue; + + $ProgressValue = [math]::Round($Global:Icinga.Private.ProgressStatus[$Name].CurrentValue / $Global:Icinga.Private.ProgressStatus[$Name].MaxValue * 100, 0); + + if ($Global:Icinga.Private.ProgressStatus[$Name].Details) { + $Message = [string]::Format('{0}: {1}/{2}', $Global:Icinga.Private.ProgressStatus[$Name].Message, $Global:Icinga.Private.ProgressStatus[$Name].CurrentValue, $Global:Icinga.Private.ProgressStatus[$Name].MaxValue); + } else { + $Message = $Global:Icinga.Private.ProgressStatus[$Name].Message; + } + + if ($ProgressValue -ge 100) { + Complete-IcingaProgressStatus -Name $Name; + return; + } + + $ProgressPreference = 'Continue'; + + Write-Progress -Activity $Message -Status ([string]::Format($Global:Icinga.Private.ProgressStatus[$Name].Status, $ProgressValue)) -PercentComplete $ProgressValue; +} diff --git a/lib/core/tools/Write-IcingaProgressStatus.psm1 b/lib/core/tools/Write-IcingaProgressStatus.psm1 deleted file mode 100644 index 922aacb..0000000 --- a/lib/core/tools/Write-IcingaProgressStatus.psm1 +++ /dev/null @@ -1,39 +0,0 @@ -function Write-IcingaProgressStatus() -{ - param ( - [int]$CurrentValue = 0, - [int]$MaxValue = 1, - [string]$Message = 'Processing Icinga for Windows', - [string]$Status = "{0}% Complete", - [switch]$Details = $FALSE - ); - - if ($CurrentValue -le -99) { - $CurrentValue = 0; - return; - } - - if ($MaxValue -le 0) { - $MaxValue = 1; - } - - $ProgressValue = [math]::Round($CurrentValue / $MaxValue * 100, 0); - - if ($Details) { - $Message = [string]::Format('{0}: {1}/{2}', $Message, $CurrentValue, $MaxValue); - } - - $ProgressPreference = 'Continue'; - - if ($ProgressValue -ge 100) { - $ProgressValue = 100; - Write-Progress -Activity $Message -Status ([string]::Format($Status, $ProgressValue)) -PercentComplete $ProgressValue -Completed; - $CurrentValue = -99; - - return $CurrentValue; - } - - Write-Progress -Activity $Message -Status ([string]::Format($Status, $ProgressValue)) -PercentComplete $ProgressValue; - - return ($CurrentValue += 1); -}