From 7dce37717af07f123a80a4717313f2032fd940f5 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Thu, 26 Mar 2020 19:43:37 +0100 Subject: [PATCH] Adds generic PowerShell component installer and improved usability --- .../Get-IcingaPowerShellModuleArchive.psm1 | 48 +++++++++-- .../Install-IcingaFrameworkComponent.psm1 | 83 +++++++++++++++++++ .../Install-IcingaFrameworkPlugins.psm1 | 50 ++--------- 3 files changed, 128 insertions(+), 53 deletions(-) create mode 100644 lib/core/framework/Install-IcingaFrameworkComponent.psm1 diff --git a/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 b/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 index 4f6025d..36a8afc 100644 --- a/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 +++ b/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 @@ -3,23 +3,44 @@ function Get-IcingaPowerShellModuleArchive() param( [string]$DownloadUrl = '', [string]$ModuleName = '', - [string]$Repository = '' + [string]$Repository = '', + [string]$GitHubUser = 'Icinga', + [bool]$Stable = $FALSE, + [bool]$Snapshot = $FALSE, + [bool]$DryRun = $FALSE ); $ProgressPreference = "SilentlyContinue"; $Tag = 'master'; + [bool]$SkipRepo = $FALSE; + + if ($Stable -Or $Snapshot) { + $SkipRepo = $TRUE; + } + # Fix TLS errors while connecting to GitHub with old PowerShell versions [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11"; if ([string]::IsNullOrEmpty($DownloadUrl)) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you provide a custom repository for "{0}"?', $ModuleName)) -Default 'n').result -eq 1) { - $branch = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Which version to you want to install? (snapshot/stable)' -Default 'v' -DefaultInput 'stable').answer - if ($branch.ToLower() -eq 'snapshot') { - $DownloadUrl = [string]::Format('https://github.com/Icinga/{0}/archive/master.zip', $Repository); + if ($SkipRepo -Or (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you provide a custom repository for "{0}"?', $ModuleName)) -Default 'n').result -eq 1) { + if ($Stable -eq $FALSE -And $Snapshot -eq $FALSE) { + $branch = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Which version to you want to install? (snapshot/stable)' -Default 'v' -DefaultInput 'stable').answer; + } elseif ($Stable) { + $branch = 'stable'; } else { - $LatestRelease = (Invoke-WebRequest -Uri ([string]::Format('https://github.com/Icinga/{0}/releases/latest', $Repository)) -UseBasicParsing).BaseResponse.ResponseUri.AbsoluteUri; - $DownloadUrl = $LatestRelease.Replace('/releases/tag/', '/archive/'); - $Tag = $DownloadUrl.Split('/')[-1]; + $branch = 'snapshot' + } + if ($branch.ToLower() -eq 'snapshot') { + $DownloadUrl = [string]::Format('https://github.com/{0}/{1}/archive/master.zip', $GitHubUser, $Repository); + } else { + try { + $LatestRelease = (Invoke-WebRequest -Uri ([string]::Format('https://github.com/{0}/{1}/releases/latest', $GitHubUser, $Repository)) -UseBasicParsing).BaseResponse.ResponseUri.AbsoluteUri; + $DownloadUrl = $LatestRelease.Replace('/releases/tag/', '/archive/'); + $Tag = $DownloadUrl.Split('/')[-1]; + } catch { + Write-Host 'Failed to fetch latest release from GitHub. Either the module or the GitHub account do not exist'; + } + $DownloadUrl = [string]::Format('{0}/{1}.zip', $DownloadUrl, $Tag); $CurrentVersion = Get-IcingaPowerShellModuleVersion $Repository; @@ -41,6 +62,17 @@ function Get-IcingaPowerShellModuleArchive() } } + if ($DryRun) { + return @{ + 'DownloadUrl' = $DownloadUrl; + 'Version' = $Tag; + 'Directory' = ''; + 'Archive' = ''; + 'ModuleRoot' = (Get-IcingaFrameworkRootPath); + 'Installed' = $FALSE; + }; + } + try { $DownloadDirectory = New-IcingaTemporaryDirectory; $DownloadDestination = (Join-Path -Path $DownloadDirectory -ChildPath ([string]::Format('{0}.zip', $Repository))); diff --git a/lib/core/framework/Install-IcingaFrameworkComponent.psm1 b/lib/core/framework/Install-IcingaFrameworkComponent.psm1 new file mode 100644 index 0000000..2a5b0c6 --- /dev/null +++ b/lib/core/framework/Install-IcingaFrameworkComponent.psm1 @@ -0,0 +1,83 @@ +function Install-IcingaFrameworkComponent() +{ + param( + [string]$Name, + [string]$GitHubUser = 'Icinga', + [string]$Url, + [switch]$Stable = $FALSE, + [switch]$Snapshot = $FALSE, + [switch]$DryRun = $FALSE + ); + + if ([string]::IsNullOrEmpty($Name)) { + throw 'Please specify a component name to install from a GitHub/Local space'; + } + + $TextInfo = (Get-Culture).TextInfo; + $ComponentName = $TextInfo.ToTitleCase($Name); + $RepositoryName = [string]::Format('icinga-powershell-{0}', $Name); + $Archive = Get-IcingaPowerShellModuleArchive ` + -DownloadUrl $Url ` + -GitHubUser $GitHubUser ` + -ModuleName ( + [string]::Format( + 'Icinga Component {0}', $ComponentName + ) + ) ` + -Repository $RepositoryName ` + -Stable $Stable ` + -Snapshot $Snapshot ` + -DryRun $DryRun; + + if ($Archive.Installed -eq $FALSE -Or $DryRun) { + return @{ + 'RepoUrl' = $Archive.DownloadUrl + }; + } + + Write-Host ([string]::Format('Installing module into "{0}"', ($Archive.Directory))); + Expand-IcingaZipArchive -Path $Archive.Archive -Destination $Archive.Directory | Out-Null; + + $FolderContent = Get-ChildItem -Path $Archive.Directory; + $ModuleContent = $Archive.Directory; + + foreach ($entry in $FolderContent) { + if ($entry -like ([string]::Format('{0}*', $RepositoryName))) { + $ModuleContent = Join-Path -Path $ModuleContent -ChildPath $entry; + break; + } + } + + Write-Host ([string]::Format('Using content of folder "{0}" for updates', $ModuleContent)); + + $PluginDirectory = (Join-Path -Path $Archive.ModuleRoot -ChildPath $RepositoryName); + + if ((Test-Path $PluginDirectory) -eq $FALSE) { + Write-Host ([string]::Format('{0} Module Directory "{1}" is not present. Creating Directory', $ComponentName, $PluginDirectory)); + New-Item -Path $PluginDirectory -ItemType Directory | Out-Null; + } + + Write-Host ([string]::Format('Copying files to {0}', $ComponentName)); + Copy-ItemSecure -Path (Join-Path -Path $ModuleContent -ChildPath '/*') -Destination $PluginDirectory -Recurse -Force | Out-Null; + + Write-Host 'Cleaning temporary content'; + Start-Sleep -Seconds 1; + Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null; + + Unblock-IcingaPowerShellFiles -Path $PluginDirectory; + + # In case the plugins are not installed before, load the framework again to + # include the plugins + Use-Icinga; + + # Unload the module if it was loaded before + Remove-Module $RepositoryName -Force -ErrorAction SilentlyContinue; + # Now import the module + Import-Module $RepositoryName; + + Write-Host ([string]::Format('Icinga component {0} update has been completed. Please start a new PowerShell to apply it', $ComponentName)); + + return @{ + 'RepoUrl' = $Archive.DownloadUrl + }; +} diff --git a/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 b/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 index 7d11b40..124d0ea 100644 --- a/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 +++ b/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 @@ -4,52 +4,12 @@ function Install-IcingaFrameworkPlugins() [string]$PluginsUrl ); - $RepositoryName = 'icinga-powershell-plugins'; - $Archive = Get-IcingaPowerShellModuleArchive -DownloadUrl $PluginsUrl -ModuleName 'Icinga Plugins' -Repository $RepositoryName; - - if ($Archive.Installed -eq $FALSE) { - return @{ - 'PluginUrl' = $Archive.DownloadUrl - }; - } - - Write-Host ([string]::Format('Installing module into "{0}"', ($Archive.Directory))); - Expand-IcingaZipArchive -Path $Archive.Archive -Destination $Archive.Directory | Out-Null; - - $FolderContent = Get-ChildItem -Path $Archive.Directory; - $ModuleContent = $Archive.Directory; - - foreach ($entry in $FolderContent) { - if ($entry -like ([string]::Format('{0}*', $RepositoryName))) { - $ModuleContent = Join-Path -Path $ModuleContent -ChildPath $entry; - break; - } - } - - Write-Host ([string]::Format('Using content of folder "{0}" for updates', $ModuleContent)); - - $PluginDirectory = (Join-Path -Path $Archive.ModuleRoot -ChildPath $RepositoryName); - - if ((Test-Path $PluginDirectory) -eq $FALSE) { - Write-Host ([string]::Format('Plugin Module Directory "{0}" is not present. Creating Directory', $PluginDirectory)); - New-Item -Path $PluginDirectory -ItemType Directory | Out-Null; - } - - Write-Host 'Copying files to plugins'; - Copy-ItemSecure -Path (Join-Path -Path $ModuleContent -ChildPath '/*') -Destination $PluginDirectory -Recurse -Force | Out-Null; - - Write-Host 'Cleaning temporary content'; - Start-Sleep -Seconds 1; - Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null; - - Unblock-IcingaPowerShellFiles -Path $PluginDirectory; - # In case the plugins are not installed before, load the framework again to - # include the plugins - Use-Icinga; - - Write-Host 'Icinga Plugin update has been completed'; + [Hashtable]$Result = Install-IcingaFrameworkComponent ` + -Name 'plugins' ` + -GitHubUser 'Icinga' ` + -Url $PluginsUrl; return @{ - 'PluginUrl' = $Archive.DownloadUrl + 'PluginUrl' = $Result.RepoUrl; }; }