mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-20 23:00:35 -05:00
Reworks background daemon for JEA context
This commit is contained in:
parent
e3e330f5d3
commit
954e69fde1
13 changed files with 149 additions and 35 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -6,6 +6,7 @@ cache/*
|
|||
.vscode/
|
||||
.vs/
|
||||
*.log
|
||||
*.pfx
|
||||
|
||||
# JEA
|
||||
RoleCapabilities/IcingaForWindows.psrc
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
|
|||
* [#449](https://github.com/Icinga/icinga-powershell-framework/pull/449) Fixes unhandled exception while importing modules during `Install-IcingaComponent` process, because of possible missing dependencies
|
||||
* [#451](https://github.com/Icinga/icinga-powershell-framework/pull/451) Fixes PowerShell being unable to enter JEA context if only the Framework is installed and removes the `|` from plugin output, in case a JEA error is thrown that check commands are not present
|
||||
* [#452](https://github.com/Icinga/icinga-powershell-framework/pull/452) Fixes unhandled `true` output on the console while running the installer
|
||||
* [#454](https://github.com/Icinga/icinga-powershell-framework/pull/454) Fixes JEA catalog compiler and background daemon execution in JEA context
|
||||
|
||||
### Enhancements
|
||||
|
||||
|
|
|
|||
|
|
@ -172,8 +172,6 @@ function New-IcingaForWindowsComponent()
|
|||
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/';
|
||||
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 ' Use-Icinga -LibOnly -Daemon;';
|
||||
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 ' while ($TRUE) {';
|
||||
Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' # Add your daemon code within this loop';
|
||||
Add-Content -Path (Join-Path -Path $ModuleDir -ChildPath ([string]::Format('daemon\{0}.psm1', $DaemonEntry))) -Value ' Start-Sleep -Seconds 1;';
|
||||
|
|
|
|||
|
|
@ -7,40 +7,54 @@ function Get-IcingaCommandDependency()
|
|||
[string]$CmdType = ''
|
||||
);
|
||||
|
||||
# Function, Cmdlet, Alias, Modules, Application
|
||||
if ([string]::IsNullOrEmpty($CmdType)) {
|
||||
return $CompiledList;
|
||||
}
|
||||
|
||||
# Create the list container for our object type if not existing
|
||||
# => Function, Cmdlet, Alias, Modules, Application
|
||||
if ($CompiledList.ContainsKey($CmdType) -eq $FALSE) {
|
||||
$CompiledList.Add($CmdType, @{ });
|
||||
}
|
||||
|
||||
# e.g. Invoke-IcingaCheckCPU
|
||||
if ($CompiledList[$CmdType].ContainsKey($CmdName)) {
|
||||
$CompiledList[$CmdType][$CmdName] += 1;
|
||||
|
||||
return $CompiledList;
|
||||
}
|
||||
|
||||
# Add the command this function is called with
|
||||
$CompiledList[$CmdType].Add($CmdName, 0);
|
||||
|
||||
# The command is not known in our Framework dependency list -> could be a native Windows command
|
||||
if ((Test-PSCustomObjectMember -PSObject $DependencyList -Name $CmdName) -eq $FALSE) {
|
||||
return $CompiledList;
|
||||
}
|
||||
|
||||
# Loop our entire dependency list for every single command
|
||||
foreach ($CmdList in $DependencyList.$CmdName.PSObject.Properties.Name) {
|
||||
# $Cmd => The list of child commands
|
||||
# $CmdList => Function, Cmdlet, Alias, Modules, Application
|
||||
$Cmd = $DependencyList.$CmdName.$CmdList;
|
||||
|
||||
# Create the list container for our object type if not existing
|
||||
# => Function, Cmdlet, Alias, Modules, Application
|
||||
if ($CompiledList.ContainsKey($CmdList) -eq $FALSE) {
|
||||
$CompiledList.Add($CmdList, @{ });
|
||||
}
|
||||
|
||||
# Loop all commands within our child list for this command
|
||||
foreach ($entry in $Cmd.PSObject.Properties.Name) {
|
||||
if ($CompiledList[$CmdList].ContainsKey($entry) -eq $FALSE) {
|
||||
$CompiledList[$CmdList].Add($entry, 0);
|
||||
|
||||
# $entry => The command name e.g. Write-IcingaConsolePlain
|
||||
if ($CompiledList[$CmdList].ContainsKey($entry) -eq $FALSE) {
|
||||
$CompiledList = Get-IcingaCommandDependency `
|
||||
-DependencyList $DependencyList `
|
||||
-CompiledList $CompiledList `
|
||||
-CmdName $entry;
|
||||
-CmdName $entry `
|
||||
-CmdType $CmdList;
|
||||
} else {
|
||||
$CompiledList[$CmdList][$entry] += 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,11 +147,17 @@ function Get-IcingaJEAConfiguration()
|
|||
-CmdType 'Function';
|
||||
|
||||
# We need to add this function for our background daemon we start with 'Start-IcingaForWindowsDaemon',
|
||||
# as this function is called outside the JEA context
|
||||
# as these functions are called outside the JEA context
|
||||
$UsedCmdlets = Get-IcingaCommandDependency `
|
||||
-DependencyList $DependencyList `
|
||||
-CompiledList $UsedCmdlets `
|
||||
-CmdName 'Add-IcingaForWindowsDaemon' `
|
||||
-CmdName 'Start-IcingaPowerShellDaemon' `
|
||||
-CmdType 'Function';
|
||||
|
||||
$UsedCmdlets = Get-IcingaCommandDependency `
|
||||
-DependencyList $DependencyList `
|
||||
-CompiledList $UsedCmdlets `
|
||||
-CmdName 'Start-IcingaForWindowsDaemon' `
|
||||
-CmdType 'Function';
|
||||
|
||||
# Fixes error if only the Icinga PowerShell Framework is installed, which then causes JEA to fail entirely because of this missing Cmdlet
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ function Read-IcingaPowerShellModuleFile()
|
|||
[hashtable]$CmdCache = @{ };
|
||||
[hashtable]$FncCache = @{ };
|
||||
[int]$Index = 0;
|
||||
[bool]$ThreadCommand = $FALSE;
|
||||
[bool]$ThreadFetchNext = $FALSE;
|
||||
[bool]$ShellCommand = $FALSE;
|
||||
[bool]$ShellGroupStart = $FALSE;
|
||||
|
||||
foreach ($entry in $PSParser) {
|
||||
if ($entry.Type -eq 'Comment') {
|
||||
|
|
@ -31,6 +35,12 @@ function Read-IcingaPowerShellModuleFile()
|
|||
$CommandList += [string]$entry.Content;
|
||||
$CmdCache.Add($entry.Content, 0);
|
||||
}
|
||||
|
||||
# We need to include commands we call with New-IcingaThreadInstance e.g.
|
||||
# => New-IcingaThreadInstance -Name "Main" -ThreadPool (Get-IcingaThreadPool -Name 'MainPool') -Command 'Add-IcingaForWindowsDaemon' -Start;
|
||||
if ($entry.Content.ToLower() -eq 'new-icingathreadinstance') {
|
||||
$ThreadCommand = $TRUE;
|
||||
}
|
||||
} elseif ($entry.Type -eq 'CommandArgument') {
|
||||
if ($PSParser[$index - 1].Type -eq 'Keyword' -And $PSParser[$index - 1].Content.ToLower() -eq 'function') {
|
||||
if ($FncCache.ContainsKey($entry.Content) -eq $FALSE) {
|
||||
|
|
@ -38,6 +48,55 @@ function Read-IcingaPowerShellModuleFile()
|
|||
$FncCache.Add($entry.Content, 0);
|
||||
}
|
||||
}
|
||||
} elseif ($entry.Type -eq 'Member' -And $entry.Content.ToLower() -eq 'addcommand') {
|
||||
# In case we have objects that use .AddCommand() we should add these to our function list e.g.
|
||||
# => [void]$Shell.AddCommand('Set-IcingaEnvironmentGlobal');
|
||||
$ShellCommand = $TRUE;
|
||||
}
|
||||
|
||||
# If we reached -Command for New-IcingaThreadInstance, check for the String element and add its value to our function list e.g.
|
||||
# => Add-IcingaForWindowsDaemon
|
||||
if ($ThreadFetchNext) {
|
||||
if ($entry.Type -eq 'String') {
|
||||
if (Test-IcingaFunction $entry.Content) {
|
||||
if ($FncCache.ContainsKey($entry.Content) -eq $FALSE) {
|
||||
$FunctionList += [string]$entry.Content;
|
||||
$FncCache.Add($entry.Content, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
$ThreadFetchNext = $FALSE;
|
||||
}
|
||||
|
||||
# If we found the command New-IcingaThreadInstance inside ths script, loop until we reach -Command
|
||||
if ($ThreadCommand) {
|
||||
if ($entry.Type -eq 'CommandParameter' -And $entry.Content.ToLower() -eq '-command') {
|
||||
$ThreadFetchNext = $TRUE;
|
||||
$ThreadCommand = $FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
# If we reached the string content of our .AddCommand() object. add its value to our function list e.g.
|
||||
# => Set-IcingaEnvironmentGlobal
|
||||
if ($ShellGroupStart) {
|
||||
if ($entry.Type -eq 'String') {
|
||||
if (Test-IcingaFunction $entry.Content) {
|
||||
if ($FncCache.ContainsKey($entry.Content) -eq $FALSE) {
|
||||
$FunctionList += [string]$entry.Content;
|
||||
$FncCache.Add($entry.Content, 0);
|
||||
}
|
||||
}
|
||||
|
||||
$ShellGroupStart = $FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
# If we found an .AddArgument() member, continue until our group starts with (
|
||||
if ($ShellCommand) {
|
||||
if ($entry.Type -eq 'GroupStart' -And $entry.Content.ToLower() -eq '(') {
|
||||
$ShellCommand = $FALSE;
|
||||
$ShellGroupStart = $TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
$Index += 1;
|
||||
|
|
|
|||
24
lib/core/jea/Set-IcingaForWindowsServiceJEAProfile.psm1
Normal file
24
lib/core/jea/Set-IcingaForWindowsServiceJEAProfile.psm1
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
function Set-IcingaForWindowsServiceJEAProfile()
|
||||
{
|
||||
[string]$JeaProfile = Get-IcingaJEAContext;
|
||||
$IcingaForWindowsService = Get-IcingaForWindowsServiceData;
|
||||
|
||||
if ([string]::IsNullOrEmpty($IcingaForWindowsService.FullPath) -Or (Test-Path $IcingaForWindowsService.FullPath) -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
[string]$PreparedServicePath = [string]::Format(
|
||||
'\"{0}\" \"{1}\" \"{2}\"',
|
||||
$IcingaForWindowsService.FullPath,
|
||||
(Get-IcingaPowerShellModuleFile),
|
||||
$JeaProfile
|
||||
);
|
||||
|
||||
$Result = Start-IcingaProcess -Executable 'sc.exe' -Arguments ([string]::Format('config icingapowershell binPath= "{0}"', $PreparedServicePath));
|
||||
|
||||
if ($Result.ExitCode -ne 0) {
|
||||
Write-IcingaConsoleError 'Failed to update Icinga for Windows service for JEA profile "{0}": {1}{2}' -Objects $JeaProfile, $ResolveStatus.Message, $ResolveStatus.Error;
|
||||
} else {
|
||||
Write-IcingaConsoleNotice 'Icinga for Windows service JEA handling has been configured successfully to profile "{0}"' -Objects $JeaProfile;
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,12 @@ function New-IcingaThreadInstance()
|
|||
[void]$Shell.AddParameter('GlobalEnvironment', $Global:Icinga.Public);
|
||||
}
|
||||
|
||||
# Set the JEA context for all threads
|
||||
if ($null -ne $Global:Icinga -And $Global:Icinga.ContainsKey('Protected') -And $Global:Icinga.Protected.ContainsKey('JEAContext')) {
|
||||
[void]$Shell.AddCommand('Set-IcingaEnvironmentJEA');
|
||||
[void]$Shell.AddParameter('JeaEnabled', $Global:Icinga.Protected.JEAContext);
|
||||
}
|
||||
|
||||
[void]$Shell.AddCommand($Command);
|
||||
|
||||
$CodeHash = $Command;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ function New-IcingaThreadPool()
|
|||
$SessionFile = Get-IcingaJEASessionFile;
|
||||
|
||||
if ([string]::IsNullOrEmpty((Get-IcingaJEAContext))) {
|
||||
$SessionConfiguration = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault();
|
||||
$SessionConfiguration = [System.Management.Automation.RunSpaces.InitialSessionState]::CreateDefault();
|
||||
} else {
|
||||
if ([string]::IsNullOrEmpty($SessionFile)) {
|
||||
Write-IcingaEventMessage -EventId 1502 -Namespace 'Framework';
|
||||
|
|
@ -18,14 +18,14 @@ function New-IcingaThreadPool()
|
|||
$SessionConfiguration = [System.Management.Automation.Runspaces.InitialSessionState]::CreateFromSessionConfigurationFile($SessionFile);
|
||||
}
|
||||
|
||||
$Runspaces = [RunspaceFactory]::CreateRunspacePool(
|
||||
$RunSpaces = [RunSpaceFactory]::CreateRunSpacePool(
|
||||
$MinInstances,
|
||||
$MaxInstances,
|
||||
$SessionConfiguration,
|
||||
$host
|
||||
)
|
||||
|
||||
$Runspaces.Open();
|
||||
$RunSpaces.Open();
|
||||
|
||||
return $Runspaces;
|
||||
return $RunSpaces;
|
||||
}
|
||||
|
|
|
|||
10
lib/core/thread/Set-IcingaEnvironmentJEA.psm1
Normal file
10
lib/core/thread/Set-IcingaEnvironmentJEA.psm1
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
function Set-IcingaEnvironmentJEA()
|
||||
{
|
||||
param (
|
||||
[bool]$JeaEnabled = $FALSE
|
||||
);
|
||||
|
||||
if ($null -ne $Global:Icinga -And $Global:Icinga.ContainsKey('Protected') -And $Global:Icinga.Protected.ContainsKey('JEAContext')) {
|
||||
$Global:Icinga.Protected.JEAContext = $JeaEnabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,20 +2,23 @@ function Start-IcingaPowerShellDaemon()
|
|||
{
|
||||
param (
|
||||
[switch]$RunAsService = $FALSE,
|
||||
[switch]$JEAContext = $FALSE,
|
||||
[switch]$JEARestart = $FALSE
|
||||
);
|
||||
|
||||
Start-IcingaForWindowsDaemon -RunAsService:$RunAsService -JEARestart:$JEARestart;
|
||||
Start-IcingaForWindowsDaemon -RunAsService:$RunAsService -JEARestart:$JEARestart -JEAContext:$JEAContext;
|
||||
}
|
||||
|
||||
function Start-IcingaForWindowsDaemon()
|
||||
{
|
||||
param (
|
||||
[switch]$RunAsService = $FALSE,
|
||||
[switch]$JEAContext = $FALSE,
|
||||
[switch]$JEARestart = $FALSE
|
||||
);
|
||||
|
||||
$Global:Icinga.Protected.RunAsDaemon = $TRUE;
|
||||
$Global:Icinga.Protected.RunAsDaemon = [bool]$RunAsService;
|
||||
$Global:Icinga.Protected.JEAContext = [bool]$JEAContext;
|
||||
[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';
|
||||
|
|
@ -32,7 +35,6 @@ function Start-IcingaForWindowsDaemon()
|
|||
if ([string]::IsNullOrEmpty($JeaProfile)) {
|
||||
Write-IcingaDebugMessage -Message 'Starting Icinga for Windows service without JEA context' -Objects $RunAsService, $JEARestart, $JeaProfile;
|
||||
|
||||
$Global:Icinga.Protected.RunAsDaemon = $TRUE;
|
||||
# Todo: Add config for active background tasks. Set it to 20 for the moment
|
||||
Add-IcingaThreadPool -Name 'MainPool' -MaxInstances 20;
|
||||
$Global:Icinga.Public.Add('SSLCertificate', $Certificate);
|
||||
|
|
@ -41,6 +43,7 @@ function Start-IcingaForWindowsDaemon()
|
|||
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 {
|
||||
try {
|
||||
Use-Icinga -Daemon;
|
||||
|
|
@ -84,7 +87,7 @@ function Start-IcingaForWindowsDaemon()
|
|||
|
||||
Write-IcingaFileSecure -File $JeaPidFile -Value '';
|
||||
Write-IcingaEventMessage -EventId 1505 -Namespace Framework -Objects ([string]::Format('{0}/5', $JeaRestartCounter));
|
||||
Start-IcingaForWindowsDaemon -RunAsService:$RunAsService -JEARestart;
|
||||
Start-IcingaForWindowsDaemon -RunAsService:$RunAsService -JEAContext:$JEAContext -JEARestart;
|
||||
|
||||
$JeaRestartCounter += 1;
|
||||
$JeaPid = '';
|
||||
|
|
|
|||
|
|
@ -9,10 +9,6 @@ function New-IcingaForWindowsRESTApi()
|
|||
$RequireAuth
|
||||
);
|
||||
|
||||
# Import the framework library components and initialise it
|
||||
# as daemon
|
||||
Use-Icinga -LibOnly -Daemon;
|
||||
|
||||
$RESTEndpoints = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaRESTAPIEndpoint*';
|
||||
Write-IcingaDebugMessage -Message (
|
||||
[string]::Format(
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@ function New-IcingaForWindowsRESTThread()
|
|||
$ThreadId
|
||||
);
|
||||
|
||||
# Import the framework library components and initialise it
|
||||
# as daemon
|
||||
Use-Icinga -LibOnly -Daemon;
|
||||
|
||||
# Initialise our performance counter categories
|
||||
Show-IcingaPerformanceCounterCategories | Out-Null;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue