mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2026-02-03 12:19:29 -05:00
Merge pull request #709 from Icinga:fix/icinga_for_windows_repository_error_handling
Fix: Repository error handling and JSON error handling Fixes error handling for Icinga for Windows repositories by providing more details about occurring errors as well as properly checking the JSON-File for the repository and providing more details about JSON errors
This commit is contained in:
commit
2ad90a90ef
13 changed files with 206 additions and 24 deletions
|
|
@ -20,6 +20,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
|
|||
* [#672](https://github.com/Icinga/icinga-powershell-framework/pull/issues) Fixes Icinga for Windows REST-Api to fully read client data, even when they client is sending the packets on a very slow basis, preventing the API trying to process an incomplete request
|
||||
* [#707](https://github.com/Icinga/icinga-powershell-framework/pull/707) Fixes size of the `Icinga for Windows` eventlog by setting it to `20MiB`, allowing to store more events before they are overwritten
|
||||
* [#708](https://github.com/Icinga/icinga-powershell-framework/pull/708) Fixes the order for updating components with `Update-Icinga`, to ensure the `framework` is always updated first before all other components
|
||||
* [#709](https://github.com/Icinga/icinga-powershell-framework/pull/709) Fixes error handling for Icinga for Windows repositories by providing more details about occurring errors as well as properly checking the JSON-File for the repository and providing more details about JSON errors
|
||||
* [#710](https://github.com/Icinga/icinga-powershell-framework/pull/710) Fixes various console errors while running Icinga for Windows outside of an administrative shell
|
||||
* [#713](https://github.com/Icinga/icinga-powershell-framework/pull/713) Fixes Icinga for Windows REST-Api which fails during certificate auth handling while running as `NT Authority\NetworkService`
|
||||
* [#714](https://github.com/Icinga/icinga-powershell-framework/pull/714) Fixes missing service environment information during initial setup of Icinga for Windows v1.12 on some systems
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ function New-IcingaEnvironmentVariable()
|
|||
$Global:Icinga.Private.Add('Documentation', @{ });
|
||||
$Global:Icinga.Private.Add('Timers', @{ });
|
||||
$Global:Icinga.Private.Add('ProgressStatus', @{ });
|
||||
$Global:Icinga.Private.Add(
|
||||
'RepositoryStatus',
|
||||
@{
|
||||
'FailedRepositories' = @{ };
|
||||
}
|
||||
);
|
||||
|
||||
$Global:Icinga.Private.Add(
|
||||
'Scheduler',
|
||||
|
|
|
|||
32
lib/core/repository/Add-IcingaRepositoryErrorState.psm1
Normal file
32
lib/core/repository/Add-IcingaRepositoryErrorState.psm1
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
function Add-IcingaRepositoryErrorState()
|
||||
{
|
||||
param (
|
||||
[string]$Repository = $null
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($Repository)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga -eq $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Contains('Private') -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.Contains('RepositoryStatus') -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.RepositoryStatus.Contains('FailedRepositories') -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.RepositoryStatus.FailedRepositories.ContainsKey($Repository)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Global:Icinga.Private.RepositoryStatus.FailedRepositories.Add($Repository, $TRUE);
|
||||
}
|
||||
16
lib/core/repository/Clear-IcingaRepositoryErrorState.psm1
Normal file
16
lib/core/repository/Clear-IcingaRepositoryErrorState.psm1
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
function Clear-IcingaRepositoryErrorState()
|
||||
{
|
||||
if ($Global:Icinga -eq $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Contains('Private') -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.Contains('RepositoryStatus') -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Global:Icinga.Private.RepositoryStatus.FailedRepositories = @{ };
|
||||
}
|
||||
|
|
@ -15,6 +15,9 @@ function Get-IcingaComponentList()
|
|||
$SearchList | Add-Member -MemberType NoteProperty -Name 'Repos' -Value @();
|
||||
$SearchList | Add-Member -MemberType NoteProperty -Name 'Components' -Value @{ };
|
||||
|
||||
# Ensure our error list is cleared at this point
|
||||
Clear-IcingaRepositoryErrorState;
|
||||
|
||||
foreach ($entry in $Repositories) {
|
||||
$RepoContent = Read-IcingaRepositoryFile -Name $entry.Name;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ function Get-IcingaInstallation()
|
|||
|
||||
Set-IcingaServiceEnvironment;
|
||||
|
||||
# Ensure our error list is cleared at this point
|
||||
Clear-IcingaRepositoryErrorState;
|
||||
|
||||
[hashtable]$InstalledComponents = @{ };
|
||||
|
||||
$PowerShellModules = Get-Module -ListAvailable;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
function Install-IcingaComponent()
|
||||
{
|
||||
param (
|
||||
[string]$Name = $null,
|
||||
[string]$Version = $null,
|
||||
[switch]$Release = $FALSE,
|
||||
[switch]$Snapshot = $FALSE,
|
||||
[switch]$Confirm = $FALSE,
|
||||
[switch]$Force = $FALSE
|
||||
[string]$Name = $null,
|
||||
[string]$Version = $null,
|
||||
[switch]$Release = $FALSE,
|
||||
[switch]$Snapshot = $FALSE,
|
||||
[switch]$Confirm = $FALSE,
|
||||
[switch]$Force = $FALSE,
|
||||
[switch]$KeepRepoErrors = $FALSE
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($Name)) {
|
||||
|
|
@ -14,6 +15,10 @@ function Install-IcingaComponent()
|
|||
return;
|
||||
}
|
||||
|
||||
if ($KeepRepoErrors -eq $FALSE) {
|
||||
Clear-IcingaRepositoryErrorState;
|
||||
}
|
||||
|
||||
# Branch snapshot versions will have '/' inside their name
|
||||
if ($Name.Contains('/') -And $Snapshot) {
|
||||
$Name = $Name.Split('/')[0];
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
function Read-IcingaRepositoryFile()
|
||||
{
|
||||
param (
|
||||
[string]$Name = $null,
|
||||
[switch]$TryAlternate = $FALSE
|
||||
[string]$Name = $null,
|
||||
[switch]$TryAlternate = $FALSE,
|
||||
[switch]$PrintRetryMsg = $FALSE
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($Name)) {
|
||||
|
|
@ -10,6 +11,10 @@ function Read-IcingaRepositoryFile()
|
|||
return $null;
|
||||
}
|
||||
|
||||
if ((Test-IcingaRepositoryErrorState -Repository $Name) -And $TryAlternate -eq $FALSE) {
|
||||
return $null;
|
||||
}
|
||||
|
||||
$Name = $Name.Replace('.', '-');
|
||||
|
||||
$Repository = Get-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.Repositories.{0}', $Name));
|
||||
|
|
@ -22,6 +27,10 @@ function Read-IcingaRepositoryFile()
|
|||
$RepoPath = $null;
|
||||
$Content = $null;
|
||||
|
||||
if ($PrintRetryMsg) {
|
||||
Write-IcingaConsoleNotice 'Unable to fetch Icinga for Windows repository information for repository "{0}" from provided location. Trying different lookup by adding "ifw.repo.json" to the end of the remote path.' -Objects $Name;
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($Repository.LocalPath) -eq $FALSE -And (Test-Path -Path $Repository.LocalPath)) {
|
||||
$RepoPath = $Repository.LocalPath;
|
||||
} elseif ([string]::IsNullOrEmpty($Repository.RemotePath) -eq $FALSE -And (Test-Path -Path $Repository.RemotePath)) {
|
||||
|
|
@ -29,17 +38,19 @@ function Read-IcingaRepositoryFile()
|
|||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($RepoPath) -eq $FALSE -And (Test-Path -Path $RepoPath)) {
|
||||
if ([IO.Path]::GetExtension($RepoPath).ToLower() -ne '.json' -And $TryAlternate -eq $FALSE) {
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate);
|
||||
} elseif ([IO.Path]::GetExtension($RepoPath).ToLower() -ne '.json' -And $TryAlternat) {
|
||||
Write-IcingaConsoleError 'Unable to read repository file from "{0}" for repository "{1}". No "ifw.repo.json" was found at defined location' -Objects $RepoPath, $Name;
|
||||
return $null;
|
||||
}
|
||||
|
||||
if ($TryAlternate) {
|
||||
$RepoPath = Join-Path $RepoPath -ChildPath 'ifw.repo.json';
|
||||
}
|
||||
|
||||
if ([IO.Path]::GetExtension($RepoPath).ToLower() -ne '.json' -And $TryAlternate -eq $FALSE) {
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate);
|
||||
} elseif ([IO.Path]::GetExtension($RepoPath).ToLower() -ne '.json' -And $TryAlternate) {
|
||||
Write-IcingaConsoleError 'Unable to read repository file from "{0}" for repository "{1}". No "ifw.repo.json" was found at defined location' -Objects $RepoPath, $Name;
|
||||
Add-IcingaRepositoryErrorState -Repository $Name;
|
||||
return $null;
|
||||
}
|
||||
|
||||
$Content = Get-Content -Path $RepoPath -Raw;
|
||||
} else {
|
||||
try {
|
||||
|
|
@ -52,19 +63,26 @@ function Read-IcingaRepositoryFile()
|
|||
$WebContent = Invoke-IcingaWebRequest -UseBasicParsing -Uri $RepoPath;
|
||||
|
||||
if ($null -ne $WebContent) {
|
||||
if ($WebContent.RawContent.Contains('application/octet-stream')) {
|
||||
$Content = [System.Text.Encoding]::UTF8.GetString($WebContent.Content)
|
||||
if ((Test-PSCustomObjectMember -PSObject $WebContent -Name 'RawContent') -Or (Test-PSCustomObjectMember -PSObject $WebContent -Name 'Content')) {
|
||||
if ((Test-PSCustomObjectMember -PSObject $WebContent -Name 'RawContent') -And $WebContent.RawContent.Contains('application/octet-stream')) {
|
||||
$Content = [System.Text.Encoding]::UTF8.GetString($WebContent.Content)
|
||||
} else {
|
||||
$Content = $WebContent.Content;
|
||||
}
|
||||
} else {
|
||||
$Content = $WebContent.Content;
|
||||
if ($TryAlternate -eq $FALSE) {
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate -PrintRetryMsg);
|
||||
}
|
||||
$Content = $null;
|
||||
}
|
||||
} else {
|
||||
if ($TryAlternate -eq $FALSE) {
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate);
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate -PrintRetryMsg);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
if ($TryAlternate -eq $FALSE) {
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate);
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate -PrintRetryMsg);
|
||||
} else {
|
||||
Write-IcingaConsoleError 'Unable to resolve repository URL "{0}" for repository "{1}": {2}' -Objects $Repository.RemotePath, $Name, $_.Exception.Message;
|
||||
return $null;
|
||||
|
|
@ -74,15 +92,21 @@ function Read-IcingaRepositoryFile()
|
|||
|
||||
if ($null -eq $Content) {
|
||||
Write-IcingaConsoleError 'Unable to fetch data for repository "{0}" from any configured location' -Objects $Name;
|
||||
Add-IcingaRepositoryErrorState -Repository $Name;
|
||||
return $null;
|
||||
}
|
||||
|
||||
try {
|
||||
$RepositoryObject = $null;
|
||||
|
||||
if (Test-IcingaJSONObject -InputObject $Content) {
|
||||
$RepositoryObject = ConvertFrom-Json -InputObject $Content -ErrorAction Stop;
|
||||
} catch {
|
||||
} else {
|
||||
Write-IcingaConsoleError 'Failed to convert retreived content from repository "{0}" with location "{1}" to JSON' -Objects $Name, $Repository.RemotePath
|
||||
if ($TryAlternate -eq $FALSE) {
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate);
|
||||
return (Read-IcingaRepositoryFile -Name $Name -TryAlternate -PrintRetryMsg);
|
||||
}
|
||||
|
||||
Add-IcingaRepositoryErrorState -Repository $Name;
|
||||
}
|
||||
|
||||
return $RepositoryObject;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ function Search-IcingaRepository()
|
|||
$SearchList = New-Object -TypeName PSObject;
|
||||
$SearchList | Add-Member -MemberType NoteProperty -Name 'Repos' -Value @();
|
||||
|
||||
# Ensure our error list is cleared at this point
|
||||
Clear-IcingaRepositoryErrorState;
|
||||
|
||||
foreach ($entry in $Repositories) {
|
||||
$RepoContent = Read-IcingaRepositoryFile -Name $entry.Name;
|
||||
|
||||
|
|
|
|||
51
lib/core/repository/Test-IcingaJSONObject.psm1
Normal file
51
lib/core/repository/Test-IcingaJSONObject.psm1
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
function Test-IcingaJSONObject()
|
||||
{
|
||||
param (
|
||||
[string]$InputObject = $null
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($InputObject)) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
try {
|
||||
$JSONContent = ConvertFrom-Json -InputObject $InputObject -ErrorAction Stop;
|
||||
return $TRUE;
|
||||
} catch {
|
||||
[string]$ErrMsg = $_.Exception.Message;
|
||||
|
||||
if ($ErrMsg.Contains('(') -And $ErrMsg.Contains(')')) {
|
||||
try {
|
||||
[int]$ErrLocation = $ErrMsg.Substring($ErrMsg.IndexOf('(') + 1, $ErrMsg.IndexOf(')') - $ErrMsg.IndexOf('(') - 1) - 1;
|
||||
[string]$ExceptionMsg = $ErrMsg.Substring(0, $ErrMsg.IndexOf(')') + 1);
|
||||
[string]$ErrOutput = $InputObject.Substring(0, $ErrLocation);
|
||||
[array]$ErrArray = $ErrOutput.Split("`n");
|
||||
[string]$Indentation = '';
|
||||
[string]$ErrLine = '';
|
||||
|
||||
[int]$tmp = 0;
|
||||
foreach ($entry in $ErrArray) {
|
||||
$tmp += 1;
|
||||
}
|
||||
|
||||
foreach ($character in ([string]($ErrArray[$ErrArray.Count - 2])).ToCharArray()) {
|
||||
if ([string]::IsNullOrEmpty($character) -Or $character -eq ' ') {
|
||||
$Indentation += ' ';
|
||||
} else {
|
||||
$ErrLine += '^';
|
||||
}
|
||||
}
|
||||
|
||||
$ErrOutput = [string]::Format('{0}{1}{2}{3}', $ErrOutput, (New-IcingaNewLine), $Indentation, $ErrLine);
|
||||
|
||||
Write-IcingaConsoleError 'Failed to parse JSON object. Exception: {0}{1}{2}' -Objects $ExceptionMsg, (New-IcingaNewLine), $ErrOutput;
|
||||
return $FALSE;
|
||||
} catch {
|
||||
Write-IcingaConsoleError 'Failed to parse JSON object: {0}' -Objects $ErrMsg;
|
||||
return $FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $TRUE;
|
||||
}
|
||||
32
lib/core/repository/Test-IcingaRepositoryErrorState.psm1
Normal file
32
lib/core/repository/Test-IcingaRepositoryErrorState.psm1
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
function Test-IcingaRepositoryErrorState()
|
||||
{
|
||||
param (
|
||||
[string]$Repository
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($Repository)) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
if ($Global:Icinga -eq $null) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Contains('Private') -eq $FALSE) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.Contains('RepositoryStatus') -eq $FALSE) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.RepositoryStatus.Contains('FailedRepositories') -eq $FALSE) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
if ($Global:Icinga.Private.RepositoryStatus.FailedRepositories.ContainsKey($Repository) -eq $FALSE) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
return $TRUE;
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@ function Update-Icinga()
|
|||
$UpdateJEA = $TRUE;
|
||||
}
|
||||
|
||||
Install-IcingaComponent -Name $entry -Version $NewVersion -Release:$Release -Snapshot:$Snapshot -Confirm:$Confirm -Force:$Force;
|
||||
Install-IcingaComponent -Name $entry -Version $NewVersion -Release:$Release -Snapshot:$Snapshot -Confirm:$Confirm -Force:$Force -KeepRepoErrors;
|
||||
}
|
||||
|
||||
# Update JEA profile if JEA is enabled once the update is complete
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
function Test-PSCustomObjectMember()
|
||||
{
|
||||
param(
|
||||
param (
|
||||
$PSObject,
|
||||
$Name
|
||||
);
|
||||
|
|
@ -9,5 +9,11 @@ function Test-PSCustomObjectMember()
|
|||
return $FALSE;
|
||||
}
|
||||
|
||||
# Lets make sure we also test for hashtables in case our object is a hashtable
|
||||
# instead of a PSCustomObject
|
||||
if ($PSObject -Is [hashtable]) {
|
||||
return ([bool]($PSObject.ContainsKey($Name)));
|
||||
}
|
||||
|
||||
return ([bool]($PSObject.PSObject.Properties.Name -eq $Name));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue