348 lines
17 KiB
PowerShell
348 lines
17 KiB
PowerShell
|
function Install-SDKRelease {
|
||
|
<#
|
||
|
.SYNOPSIS
|
||
|
Install a release of SDK with some set of feature packages, where they exist
|
||
|
#>
|
||
|
[CmdletBinding(DefaultParameterSetName = 'VersionAndFeatures')]
|
||
|
param (
|
||
|
[Parameter(ParameterSetName = 'VersionAndFeatures')]
|
||
|
[ArgumentCompleter({
|
||
|
$manifestFolder = (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Manifests")
|
||
|
if (!(Test-Path -Path $manifestFolder)) {
|
||
|
$manifestFolder = (Join-Path -Path $PSScriptRoot -ChildPath "Manifests")
|
||
|
}
|
||
|
$files = Get-ChildItem -Path (Join-Path $manifestFolder "*.json")
|
||
|
$fileNames = $files | Foreach-Object { return ([System.IO.Path]::GetFileNameWithoutExtension($_) -split '\.')[0..1] -join '.' } | Sort-Object | Get-Unique
|
||
|
return $filenames | Foreach-Object { $_ }
|
||
|
})][string]$Version = ((Get-SavedInstallVersions) -split "`n")[0],
|
||
|
|
||
|
[Parameter(ParameterSetName = 'VersionAndFeatures')]
|
||
|
[ArgumentCompleter({
|
||
|
$manifestFolder = (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Manifests")
|
||
|
if (!(Test-Path -Path $manifestFolder)) {
|
||
|
$manifestFolder = (Join-Path -Path $PSScriptRoot -ChildPath "Manifests")
|
||
|
}
|
||
|
$files = Get-ChildItem -Path (Join-Path $manifestFolder "*.json")
|
||
|
$fileNames = $files | Foreach-Object { return ([System.IO.Path]::GetFileNameWithoutExtension($_) -split '\.')[2] } | Sort-Object | Get-Unique
|
||
|
return $filenames | Foreach-Object { $_ }
|
||
|
})][string[]]$Features = ((Get-SavedInstallVersions) -split "`n")[1],
|
||
|
|
||
|
[Parameter(ParameterSetName = 'Latest')]
|
||
|
[switch]$Latest
|
||
|
)
|
||
|
|
||
|
$logLead = Get-LogLeadName
|
||
|
$tiers = 0..4
|
||
|
|
||
|
if ($null -ne (Get-Command -Name Set-EnvironmentVariable -ErrorAction Ignore)) {
|
||
|
Set-AlkamiConfiguration -Configuration StartServicesOnInstall -Off
|
||
|
}
|
||
|
|
||
|
$transcriptFilename = "Alkami.SDK.InstallRelease.$(Get-Date -Format "yyyyMMddhhmm").txt"
|
||
|
$transcriptPath = Join-Path -Path (Get-OrbLogsPath) -ChildPath $transcriptFilename
|
||
|
Start-Transcript -Path $transcriptPath
|
||
|
|
||
|
# Ensure hosts file entries exist for later
|
||
|
Add-OrbHostEntries
|
||
|
|
||
|
# Install/Upgrade Alkami.SDKRelease.Manifests package
|
||
|
$chocoSplat = @(
|
||
|
"upgrade"
|
||
|
"Alkami.SDKRelease.Manifests"
|
||
|
"-i"
|
||
|
"-y"
|
||
|
"--no-progress"
|
||
|
"--limit-output"
|
||
|
)
|
||
|
Invoke-CallOperatorWithPathAndParameters -Path Choco -Arguments $chocoSplat *>&1 | Out-Default -Transcript | Out-Null
|
||
|
|
||
|
try {
|
||
|
$allPackages, $removePackages = Get-FeatureSets
|
||
|
Write-Verbose (ConvertTo-Json $allPackages)
|
||
|
$packagesToUpgrade, $newPackagesToInstall, $packagesToRemove = Get-LocalPackages -Packages $allPackages
|
||
|
|
||
|
Write-Host "$logLead : Found [$($packagesToUpgrade.Count)] existing packages to upgrade"
|
||
|
foreach ($packageToUpgrade in $packagesToUpgrade) {
|
||
|
"Upgrade $($packageToUpgrade.Tier) -> $($packageToUpgrade.id) $($packageToUpgrade.Version)" | Out-Default -Transcript | Out-Null
|
||
|
}
|
||
|
|
||
|
Write-Host "$logLead : Found [$($newPackagesToInstall.Count)] new packages to install"
|
||
|
foreach ($packageToInstall in $newPackagesToInstall) {
|
||
|
"Install $($packageToInstall.Tier) -> $($packageToInstall.id) $($packageToInstall)." | Out-Default -Transcript | Out-Null
|
||
|
}
|
||
|
|
||
|
if ($packagesToRemove.Count -gt 0) {
|
||
|
Write-Host "$logLead : Found [$($packagesToRemove.Count)] existing packages to remove"
|
||
|
foreach ($package in $packagesToRemove) {
|
||
|
"Remove $package" | Out-Default -Transcript | Out-Null
|
||
|
}
|
||
|
} else {
|
||
|
Write-Host "No packages marked for deletion"
|
||
|
}
|
||
|
|
||
|
$packagesToInstall = @{}
|
||
|
|
||
|
foreach ($tier in $tiers) {
|
||
|
#Write-host "$logLead : Tier $tier Installs"
|
||
|
$installs = @()
|
||
|
|
||
|
foreach ($package in $packagesToUpgrade) {
|
||
|
if ($package.Tier -eq $tier) {
|
||
|
$installs += $package
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach ($package in $newPackagesToInstall) {
|
||
|
if ($package.Tier -eq $tier) {
|
||
|
$installs += $package
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$packagesToInstall[$tier] = $installs
|
||
|
}
|
||
|
|
||
|
Write-Host "$logLead : Setting Alkami services recovery to take no action"
|
||
|
Set-SDKServiceRecovery -ServiceName 'All' -Action 'TakeNoAction'
|
||
|
|
||
|
Write-Host "$logLead : Stopping IIS and only services to be upgraded"
|
||
|
|
||
|
# Only stop services we are going to be installing so we do as little interruption as possible
|
||
|
# Only has to be packages that are being upgraded, the ones being installed don't affect anything
|
||
|
foreach ($package in $packagesToUpgrade) {
|
||
|
$serviceInfo = (Get-ServiceInfoByCIMFragment -Fragment $package.Id)
|
||
|
if ($null -eq $serviceInfo) {
|
||
|
# This isn't a service, so we don't care
|
||
|
continue
|
||
|
}
|
||
|
$serviceName = $serviceInfo.Name
|
||
|
if (![string]::IsNullOrWhiteSpace($serviceName)) {
|
||
|
#Stop-AlkamiService -ServiceName $serviceName
|
||
|
#Write-Host "Package Id: " $package.Id
|
||
|
#Write-Host "ServiceName: " $serviceName
|
||
|
$service = Get-Service -Name $serviceName | Select-Object -First 1
|
||
|
$processes = @(Get-ProcessFromService $service)
|
||
|
if ($processes.Count -ne 0) {
|
||
|
$process = ($processes | Select-Object -First 1)
|
||
|
"Stopping Process: $($process.Name) | $($process.id)" | Out-Default -Transcript | Out-Null
|
||
|
#Stop-ProcessIfFound $process.Name
|
||
|
Stop-Process $process.Id -force | Out-Null
|
||
|
} else {
|
||
|
"No running processes found for $($service.Name)" | Out-Default -Transcript | Out-Null
|
||
|
}
|
||
|
}
|
||
|
if ($null -eq $package.ComponentType) {
|
||
|
# because of legacy installers, remove this package's service registration to allow for downgrade experiences
|
||
|
Invoke-SCExe @('delete', $serviceName)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($packagesToRemove.Count -gt 0) {
|
||
|
# remove packages we are uninstalling
|
||
|
foreach ($package in $packagesToRemove) {
|
||
|
Write-Verbose "Package to remove: $package"
|
||
|
$serviceName = (Get-ServiceInfoByCIMFragment -Fragment $package).Name
|
||
|
if (![string]::IsNullOrWhiteSpace($serviceName)) {
|
||
|
Stop-AlkamiService -ServiceName $serviceName
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Stop-IISOnly
|
||
|
|
||
|
#Stop Radium if installed
|
||
|
$serviceName = Get-ServiceInfoByCIMFragment -QueryFragment (Join-Path (Get-OrbPath) 'Radium')
|
||
|
if (-not [string]::IsNullOrWhiteSpace($serviceName.Name)) {
|
||
|
Stop-AlkamiService -ServiceName $serviceName.Name
|
||
|
}
|
||
|
|
||
|
#Stop Nag if installed
|
||
|
$serviceName = Get-ServiceInfoByCIMFragment -QueryFragment (Join-Path (Get-OrbPath) 'Nag')
|
||
|
if (-not [string]::IsNullOrWhiteSpace($serviceName.Name)) {
|
||
|
Stop-AlkamiService -ServiceName $serviceName.Name
|
||
|
}
|
||
|
# We are installing ORB, so we are always going to start it back up
|
||
|
$startIIS = $true
|
||
|
|
||
|
if ($packagesToRemove.Count -gt 0) {
|
||
|
Write-Host "$logLead : Removing packages now"
|
||
|
# remove packages we are uninstalling
|
||
|
foreach ($package in $packagesToRemove) {
|
||
|
"Completely removed package [$package]" | Out-Default -Transcript | Out-Null
|
||
|
choco uninstall $package -n -f -i
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$chocoPath = Get-ChocolateyInstallPath
|
||
|
|
||
|
Write-Host "$logLead : Installing packages now"
|
||
|
|
||
|
"Dumping `$newPackagesToInstall to Transcript" | Out-Default -Transcript | Out-Null
|
||
|
(ConvertTo-Json $newPackagesToInstall) | Out-Default -Transcript | Out-Null
|
||
|
"Dumping `$packagesToUpgrade to Transcript" | Out-Default -Transcript | Out-Null
|
||
|
(ConvertTo-Json $packagesToUpgrade) | Out-Default -Transcript | Out-Null
|
||
|
"Dumping `$packagesToRemove to Transcript" | Out-Default -Transcript | Out-Null
|
||
|
(ConvertTo-Json $packagesToRemove) | Out-Default -Transcript | Out-Null
|
||
|
"Dumping `$tiers to Transcript" | Out-Default -Transcript | Out-Null
|
||
|
(ConvertTo-Json $tiers) | Out-Default -Transcript | Out-Null
|
||
|
|
||
|
|
||
|
foreach ($tier in $tiers) {
|
||
|
if ($tier -eq 1) {
|
||
|
Write-Host "Force removing AlkamiModules that just got installed"
|
||
|
Get-Module Alkami* | Remove-Module -Force
|
||
|
Import-Module Alkami.PowerShell.Database # ensure that database runners can get run, or show us an error message
|
||
|
#$tiers[0].Where({$_.ComponentType -eq 'SREModule' -and $_.Id -notmatch "\.SRE\."}).Id | Foreach-Object { Import-Module $_ }
|
||
|
|
||
|
Write-Host "$logLead : Starting Redis"
|
||
|
Start-Service -Name "redis-master18620"
|
||
|
Start-Service -Name "redis-slave18621"
|
||
|
Write-Warning "$logLead : If the following two commands (Import-Module WebAdministration, Load-Assembly) fail and stop the installation, please close and reopen your powershell session and try again."
|
||
|
Write-Warning "$logLead : Alkami developers occasionally encounter this on new machine installs, and are working to resolve the issue."
|
||
|
|
||
|
Import-Module WebAdministration
|
||
|
try {
|
||
|
Add-Type -AssemblyName "Microsoft.Web.Administration, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||
|
}
|
||
|
catch {
|
||
|
# Just in case we have IIS Express and IIS loaded (dev machines)
|
||
|
[System.Reflection.Assembly]::LoadFile("C:\Windows\system32\inetsrv\Microsoft.Web.Administration.dll")
|
||
|
}
|
||
|
Assert-PlatformDeveloperKitComponentsInstalled
|
||
|
|
||
|
# Before we install anything after the basics, we need to initialize the databases if they haven't been. We should have already delivered the database component.
|
||
|
if ($null -eq (Get-EnvironmentVariable -Name "Alkami_SDK_Initialization_DatabaseStandup")) {
|
||
|
Write-Host "Ensure default AlkamiDatabases are available and have been configured"
|
||
|
$connectionString = Get-MasterConnectionString
|
||
|
# names are hard-coded especially
|
||
|
Initialize-AlkamiDatabase $connectionString 'AlkamiMaster'
|
||
|
Initialize-AlkamiDatabase $connectionString 'DeveloperDynamic'
|
||
|
# TODO: Incredibly brittle. Will need to be refactored
|
||
|
# Easiest refactor is to restore a masterdb in the initialize functions above
|
||
|
C:\programdata\Alkami\Alkami\MachineSetup\DatabaseCore\Migrate.exe -a C:\programdata\Alkami\Alkami\MachineSetup\DatabaseCore\Alkami.Tools.MasterDatabaseMigration.dll --connectionString $connectionString -provider SqlServer2008 -tag alkamimaster -context sdk
|
||
|
Write-Host "Setting tenant"
|
||
|
Import-DeveloperDynamicTenant $connectionString
|
||
|
Set-EnvironmentVariable -Name "Alkami_SDK_Initialization_DatabaseStandup" -Value (Get-Date) -StoreName Machine
|
||
|
}
|
||
|
|
||
|
# Before we install anything after the basics, we need to initialize the websites and webapps if they haven't been. We should have already delivered the required orb file components.
|
||
|
Write-Host "$logLead : Creating web sites and applications now"
|
||
|
Install-SDKIISComponents
|
||
|
|
||
|
# You have to create the sites before you can run the migrations because of how the database users get setup in the database
|
||
|
# It's a pain, I know, but yay out of order operations ...
|
||
|
Write-host "$logLead : Running migrations"
|
||
|
Invoke-SDKAlkamiMigrations
|
||
|
}
|
||
|
|
||
|
$packages = $packagesToInstall[$tier]
|
||
|
if (Test-IsCollectionNullOrEmpty $packages) {
|
||
|
Write-Host "$logLead : PackagesToInstall was empty"
|
||
|
continue
|
||
|
} else {
|
||
|
Write-Host "$logLead : Installing Tier $tier packages with count $($packages.count)"
|
||
|
}
|
||
|
$potentialServicePaths = @()
|
||
|
$parallelInstall = @()
|
||
|
# We have to check $allPackages because they may already be installed
|
||
|
foreach ($package in $packages) {
|
||
|
$packageFolder = Join-Path -Path (Join-Path -Path $chocoPath -ChildPath "lib") -ChildPath $package.Id
|
||
|
$potentialServicePaths += $packageFolder
|
||
|
}
|
||
|
($potentialServicePaths -Join "`n") | Out-Default -Transcript | Out-Null
|
||
|
|
||
|
foreach ($package in $packages) {
|
||
|
$packageFolder = Join-Path -Path (Join-Path -Path $chocoPath -ChildPath "lib") -ChildPath $package.Id
|
||
|
$runScripts = "-y"
|
||
|
if ($package.HasManifest -and $null -ne $package.ComponentType) {
|
||
|
$runScripts = "--skip-scripts"
|
||
|
$parallelInstall += $packageFolder
|
||
|
}
|
||
|
|
||
|
$runQuietly = "--no-progress"
|
||
|
$sayVeryLittle = "--limit-output"
|
||
|
$ignoreDependencies = "-i"
|
||
|
if ($package.Id -in @("redis-64")) {
|
||
|
$ignoreDependencies = " "
|
||
|
}
|
||
|
|
||
|
$version = "$($package.Version)"
|
||
|
$packageVersion = "[$($package.Version)]"
|
||
|
|
||
|
$chocoSplat = @(
|
||
|
"upgrade"
|
||
|
$package.Id
|
||
|
$ignoreDependencies
|
||
|
$runScripts
|
||
|
$runQuietly
|
||
|
$sayVeryLittle
|
||
|
)
|
||
|
|
||
|
if ($package.VersionCanTakeAny) {
|
||
|
$version = ""
|
||
|
$packageVersion = "the latest available"
|
||
|
|
||
|
# Write-Host "choco upgrade $($package.Id) -i $runScripts"
|
||
|
# choco upgrade $package.Id -i $runScripts #Removed -f
|
||
|
} else {
|
||
|
# Write-Host "choco upgrade $($package.Id) --version $version -i $runScripts"
|
||
|
# choco upgrade $package.Id --version $version -i $runScripts #Removed -f
|
||
|
$chocoSplat += "--version=$version"
|
||
|
}
|
||
|
|
||
|
Write-Host "Downloading$(if (!$package.HasManifest){" and installing"}) $($package.id) - This may take a moment, even if things seem frozen."
|
||
|
# https://stackoverflow.com/questions/38523369/write-host-vs-write-information-in-powershell-5
|
||
|
# Out-Default -Transcript <-- magic
|
||
|
Invoke-CallOperatorWithPathAndParameters -Path Choco -Arguments $chocoSplat *>&1 | Out-Default -Transcript | Out-Null
|
||
|
"Installed package [$($package.Id)] version to $packageVersion" | Out-Default -Transcript | Out-Null
|
||
|
}
|
||
|
|
||
|
if (!(Test-IsCollectionNullOrEmpty $parallelInstall)) {
|
||
|
Write-Host "Running parallel installs. This is going to look like things are locked up. They aren't. Promise."
|
||
|
Invoke-Parallel -Objects $parallelInstall -ReturnObjects -Script {
|
||
|
param ($innerPackagePath)
|
||
|
$path = Join-Path -Path (Join-Path -Path $innerPackagePath -ChildPath tools) -ChildPath "chocolateyInstall.ps1"
|
||
|
if (Test-Path -Path $path) {
|
||
|
Write-Host "Calling $path"
|
||
|
& $path
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$servicesInstalled = Invoke-Parallel -Objects $potentialServicePaths -ReturnObjects -Script {
|
||
|
param ($innerPackagePath)
|
||
|
$cimService = Get-ServiceInfoByCIMFragment -QueryFragment $innerPackagePath
|
||
|
if ($null -ne $cimService) {
|
||
|
return $cimService.Name
|
||
|
}
|
||
|
}
|
||
|
if ($tier -lt 3) {
|
||
|
foreach ($serviceName in $servicesInstalled) {
|
||
|
Write-Host "$logLead : Start-AlkamiService -ServiceName $serviceName"
|
||
|
Start-AlkamiService -ServiceName $serviceName
|
||
|
}
|
||
|
} else {
|
||
|
Invoke-Parallel -Objects $servicesInstalled -ReturnObjects -Script {
|
||
|
param ($serviceName)
|
||
|
Start-AlkamiService -ServiceName $serviceName
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# We've already done the database migrations, but we need to ensure the database users got setup for componentized web services
|
||
|
# Ensure logins are setup
|
||
|
Invoke-DatabaseConfigurationAlkamiMasterTask
|
||
|
Invoke-DatabaseConfigurationAlkamiTenantTask
|
||
|
|
||
|
if ($startIIS) {
|
||
|
Remove-DotNetTemporaryFiles
|
||
|
Start-IISAndServices # restarts all of the services that were not upgraded/installed but stopped by installing Alkami.SRE.MigrationUtility
|
||
|
}
|
||
|
|
||
|
Write-Host "$logLead : Setting Alkami services back to recover"
|
||
|
Set-SDKServiceRecovery -ServiceName 'All' -Action 'recovery'
|
||
|
Set-SDKServiceStartupType -ServiceName 'All' -StartupType 'Automatic'
|
||
|
} finally {
|
||
|
Stop-Transcript
|
||
|
Write-Host "`n`n`tTranscript log saved to $transcriptPath`n`n"
|
||
|
}
|
||
|
}
|