250 lines
11 KiB
PowerShell
250 lines
11 KiB
PowerShell
function Get-PackageInstallationData {
|
|
<#
|
|
.SYNOPSIS
|
|
Returns an array of tiered packages to install, and attaches metadata to each package object about how the package should be installed. This does not modify the original $packages list.
|
|
|
|
.PARAMETER ChocoPackages
|
|
Array of [object] Packages with Name, Version, and Feed info
|
|
|
|
.PARAMETER Servers
|
|
Array of [string] Server hostnames used to decide which hosttypes should be signalled as targets for a given ChocoPackage
|
|
|
|
.PARAMETER FIlterFeeds
|
|
Causes the filtering out of ChocoPackages whose Feed property is undesirable for a deploy; for example, "Default", nuget.internal, SRETools.
|
|
|
|
.PARAMETER FilterPowerShellModules
|
|
Causes the filtering out of ChocoPackages that are PowerShellModules
|
|
|
|
.PARAMETER NugetCredential
|
|
Credential information to access the nuget server
|
|
|
|
.PARAMETER IncludeMissingPackages
|
|
Include packages not found on nuget server in the return object(s).
|
|
Bypass default Error output for missing packages.
|
|
Packages returned this way are duplicates of the package that was passed in, plus two members: IsValid=$false, Tier=Tier count + 1
|
|
|
|
.PARAMETER UseV2PackageMetadata
|
|
Use the new pacakge metadata v2 methods
|
|
|
|
.PARAMETER PackageToServerMap
|
|
Optional map of packages to servers. Useful in TeamCity.Deployment.Code for determining if a package is missing from the servers in the environment
|
|
#>
|
|
[CmdletBinding()]
|
|
Param (
|
|
[Parameter(Mandatory=$true)]
|
|
[AllowNull()]
|
|
[object[]]$ChocoPackages,
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]$Servers,
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$FilterFeeds,
|
|
[Parameter(Mandatory = $false)]
|
|
[switch]$FilterPowerShellModules,
|
|
[Parameter(Mandatory=$true)]
|
|
[PSCredential]$NugetCredential,
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$IncludeMissingPackages,
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$UseV2PackageMetadata,
|
|
[object]$PackageToServerMap
|
|
)
|
|
|
|
$loglead = Get-LogLeadName
|
|
|
|
if (!$ChocoPackages -or ($ChocoPackages.Count -eq 0)) {
|
|
return $null
|
|
}
|
|
|
|
# Determine what types of servers are in the environment.
|
|
$webServers = Select-AlkamiWebServers $Servers
|
|
$appServers = Select-AlkamiAppServers $Servers
|
|
$micServers = Select-AlkamiMicServers $Servers
|
|
$fabServers = Select-AlkamiFabServers $Servers
|
|
$hasWebServers = $null -ne $webServers
|
|
$hasAppServers = $null -ne $appServers
|
|
$hasMicServers = $null -ne $micServers
|
|
$hasFabServers = $null -ne $fabServers
|
|
|
|
# Select the first server to grab configured feeds from.
|
|
$firstServer = $Servers | Select-Object -First 1
|
|
|
|
# Verify that all of the packages have feeds set, to make the appropriate proget API calls.
|
|
if (([array]($ChocoPackages | Where-Object { $null -eq $_.Feed })).Count -gt 0) {
|
|
Set-ChocoPackageSourceFeedsV2 -Packages $ChocoPackages -Hostname $firstServer
|
|
}
|
|
# Filter out any packages that come from the default chocolatey feed, nuget.internal, or the SRE tools feed.
|
|
if ($filterFeeds.IsPresent) {
|
|
$ChocoPackages = $ChocoPackages | Where-Object { (!$_.Feed.IsDefault) -and ($_.Feed.Source -notlike "*nuget/nuget.internal*") -and ($_.Feed.Source -notlike "*SRETools*") }
|
|
}
|
|
|
|
# Filter out PowerShell modules.
|
|
if ($filterPowerShellModules.IsPresent -and ($null -ne $chocoPackages)) {
|
|
# Test-IsPackagePowerShellModule tests against a global in \Alkami.PowerShell.Choco\Private\VariableDeclarations.ps1
|
|
$ChocoPackages = $ChocoPackages | Where-Object { !(Test-IsPackagePowerShellModuleV2 -PackageName $_.Name) }
|
|
}
|
|
|
|
# Fetch package metadata for each package.
|
|
# Parallelize this because it is making calls against Proget.
|
|
# TODO: Refactor this to use a splatted var
|
|
# Force the results into an array. Necessary for unit testing, and prevents PS unilaterally unboxing for no raisin.
|
|
$categorizedPackages = @()
|
|
|
|
$categorizedPackages += Invoke-Parallel -objects $ChocoPackages -returnObjects -arguments ($NugetCredential, $UseV2PackageMetadata, $hasMicServers, $hasFabServers) -script {
|
|
param($package, $arguments)
|
|
$NugetCredential = $arguments[0]
|
|
$micServersPresent = $arguments[2]
|
|
$fabServersPresent = $arguments[3]
|
|
|
|
# Fetch metadata for the package.
|
|
$categorizedPackage = Get-PackageMetadataV2 -Package $package -NugetCredential $NugetCredential -MicroserviceTierPresent:$micServersPresent -ServiceFabricTierPresent:$fabServersPresent
|
|
|
|
# Return the results in a map so we can separate the real result from needless PSJob properties (such as RunspaceId) on every package.
|
|
return @{ Package = $categorizedPackage; ValidPackage = $categorizedPackage.IsValid; }
|
|
}
|
|
|
|
$badPackages = $categorizedPackages | Where-Object { $_.ValidPackage -ne $true }
|
|
|
|
[string]$errorText = $null
|
|
if (!(Test-IsCollectionNullOrEmpty $badPackages)) {
|
|
if ($IncludeMissingPackages) {
|
|
Write-Host "$logLead : Resultset will be returned with Missing Packages included."
|
|
} else {
|
|
foreach ($badPackage in $badPackages) {
|
|
$errorText += "$($badPackage.Package.Name)|$($badPackage.Package.Version)|$($badPackage.Package.Feed.Source)`n"
|
|
}
|
|
Write-Error "$logLead : These Packages Were not found: `n $errorText"
|
|
}
|
|
}
|
|
|
|
# retrieve just the packages and discard the other information
|
|
$categorizedPackages = $categorizedPackages | ForEach-Object { $_.Package }
|
|
|
|
# Run back through each package and figure out where the package should be installed.
|
|
foreach ($package in $categorizedPackages) {
|
|
# This didn't pick up like I expected it to
|
|
$package | Add-Member -NotePropertyName "Tier" -NotePropertyValue (-1) -Force
|
|
|
|
# ensure if we chose that we should do a force-install that we stick to the types of servers present
|
|
# as-is, a package can be marked "force install" to both tiers if neither tier can be determined correctly
|
|
if ($package.ForceInstallToWebDetermination) {
|
|
$package.InstallToWeb = $package.InstallToWeb -and $hasWebServers
|
|
}
|
|
if ($package.ForceInstallToAppDetermination) {
|
|
$package.InstallToApp = $package.InstallToApp -and $hasAppServers
|
|
}
|
|
|
|
# we don't need this loop because all this should be happening in Get-PackageMetadata
|
|
Write-Host "$loglead : Skipping re-categorization for [$($package.Name)]"
|
|
continue
|
|
}
|
|
|
|
if (!(Test-IsCollectionNullOrEmpty $PackageToServerMap)) {
|
|
# Since we have some packages that can be mapped, let's find out if they are on all the servers
|
|
Write-Host "$logLead : Testing each package for correct server count in PackageToServerMap hashtable"
|
|
foreach ($package in $categorizedPackages) {
|
|
$lowerName = $package.Name.ToLower()
|
|
$packageMap = $PackageToServerMap[$lowerName]
|
|
if (!(Test-IsCollectionNullOrEmpty $packageMap)) {
|
|
# The value in the map is a non-empty array
|
|
if ($package.InstallToWeb -and $hasWebServers) {
|
|
# figure out which servers are not in the list
|
|
foreach ($server in $webServers) {
|
|
if ($packageMap -notcontains $server) {
|
|
Write-Host "$logLead : Could not find server [$server] in the packageMap for package [$lowerName] - package missing from server."
|
|
if ($null -eq $package.MissingFromServers) {
|
|
$package.MissingFromServers = @()
|
|
}
|
|
$package.MissingFromServers += $server
|
|
$package.IsMissingFromServers = $true
|
|
}
|
|
}
|
|
}
|
|
if ($package.InstallToApp -and $hasAppServers) {
|
|
# figure out which servers are not in the list
|
|
foreach ($server in $appServers) {
|
|
if ($packageMap -notcontains $server) {
|
|
Write-Host "$logLead : Could not find server [$server] in the packageMap for package [$lowerName]. Package missing from server."
|
|
if ($null -eq $package.MissingFromServers) {
|
|
$package.MissingFromServers = @()
|
|
}
|
|
$package.MissingFromServers += $server
|
|
$package.IsMissingFromServers = $true
|
|
}
|
|
}
|
|
}
|
|
if ($package.InstallToMic -and $hasMicServers) {
|
|
# figure out which servers are not in the list
|
|
foreach ($server in $micServers) {
|
|
if ($packageMap -notcontains $server) {
|
|
Write-Host "$logLead : Could not find server [$server] in the packageMap for package [$lowerName]. Package missing from server."
|
|
if ($null -eq $package.MissingFromServers) {
|
|
$package.MissingFromServers = @()
|
|
}
|
|
$package.MissingFromServers += $server
|
|
$package.IsMissingFromServers = $true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get the microservice tiers.
|
|
$tiers = Get-MicroserviceTiers
|
|
|
|
# Get a [packageName -> tier] mapping of the tiers.
|
|
$tierMap = @{}
|
|
for ($tier = 0; $tier -lt $tiers.Count; $tier++) {
|
|
$tierPackageNames = $tiers[$tier]
|
|
foreach ($packageName in $tierPackageNames) {
|
|
$tierMap[$packageName] = $tier
|
|
}
|
|
}
|
|
$catchAllTier = $tiers.Count
|
|
|
|
# Assign each package to a tier.
|
|
foreach ($package in $categorizedPackages) {
|
|
# Assign installers to the first tier.
|
|
$tier = -1
|
|
if ($package.IsInstaller) {
|
|
$tier = 0
|
|
} elseif ($package.IsComponentizedWebApp) {
|
|
$tier = 1
|
|
} else {
|
|
# Check if the package is specifically named as being in a tier.
|
|
if ($tierMap.ContainsKey($package.Name)) {
|
|
$tier = $tierMap[$package.Name]
|
|
} elseif ($package.IsValid) {
|
|
# Put it in the last tier.
|
|
$tier = $catchAllTier
|
|
} else {
|
|
# Missing(invalid) packages get (Number of Tiers + 1) so that
|
|
# The sorting expression will give them a negative number so
|
|
# that they are _obviously_ invalid
|
|
$tier = $catchAllTier + 1
|
|
}
|
|
}
|
|
|
|
$package.Tier = $tier
|
|
}
|
|
|
|
# FUTURE US SRE-16834 Hotfix Tiering
|
|
# We may want to set all hotfixes to $tiers.Count + 1. This is a good place for that.
|
|
|
|
# Sort packages.
|
|
# Tiers -> Installers -> Infrastructure Microservices -> Microservices -> Not-Microservices -> SDK
|
|
# Powers of 2 guarantee that the higher-precedent conditions will always take priority in sorting.
|
|
# The "catchAllTier - tier" is to make the tiers sort in ascending order. catchAllTier = tiers.count
|
|
$categorizedPackages = ($categorizedPackages | Sort-Object -Property @{
|
|
Expression = {
|
|
16 * [int]($catchAllTier - $_.Tier) +
|
|
8 * [int]($_.IsInstaller) +
|
|
4 * [int]($_.IsInfrastructure) +
|
|
2 * [int]($_.IsMicroservice) +
|
|
1 * [int](!($_.IsSDK))
|
|
}
|
|
} -Descending)
|
|
|
|
return $categorizedPackages
|
|
}
|