Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Adds test and repair for the Icinga Agent state file #531

Merged
merged 1 commit into from
Jun 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/100-General/10-Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic

* [#40](https://github.com/Icinga/icinga-powershell-framework/issues/40) Adds support to set service recovery for the Icinga Agent and Icinga for Windows service, to restart them in case of a crash or error
* [#525](https://github.com/Icinga/icinga-powershell-framework/pull/525) Adds new developer mode for `icinga` command and improved cache handling, to ensure within `-DeveloperMode` and inside a VS Code environment, the framework cache file is never overwritten, while still all functions are loaded and imported.
* [#531](https://github.com/Icinga/icinga-powershell-framework/pull/531) Adds `Test-IcingaStateFile` and `Repair-IcingaStateFile`, which is integrated into `Test-IcingaAgent`, to ensure the Icinga Agent state file is healthy and not corrupt, causing the Icinga Agent to fail on start

## 1.9.1 (2022-05-13)

Expand Down
46 changes: 46 additions & 0 deletions lib/core/icingaagent/readers/Read-IcingaStateFile.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function Read-IcingaStateFile()
{
param (
[switch]$WriteOutput = $FALSE
);

[string]$StateFilePath = Join-Path -Path $ENV:ProgramData -ChildPath 'icinga2\var\lib\icinga2\icinga2.state';

if ((Test-Path $StateFilePath) -eq $FALSE) {
return $TRUE;
}

$StateFileContent = Get-Content -Path $StateFilePath -Encoding 'UTF8' -Raw;
$FileInformation = Get-Item -Path $StateFilePath;

if ([string]::IsNullOrEmpty($StateFileContent)) {
return $FALSE;
}

while ($TRUE) {
try {
if ([string]::IsNullOrEmpty($StateFileContent)) {
break;
}

if ($StateFileContent.Contains(':') -eq $FALSE) {
Write-IcingaTestOutput -Severity 'Failed' -Message 'The start index of the Icinga Agent state file could not be found. The file seems to be corrupt.' -DropMessage:(-Not $WriteOutput);
return $FALSE;
}

[int]$IndexOfJSON = $StateFileContent.IndexOf(':');
[int]$StatementSize = $StateFileContent.SubString(0, $IndexOfJSON);
[string]$JSONString = $StateFileContent.Substring($IndexOfJSON + 1, $StatementSize);
[int]$TotalMsgLen = $IndexOfJSON + $StatementSize + 2;
$StateFileContent = $StateFileContent.Substring($TotalMsgLen, $StateFileContent.Length - $TotalMsgLen);
$JsonValid = ConvertFrom-Json -InputObject $JSONString -ErrorAction Stop;
} catch {
[string]$ErrMessage = [string]::Format('The Icinga Agent state file validation failed with an exception: "{0}"', $_.Exception.Message);
Write-IcingaTestOutput -Severity 'Failed' -Message $ErrMessage -DropMessage:(-Not $WriteOutput);

return $FALSE;
}
}

return $TRUE;
}
21 changes: 21 additions & 0 deletions lib/core/icingaagent/repair/Repair-IcingaStateFile.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function Repair-IcingaStateFile()
{
param (
[switch]$Force
);

[string]$StateFilePath = Join-Path -Path $ENV:ProgramData -ChildPath 'icinga2\var\lib\icinga2\icinga2.state*';

if ((Test-IcingaStateFile) -And $Force -eq $FALSE) {
Write-IcingaConsoleNotice -Message 'The Icinga Agent state file seems to be okay';
return;
}

$Success = Remove-ItemSecure -Path $StateFilePath -Force -Retries 5;

if ($Success) {
Write-IcingaConsoleNotice -Message 'The corrupted Icinga Agent State files have been removed';
} else {
Write-IcingaConsoleError -Message 'Failed to remove the corrupted Icinga Agent state files';
}
}
1 change: 1 addition & 0 deletions lib/core/icingaagent/tests/Test-IcingaAgent.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function Test-IcingaAgent()
Test-IcingaAcl (Get-IcingaCacheDir) -WriteOutput | Out-Null;
Test-IcingaAcl (Get-IcingaPowerShellConfigDir) -WriteOutput | Out-Null;
Test-IcingaAcl -Directory (Join-Path -Path (Get-IcingaFrameworkRootPath) -ChildPath 'certificate') -WriteOutput | Out-Null;
Test-IcingaStateFile -WriteOutput | Out-Null;

if ($IcingaAgentData.Installed) {
Test-IcingaAgentConfig | Out-Null;
Expand Down
25 changes: 25 additions & 0 deletions lib/core/icingaagent/tests/Test-IcingaStateFile.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
function Test-IcingaStateFile()
{
param (
[switch]$WriteOutput = $FALSE
);

$IcingaAgentData = Get-IcingaAgentInstallation;
[string]$StateFilePath = Join-Path -Path $ENV:ProgramData -ChildPath 'icinga2\var\lib\icinga2\icinga2.state';

if ((Test-Path $StateFilePath) -eq $FALSE) {
Write-IcingaTestOutput -Severity 'Passed' -Message 'The Icinga Agent state file does not exist' -DropMessage:(-Not $WriteOutput);
return $TRUE;
}

$Success = Read-IcingaStateFile;

if ($Success) {
Write-IcingaTestOutput -Severity 'Passed' -Message 'The Icinga Agent state file is healthy' -DropMessage:(-Not $WriteOutput);
return $TRUE;
} else {
Write-IcingaTestOutput -Severity 'Failed' -Message 'The Icinga Agent state file is corrupt. Use the "Repair-IcingaStateFile" command to repair the file or "Read-IcingaStateFile -WriteOutput" for further details' -DropMessage:(-Not $WriteOutput);
}

return $FALSE;
}
7 changes: 6 additions & 1 deletion lib/core/icingaagent/writers/Write-IcingaTestOutput.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ function Write-IcingaTestOutput()
param(
[ValidateSet('Passed', 'Warning', 'Failed')]
$Severity,
$Message
$Message,
[switch]$DropMessage = $FALSE
);

if ($DropMessage) {
return;
}

$Color = 'Green';

Switch ($Severity) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function Show-IcingaForWindowsMenuManageTroubleshooting()
},
@{
'Caption' = 'Repair Icinga Agent service';
'Command' = 'Show-IcingaForWindowsMenuManageIcingaForWindowsServices';
'Command' = 'Show-IcingaForWindowsMenuManageTroubleshooting';
'Help' = 'Allows to repair the Icinga Agent service in case it was removed or broke during installation/upgrade';
'Disabled' = ($null -ne $IcingaAgentService);
'DisabledReason' = 'The Icinga Agent service is already present';
Expand All @@ -52,6 +52,17 @@ function Show-IcingaForWindowsMenuManageTroubleshooting()
'Command' = 'Repair-IcingaService';
}
},
@{
'Caption' = 'Repair Icinga Agent state file';
'Command' = 'Show-IcingaForWindowsMenuManageTroubleshooting';
'Help' = 'Allows to repair the Icinga Agent state file, in case the file is corrupt';
'Disabled' = (Test-IcingaStateFile);
'DisabledReason' = 'The Icinga Agent state file is healthy';
'AdminMenu' = $TRUE;
'Action' = @{
'Command' = 'Repair-IcingaStateFile';
}
},
@{
'Caption' = 'Allow untrusted certificate communication (This session)';
'Command' = 'Show-IcingaForWindowsMenuManageTroubleshooting';
Expand Down