Skip to content

Commit

Permalink
(#86) Adds OfflineInstallPreparation Script
Browse files Browse the repository at this point in the history
This commit introduces a script to download all the prerequisites for the other scripts, allowing for airgapped deployments.

This requires a few additional changes, including a large refactor of the Start-C4bSetup script.
  • Loading branch information
JPRuskin committed Apr 19, 2024
1 parent c6cb689 commit ae54cf4
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 152 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.nupkg
*.zip
/scripts/ChocolateyInstall.ps1
Chocolatey.License.xml
*/bcrypt.net.0.1.0/*
146 changes: 146 additions & 0 deletions OfflineInstallPreparation.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<#
.Synopsis
Prepares the repository for an offline deployment.
.Description
These scripts can be run from a network without access to the internet,
but it needs to prepare packages to be run offline.
This script downloads and internalizes packages for such usage.
.Notes
This must be run on a Windows system with access to the internet because
it uses Chocolatey for Business' Package Internalizer.
.Notes
Instead of using this script, you can internalize all required packages manually,
zip them, and drop them in the files directory as shown below.
.Example
.\OfflineInstallPreparation.ps1 -LicensePath C:\ProgramData\chocolatey\license\chocolatey.license.xml
#>
[CmdletBinding()]
param(
[ValidateScript({
if (-not (Test-Path (Convert-Path $_))) {
throw "License file does not exist at '$($_)'. Please provide a valid -LicensePath"
}
try {
[xml]$License = Get-Content $_
$Expiry = Get-Date $License.license.expiration
if (-not $Expiry -or $Expiry -lt (Get-Date)) {throw}
} catch {
throw "License '$($_)' is not valid.$(if ($Expiry) {" It expired at '$($Expiry)'."})"
}
$true
})]
[string]$LicensePath = "C:\ProgramData\chocolatey\license\chocolatey.license.xml",

[string]$WorkingDirectory = $(Join-Path $env:Temp "choco-offline")
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$LicensePath = Convert-Path $LicensePath

. $PSScriptRoot\scripts\Get-Helpers.ps1

$ChocoInstallScript = Join-Path $PSScriptRoot "scripts\ChocolateyInstall.ps1"
if (-not (Test-Path $ChocoInstallScript)) {
Invoke-WebRequest -Uri 'https://chocolatey.org/install.ps1' -OutFile $ChocoInstallScript
}

$Signature = Get-AuthenticodeSignature -FilePath $ChocoInstallScript

if ($Signature.Status -eq 'Valid' -and $Signature.SignerCertificate.Subject -eq 'CN="Chocolatey Software, Inc.", O="Chocolatey Software, Inc.", L=Topeka, S=Kansas, C=US') {
if (-not (Get-Command choco.exe)) {
if (Test-Path $PSScriptRoot\files\chocolatey.*.nupkg) {
$env:ChocolateyDownloadUrl = (Convert-Path $PSScriptRoot\files\chocolatey.*.nupkg)[0]
}
& $ChocoInstallScript
}
} else {
Write-Error "ChocolateyInstall.ps1 script signature is not valid. Please investigate." -ErrorAction Stop
}

# Initialize environment, ensure Chocolatey For Business, etc.
$Licensed = ($($(choco.exe)[0] -match "^Chocolatey (?<Version>\S+)\s*(?<LicenseType>Business)?$") -and $Matches.LicenseType)
$InstalledLicensePath = "$env:ChocolateyInstall\license\chocolatey.license.xml"
if (-not $Licensed) {
if (-not (Test-Path $InstalledLicensePath)) {
if (-not (Test-Path $env:ChocolateyInstall\license)) {
$null = New-Item $env:ChocolateyInstall\license -ItemType Directory
}
Copy-Item $LicensePath $InstalledLicensePath -Force
}
$ExtensionSource = if (Test-Path $PSScriptRoot\files\chocolatey.extension.*.nupkg) {
Convert-Path $PSScriptRoot\files\
} else {
'https://licensedpackages.chocolatey.org/api/v2/'
}
choco install chocolatey.extension --source $ExtensionSource --params="'/NoContextMenu'" --confirm
}

# Download each set of packages to the output directories
$PackageWorkingDirectory = Join-Path $WorkingDirectory "Packages"
if (-not (Test-Path $PackageWorkingDirectory)) {
$null = New-Item -Path $PackageWorkingDirectory -ItemType Directory -Force
}
foreach ($Package in (Get-Content $PSScriptRoot\files\chocolatey.json | ConvertFrom-Json).packages) {
$ChocoArgs = @(
"download", "$($Package.Name)"
"--output-directory", $PackageWorkingDirectory
)
$ChocoArgs += switch ($Package.psobject.properties.name) {
"Version" { "--version=$($Package.Version)" }
"Args" { $Package.Args }
}
if ($Package.Internalize -or $Package.PSObject.Properties.Name -notcontains "Internalize") {
$ChocoArgs += "--internalize" # Default to internalizing
}

try {
if (-not (Test-Path "$($PackageWorkingDirectory)\$($Package.Name)*.nupkg") -and -not (Test-Path "$PSScriptRoot\files\$($Package.Name)*.nupkg")) {
Write-Host "Downloading '$($Package.Name)'"

while ((Get-ChildItem $PackageWorkingDirectory -Filter *.nupkg).Where{$_.CreationTime -gt (Get-Date).AddMinutes(-2)}.Count -gt 5) {
Write-Verbose "Slowing down for a minute, in order to not trigger rate-limiting..."
Start-Sleep -Seconds 5
}

choco @ChocoArgs
}
} catch {
throw $_
}
}
Move-Item -Path $PackageWorkingDirectory\*.nupkg -Destination $PSScriptRoot\files\

# Jenkins Plugins
$PluginsWorkingDirectory = Join-Path $WorkingDirectory "JenkinsPlugins"
if (-not (Test-Path $PluginsWorkingDirectory)) {
$null = New-Item -Path $PluginsWorkingDirectory -ItemType Directory -Force
}
if (Test-Path $PSScriptRoot\files\JenkinsPlugins.zip) {
Expand-Archive -Path $PSScriptRoot\files\JenkinsPlugins.zip -DestinationPath $PluginsWorkingDirectory -Force
}
$ProgressPreference = "Ignore"
foreach ($Plugin in (Get-Content $PSScriptRoot\files\jenkins.json | ConvertFrom-Json).plugins) {
$RestArgs = @{
Uri = "https://updates.jenkins-ci.org/latest/$($Plugin.Name).hpi"
OutFile = Join-Path $PluginsWorkingDirectory "$($Plugin.Name).hpi"
}
if ($Plugin.Version -and $Plugin.Version -ne 'latest') {
$RestArgs.Uri = "https://updates.jenkins-ci.org/download/plugins/$($Plugin.Name)/$($Plugin.Version)/$($Plugin.Name).hpi"
}
if (-not (Test-Path $RestArgs.OutFile)) {
Invoke-WebRequest @RestArgs -UseBasicParsing
}
}
Compress-Archive -Path $PluginsWorkingDirectory\* -Destination $PSScriptRoot\files\JenkinsPlugins.zip -Force

# BCryptDll
$null = Get-BcryptDll

# License
if ($LicensePath -ne "$PSScriptRoot\files\chocolatey.license.xml") {
Copy-Item -Path (Convert-Path $LicensePath) -Destination $PSScriptRoot\files\chocolatey.license.xml
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Below are the minimum requirements for setting up your C4B server via this guide

> :warning:**DISCLAIMER**: This guide utilizes code from a GitHub repository, namely: [choco-quickstart-scripts](https://github.com/chocolatey/choco-quickstart-scripts). Though we explain what each script does in drop-down boxes, please do your due diligence to review this code and ensure it meets your Organizational requirements.
> :memo:**Offline Install**: If your C4B server does not have unrestricted access to the internet, you can download the `choco-quickstart-scripts` repository to a Windows machine that is connected to the internet and run `OfflineInstallPreparation.ps1`. This will use Chocolatey to save all of the required assets into the repository folder, which can then be transferred to the target C4B server.
### Step 1: Begin C4B Setup

> :exclamation:**[IMPORTANT]** All commands should be run from an **elevated** PowerShell window (and **not ISE**), by opening your PowerShell console with the `Run as Administrator` option.
Expand Down
14 changes: 7 additions & 7 deletions Start-C4bCcmSetup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ process {
# Dot-source helper functions
. .\scripts\Get-Helpers.ps1

# DB Setup
$PkgSrc = "$env:SystemDrive\choco-setup\packages"
$Ccr = 'https://community.chocolatey.org/api/v2/'
$Packages = (Get-Content $PSScriptRoot\files\chocolatey.json | ConvertFrom-Json).packages

$chocoArgs = @('upgrade', 'sql-server-express', 'sql-server-management-studio', '-y', "--source='$Ccr'", '--no-progress')
# DB Setup
Write-Host "Installing SQL Server Express"
$chocoArgs = @('upgrade', 'sql-server-express', '-y', '--no-progress')
& choco @chocoArgs

# https://docs.microsoft.com/en-us/sql/tools/configuration-manager/tcp-ip-properties-ip-addresses-tab
Expand Down Expand Up @@ -104,13 +104,13 @@ process {
$chocoArgs = @('install', 'IIS-ApplicationInit', "--source='windowsfeatures'" ,'--no-progress', '-y')
& choco @chocoArgs

$chocoArgs = @('install', 'dotnet-aspnetcoremodule-v2', "--version='16.0.24052'", "--source='$Ccr'", '--no-progress', '--pin', '--pin-reason="Latest version compatible with chocolatey-management-web V 0.12.0"', '-y')
$chocoArgs = @('install', 'dotnet-aspnetcoremodule-v2', "--version='$($Packages.Where{$_.Name -eq 'dotnet-aspnetcoremodule-v2'}.Version)'", '--no-progress', '--pin', '--pin-reason="Latest version compatible with chocolatey-management-web V 0.12.0"', '-y')
& choco @chocoArgs

$chocoArgs = @('install', 'dotnet-6.0-runtime', '--version=6.0.28', "--source='$Ccr'", '--no-progress', '--pin', '--pin-reason="Latest version compatible with chocolatey-management-database V 0.12.0"', '-y')
$chocoArgs = @('install', 'dotnet-6.0-runtime', "--version=$($Packages.Where{$_.Name -eq 'dotnet-6.0-runtime'}.Version)", '--no-progress', '--pin', '--pin-reason="Latest version compatible with chocolatey-management-database V 0.12.0"', '-y')
& choco @chocoArgs

$chocoArgs = @('install', 'dotnet-6.0-aspnetruntime', '--version=6.0.28', "--source='$Ccr'", '--no-progress', '--pin', '--pin-reason="Latest version compatible with chocolatey-management-database V 0.12.0"', '-y')
$chocoArgs = @('install', 'dotnet-6.0-aspnetruntime', "--version=$($Packages.Where{$_.Name -eq 'dotnet-6.0-aspnetruntime'}.Version)", '--no-progress', '--pin', '--pin-reason="Latest version compatible with chocolatey-management-database V 0.12.0"', '-y')
& choco @chocoArgs

# Install CCM DB package using Local SQL Express
Expand Down
2 changes: 1 addition & 1 deletion Start-C4bJenkinsSetup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ process {
# Disabling inital setup prompts
$JenkinsHome = "C:\ProgramData\Jenkins\.jenkins"

$JenkinsVersion = (choco list jenkins --exact --limit-output).Split('|')[1]
$JenkinsVersion = (choco.exe list jenkins --exact --limit-output).Split('|')[1]
$JenkinsVersion | Out-File -FilePath $JenkinsHome\jenkins.install.UpgradeWizard.state -Encoding utf8
$JenkinsVersion | Out-File -FilePath $JenkinsHome\jenkins.install.InstallUtil.lastExecVersion -Encoding utf8

Expand Down
9 changes: 4 additions & 5 deletions Start-C4bNexusSetup.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ process {
Connect-NexusServer -Hostname localhost -Credential $Credential

#Drain default repositories
Get-NexusRepository | Remove-NexusRepository -Force
$null = Get-NexusRepository | Where-Object Name -NotLike "choco*" | Remove-NexusRepository -Force

#Enable NuGet Auth Realm
Enable-NexusRealm -Realm 'NuGet API-Key Realm'
Expand All @@ -63,10 +63,9 @@ process {
$NuGetApiKey = (Get-NexusNuGetApiKey -Credential $Credential).apikey

# Push all packages from previous steps to NuGet repo
Get-ChildItem -Path "$env:SystemDrive\choco-setup\packages" -Filter *.nupkg |
ForEach-Object {
choco push $_.FullName --source "$((Get-NexusRepository -Name 'ChocolateyInternal').url)/index.json" --apikey $NugetApiKey --force
}
Get-ChildItem -Path "$env:SystemDrive\choco-setup\files\files" -Filter *.nupkg | ForEach-Object {
choco push $_.FullName --source "$((Get-NexusRepository -Name 'ChocolateyInternal').url)/index.json" --apikey $NugetApiKey --force
}

# Temporary workaround to reset the NuGet v3 cache, such that it doesn't capture localhost as the FQDN
Remove-NexusRepositoryFolder -RepositoryName ChocolateyInternal -Name v3
Expand Down
Loading

0 comments on commit ae54cf4

Please sign in to comment.