diff --git a/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 b/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 index 7e48f9c..1d263b6 100644 --- a/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 +++ b/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 @@ -15,7 +15,7 @@ function Get-IcingaDirectorSelfServiceConfig() $ProgressPreference = "SilentlyContinue"; - $EndpointUrl = [string]::Format('{0}/self-service/powershell-parameters?key={1}', $DirectorUrl, $ApiKey); + $EndpointUrl = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/powershell-parameters?key={0}', $ApiKey)); $response = Invoke-WebRequest -Uri $EndpointUrl -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST'; diff --git a/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 b/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 new file mode 100644 index 0000000..48fca58 --- /dev/null +++ b/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 @@ -0,0 +1,29 @@ +function Get-IcingaDirectorSelfServiceTicket() +{ + param( + $DirectorUrl, + $ApiKey = $null + ); + + if ([string]::IsNullOrEmpty($DirectorUrl)) { + Write-Host 'Unable to fetch host ticket. No Director url has been specified'; + return; + } + + if ([string]::IsNullOrEmpty($ApiKey)) { + Write-Host 'Unable to fetch host ticket. No API key has been specified'; + return; + } + + [string]$url = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/ticket?key={0}', $ApiKey)); + + $response = Invoke-WebRequest -Uri $url -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST'; + + if ($response.StatusCode -ne 200) { + throw $response.Content; + } + + $JsonContent = ConvertFrom-Json -InputObject $response.Content; + + return $JsonContent; +} diff --git a/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 b/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 index da2250d..13c6c67 100644 --- a/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 +++ b/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 @@ -20,7 +20,7 @@ function Register-IcingaDirectorSelfServiceHost() $ProgressPreference = "SilentlyContinue"; - $EndpointUrl = [string]::Format('{0}/self-service/register-host?name={1}&key={2}', $DirectorUrl, $Hostname, $ApiKey); + $EndpointUrl = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/register-host?name={0}&key={1}', $Hostname, $ApiKey)); $response = Invoke-WebRequest -Uri $EndpointUrl -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST'; @@ -31,8 +31,14 @@ function Register-IcingaDirectorSelfServiceHost() $JsonContent = ConvertFrom-Json -InputObject $response.Content; if (Test-PSCustomObjectMember -PSObject $JsonContent -Name 'error') { + if ($JsonContent.error -like '*already been registered*') { + return $null; + } + throw 'Icinga Director Self-Service has thrown an error: ' + $JsonContent.error; } + Set-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey' -Value $JsonContent; + return $JsonContent; } diff --git a/lib/core/framework/Install-IcingaFrameworkService.psm1 b/lib/core/framework/Install-IcingaFrameworkService.psm1 index 71abdb3..ebf4db2 100644 --- a/lib/core/framework/Install-IcingaFrameworkService.psm1 +++ b/lib/core/framework/Install-IcingaFrameworkService.psm1 @@ -6,6 +6,11 @@ function Install-IcingaFrameworkService() [SecureString]$Password ); + if ([string]::IsNullOrEmpty($Path)) { + Write-Host 'No path specified for Framework service. Service will not be installed'; + return; + } + if ((Test-Path $Path) -eq $FALSE) { throw 'Please specify the path directly to the service binary'; } diff --git a/lib/core/icingaagent/misc/Convert-IcingaDirectorSelfServiceArguments.psm1 b/lib/core/icingaagent/misc/Convert-IcingaDirectorSelfServiceArguments.psm1 new file mode 100644 index 0000000..156bc8d --- /dev/null +++ b/lib/core/icingaagent/misc/Convert-IcingaDirectorSelfServiceArguments.psm1 @@ -0,0 +1,64 @@ +function Convert-IcingaDirectorSelfServiceArguments() +{ + param( + $JsonInput + ); + + if ($null -eq $JsonInput) { + return @{}; + } + + [hashtable]$DirectorArguments = @{ + PackageSource = $JsonInput.download_url; + AgentVersion = $JsonInput.agent_version; + CAPort = $JsonInput.agent_listen_port; + AllowVersionChanges = $JsonInput.allow_updates; + GlobalZones = $JsonInput.global_zones; + ParentZone = $JsonInput.parent_zone; + CAEndpoint = $JsonInput.ca_server; + Endpoints = $JsonInput.parent_endpoints; + AddFirewallRule = $JsonInput.agent_add_firewall_rule; + AcceptConnections = $JsonInput.agent_add_firewall_rule; + #ServiceUser = $JsonInput.service_user; # This is yet missing within the Icinga Director API + ServiceUser = 'NT Authority\NetworkService'; + UpdateAgent = $TRUE; + AddDirectorGlobal = $FALSE; + AddGlobalTemplates = $FALSE; + RunInstaller = $TRUE; + }; + + if ($JsonInput.transform_hostname -eq 1) { + $DirectorArguments.Add( + 'LowerCase', $TRUE + ); + } + + if ($JsonInput.transform_hostname -eq 2) { + $DirectorArguments.Add( + 'UpperCase', $TRUE + ); + } + + if ($JsonInput.fetch_agent_fqdn) { + $DirectorArguments.Add( + 'AutoUseFQDN', $TRUE + ); + } elseif ($JsonInput.fetch_agent_name) { + $DirectorArguments.Add( + 'AutoUseHostname', $TRUE + ); + } + + $NetworkDefault = ''; + foreach ($Endpoint in $JsonInput.parent_endpoints) { + $NetworkDefault += [string]::Format('[{0}]:{1},', $Endpoint, $JsonInput.agent_listen_port); + } + if ([string]::IsNullOrEmpty($NetworkDefault) -eq $FALSE) { + $NetworkDefault = $NetworkDefault.Substring(0, $NetworkDefault.Length - 1); + $DirectorArguments.Add( + 'EndpointConnections', $NetworkDefault + ); + } + + return $DirectorArguments; +} diff --git a/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 b/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 new file mode 100644 index 0000000..51f13cc --- /dev/null +++ b/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 @@ -0,0 +1,127 @@ +function Start-IcingaAgentDirectorWizard() +{ + param( + [string]$DirectorUrl, + [string]$SelfServiceAPIKey, + $OverrideDirectorVars = $null, + $InstallFrameworkService = $null, + $ServiceDirectory = $null, + $ServiceBin = $null, + [bool]$RunInstaller = $FALSE + ); + + if ([string]::IsNullOrEmpty($DirectorUrl)) { + $DirectorUrl = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the Url pointing to your Icinga Director' -Default 'v').answer; + } + + [bool]$HostKnown = $FALSE; + [string]$TemplateKey = $SelfServiceAPIKey; + + if ($null -eq $OverrideDirectorVars) { + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to manually override arguments provided by the Director API?' -Default 'n').result -eq 0) { + $OverrideDirectorVars = $TRUE; + } else{ + $OverrideDirectorVars = $FALSE; + } + } + + $SelfServiceAPIKey = Get-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey'; + if ([string]::IsNullOrEmpty($SelfServiceAPIKey)) { + $LegacyTokenPath = Join-Path -Path Get-IcingaAgentConfigDirectory -ChildPath 'icingadirector.token'; + if (Test-Path $LegacyTokenPath) { + $SelfServiceAPIKey = Get-Content -Path $LegacyTokenPath; + Set-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey' -Value $SelfServiceAPIKey; + } + } + + if ([string]::IsNullOrEmpty($SelfServiceAPIKey)) { + $SelfServiceAPIKey = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter your Self-Service API key' -Default 'v').answer; + } else { + $HostKnown = $TRUE; + } + + $Arguments = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey; + $Arguments = Convert-IcingaDirectorSelfServiceArguments -JsonInput $Arguments; + + if ($OverrideDirectorVars -eq $TRUE) { + $NewArguments = Start-IcingaDirectorAPIArgumentOverride -Arguments $Arguments; + $Arguments = $NewArguments; + } + + if ($HostKnown -eq $FALSE) { + Write-Host $SelfServiceAPIKey; + Write-Host (Get-IcingaHostname @Arguments); + Write-Host $DirectorUrl; + $SelfServiceAPIKey = Register-IcingaDirectorSelfServiceHost -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey -Hostname (Get-IcingaHostname @Arguments); + + # Host is already registered + if ($null -eq $SelfServiceAPIKey) { + Write-Host 'The wizard is unable to complete as this host is already registered but the local API key is not stored within the config' + return; + } + + $Arguments = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey; + $Arguments = Convert-IcingaDirectorSelfServiceArguments -JsonInput $Arguments; + if ($OverrideDirectorVars -eq $TRUE) { + $NewArguments = Start-IcingaDirectorAPIArgumentOverride -Arguments $Arguments; + $Arguments = $NewArguments; + } + } + + $Arguments.Add( + 'UseDirectorSelfService', $TRUE + ); + $Arguments.Add( + 'OverrideDirectorVars', $FALSE + ); + $Arguments.Add( + 'DirectorUrl', $DirectorUrl + ); + $Arguments.Add( + 'SelfServiceAPIKey', $TemplateKey + ); + $Arguments.Add( + 'SkipDirectorQuestion', $TRUE + ); + $Arguments.Add( + 'InstallFrameworkService', $InstallFrameworkService + ); + $Arguments.Add( + 'ServiceDirectory', $ServiceDirectory + ); + $Arguments.Add( + 'ServiceBin', $ServiceBin + ); + $Arguments.Add( + 'ProvidedArgs', $Arguments + ); + + if ($RunInstaller) { + Start-IcingaAgentInstallWizard @Arguments; + return; + } + + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'The Director wizard is complete. Do you want to start the installation now?' -Default 'y').result -eq 1) { + Start-IcingaAgentInstallWizard @Arguments; + } +} + +function Start-IcingaDirectorAPIArgumentOverride() +{ + param( + $Arguments + ); + + $NewArguments = @{}; + Write-Host 'Please follow the wizard and manually override all entries you intend to'; + Write-Host '===='; + + foreach ($entry in $Arguments.Keys) { + $value = (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Please enter the new value for the argument "{0}"', $entry)) -Default 'v' -DefaultInput $Arguments[$entry]).answer; + $NewArguments.Add($entry, $value); + } + + return $NewArguments; +} + +Export-ModuleMember -Function @( 'Start-IcingaAgentDirectorWizard' ); diff --git a/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 b/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 index 44f4d23..4a8b926 100644 --- a/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 +++ b/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 @@ -28,12 +28,41 @@ function Start-IcingaAgentInstallWizard() $InstallFrameworkService = $null, $FrameworkServiceUrl = $null, $ServiceDirectory = $null, - $ServiceBin = $null + $ServiceBin = $null, + $UseDirectorSelfService = $null, + [bool]$SkipDirectorQuestion = $FALSE, + [string]$DirectorUrl, + [string]$SelfServiceAPIKey, + $OverrideDirectorVars = $null, + [hashtable]$ProvidedArgs = @{} ); [array]$InstallerArguments = @(); [array]$GlobalZoneConfig = @(); + if ($SkipDirectorQuestion -eq $FALSE) { + if ($null -eq $UseDirectorSelfService) { + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to use the Icinga Director Self-Service API?' -Default 'y').result -eq 1) { + $UseDirectorSelfService = $TRUE; + } else { + $UseDirectorSelfService = $FALSE; + $InstallerArguments += '-UseDirectorSelfService 0'; + } + } + if ($UseDirectorSelfService) { + $InstallerArguments += '-UseDirectorSelfService 1'; + Start-IcingaAgentDirectorWizard ` + -DirectorUrl $DirectorUrl ` + -SelfServiceAPIKey $SelfServiceAPIKey ` + -OverrideDirectorVars $OverrideDirectorVars ` + -InstallFrameworkService $InstallFrameworkService ` + -ServiceDirectory $ServiceDirectory ` + -ServiceBin $ServiceBin ` + -RunInstaller $RunInstaller; + return; + } + } + if ([string]::IsNullOrEmpty($Hostname) -And $AutoUseFQDN -eq $FALSE -And $AutoUseHostname -eq $FALSE) { if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to manually specify a hostname?' -Default 'n').result -eq 1) { if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to automatically fetch the hostname with its FQDN?' -Default 'y').result -eq 1) { @@ -261,27 +290,87 @@ function Start-IcingaAgentInstallWizard() $InstallerArguments += [string]::Format("-ServiceDirectory '{0}'", $result.ServiceDirectory); $InstallerArguments += [string]::Format("-ServiceBin '{0}'", $result.ServiceBin); $ServiceBin = $result.ServiceBin; + } else { + $InstallerArguments += "-InstallFrameworkService 0"; } } elseif ($InstallFrameworkService -eq $TRUE) { $result = Get-IcingaFrameworkServiceBinary -FrameworkServiceUrl $FrameworkServiceUrl -ServiceDirectory $ServiceDirectory; $ServiceBin = $result.ServiceBin; + } else { + $InstallerArguments += "-InstallFrameworkService 0"; } if ($InstallerArguments.Count -ne 0) { $InstallerArguments += "-RunInstaller"; Write-Host 'The wizard is complete. These are the configured settings:'; + + foreach ($entry in $ProvidedArgs.Keys) { + if ($entry -eq 'ProvidedArgs' -Or $entry -eq 'SkipDirectorQuestion') { + continue; + } + + [bool]$SkipArgument = $FALSE; + + if ($OverrideDirectorVars -eq $FALSE) { + switch ($entry) { + 'InstallFrameworkService' { break; }; + 'FrameworkServiceUrl' { break; }; + 'ServiceDirectory' { break; }; + 'ServiceBin' { break; }; + 'UseDirectorSelfService' { break; }; + 'DirectorUrl' { break; }; + 'SelfServiceAPIKey' { break; }; + 'OverrideDirectorVars' { break; }; + Default { + $SkipArgument = $TRUE; + break; + } + } + + if ($SkipArgument) { + continue; + } + } + + [bool]$KnownArgument = $FALSE; + foreach ($item in $InstallerArguments) { + if ($item -like "-$entry *" -Or $item -eq "-$entry") { + $KnownArgument = $TRUE; + break; + } + } + + if ($KnownArgument) { + continue; + } + + $Value = $ProvidedArgs[$entry]; + if ($Value -is [System.Object]) { + $Value = [string]::Join(',', $Value); + } + + if ($OverrideDirectorVars -eq $FALSE) { + #$ClearedArguments += [string]::Format("-{0} '{1}'", $entry, $Value); + #continue; + } + + $InstallerArguments += [string]::Format("-{0} '{1}'", $entry, $Value); + } + Write-Host ($InstallerArguments | Out-String); - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Is this configuration correct?' -Default 'y').result -eq 1) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to run the installer now? (Otherwise only the configration command will be printed)' -Default 'y').result -eq 1) { - Write-Host 'To execute your Icinga Agent installation based on your answers again on this or another machine, simply run this command:' + if (-Not $RunInstaller) { + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Is this configuration correct?' -Default 'y').result -eq 1) { + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to run the installer now? (Otherwise only the configration command will be printed)' -Default 'y').result -eq 1) { + Write-Host 'To execute your Icinga Agent installation based on your answers again on this or another machine, simply run this command:' - $RunInstaller = $TRUE; + $RunInstaller = $TRUE; + } else { + Write-Host 'To execute your Icinga Agent installation based on your answers, simply run this command:' + } } else { - Write-Host 'To execute your Icinga Agent installation based on your answers, simply run this command:' + Write-Host 'Please run the wizard again to modify your answers or modify the command below:' } - } else { - Write-Host 'Please run the wizard again to modify your answers or modify the command below:' } Get-IcingaAgentInstallCommand -InstallerArguments $InstallerArguments -PrintConsole; } @@ -289,8 +378,8 @@ function Start-IcingaAgentInstallWizard() if ($RunInstaller) { if ((Install-IcingaAgent -Version $AgentVersion -Source $PackageSource -AllowUpdates $AllowVersionChanges) -Or $Reconfigure) { Move-IcingaAgentDefaultConfig; - Set-IcingaAgentServiceUser -User $ServiceUser -Password $ServicePass; - Set-IcingaAgentServicePermission; + Set-IcingaAgentServiceUser -User $ServiceUser -Password $ServicePass | Out-Null; + Set-IcingaAgentServicePermission | Out-Null; Set-IcingaAcl "$Env:ProgramData\icinga2\etc"; Set-IcingaAcl "$Env:ProgramData\icinga2\var"; Set-IcingaAcl (Get-IcingaCacheDir);