ps/Modules/Alkami.PowerShell.ServiceFabric/Public/Publish-AlkamiServiceFabricPackages.ps1

182 lines
8.8 KiB
PowerShell
Raw Normal View History

2023-05-30 22:51:22 -07:00
function Publish-AlkamiServiceFabricPackages {
<#
.SYNOPSIS
Stages Microservice Packages to the service fabric cluster endpoint before deployments.
.PARAMETER packages
The package objects to be staged onto the service fabric cluster.
.PARAMETER hostname
A single server hostname from the target Service Fabric cluster.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true)]
[Alias("PackagesToPublish")]
[AllowNull()]
[object[]]$packages,
[Parameter(Mandatory = $false)]
[Alias("s")]
[string]$hostname = "localhost",
[Parameter(Mandatory = $false)]
[string]$defaultLogConfigFolder = $null,
[Parameter(Mandatory = $false)]
[pscredential]$NugetCredential
)
$loglead = Get-LogLeadName;
$StopWatch = [System.Diagnostics.Stopwatch]::StartNew();
# Set feeds to packages if they are not already there.
Set-ChocoPackageSourceFeeds -packages $packages -hostname $hostname -Verbose;
# Remove installers from the list.
$packages = $packages | Where-Object { !(Test-IsPackageInstaller -packageName $_.Name) };
Write-Host "$loglead : Looking up information on remote host $hostname";
# Connect to SF cluster.
Connect-AlkamiServiceFabricCluster -hostname $hostname | Out-Null;
# Get machine config AppSettings.
$environmentName = Get-AppSetting -appSettingKey "Environment.Name" -ComputerName $hostname;
$environmentType = Get-AppSetting -appSettingKey "Environment.Type" -ComputerName $hostname;
$dbUser = Get-AppSetting -appSettingKey "DatabaseMicroServiceAccount" -ComputerName $hostname;
$microUser = Get-AppSetting -appSettingKey "NonDatabaseMicroServiceAccount" -ComputerName $hostname;
$environmentShortName = Format-AlkamiEnvironmentName -name $environmentName;
# Get the server nodes relevant to the environment.
$nodes = Get-AlkamiServiceFabricNode -EnvironmentName $environmentName;
if(Test-IsCollectionNullOrEmpty $nodes) {
throw "$loglead : Could not identify environment Service Fabric nodes for $environmentShortName";
}
$nodeCount = $nodes.count;
# Determine the default instance count of microservices based on the environment.
# Make sure there are at least two instances, unless it's a single server environment.
$defaultInstanceCount = [System.Math]::Max($nodeCount-2, 2);
if($nodeCount -eq 1) {
$defaultInstanceCount = 1;
}
# Get the running applications on the cluster. Note: This is not the list of registered package images.
$runningApplications = Get-AlkamiServiceFabricApplications -ComputerName $hostname -EnvironmentName $environmentName;
# Create and register applications.
foreach($package in $packages) {
$packageStopWatch = [System.Diagnostics.Stopwatch]::StartNew();
$name = $package.Name;
$version = $package.Version;
$hasError = $false;
# Try to find/create the package from each of the choco feeds configured on the remote server.
$packageSource = $package.Feed.Source;
if([string]::IsNullOrWhiteSpace($packageSource)) {
throw "$loglead : Unable to locate chocolatey feed containing package $name|$version on remote computer $hostname";
}
# Determine if the package is a SF reliable service vs a normal microservice.
$isReliableService = (Test-IsPackageReliableService -feedSource $packageSource -name $name -version $version -Credential $NugetCredential);
# Determine application name and application type name.
$applicationTypeName = $null;
if($isReliableService) {
# The application type name -must- be the name of the class that implements the reliable service contract.
# Pull this name from the manifest located inside the package.
$applicationTypeName = Get-AlkamiServiceFabricPackageServiceTypeName -source $packageSource -name $name -version $version -NugetCredential $NugetCredential
} else {
# For normal microservices the application type name is environment tied, and the application name matches the service name.
$applicationTypeName = Format-AlkamiServiceFabricApplicationName -name $name -environmentName $environmentName;
}
# Build the full name for SF image versioning purposes.
$fullNameVersion = "$name-$version-$environmentShortName";
Write-Verbose "$loglead : Determining if `"$name|$version`" is already registered on the cluster.";
$registrationInfo = Get-ServiceFabricApplicationType -ApplicationTypeName $applicationTypeName -ApplicationTypeVersion $version;
if(!($registrationInfo)) {
# Determine the number of instances to deploy the application with.
$instanceCount = $defaultInstanceCount;
# Figure out if another version of the service is already running on the cluster, and set the instance count to what it currently is.
$applicationSearch = $runningApplications | Where-Object {$_.Name -eq $name} | Select-Object -First 1;
if($null -ne $applicationSearch) {
$instanceCount = Get-AlkamiServiceFabricApplicationInstanceCount -ServiceFabricApplicationName $applicationSearch.ServiceFabricApplicationName -ComputerName $hostname;
}
# Create temporary folder location.
$tempOutputFolder = [System.IO.Path]::GetTempPath() + [guid]::NewGuid().ToString();
try {
if($isReliableService) {
# Poke required values into reliable service app/svc manifests where appropriate.
$arguments = @{
source = $packageSource
name = $name
version = $version
outputFolder = $tempOutputFolder
userDbms = $dbUser
userMicro = $microUser
defaultInstanceCount = $instanceCount
environmentType = $environmentType
defaultLogConfigFolder = $defaultLogConfigFolder
NugetCredential = $NugetCredential
}
New-AlkamiServiceFabricReliableServicePackage @arguments;
} else {
# Repackage topshelf microservice to the format that service fabric expects..
$arguments = @{
source = $packageSource
name = $name
version = $version
outputFolder = $tempOutputFolder
userDbms = $dbUser
userMicro = $microUser
defaultInstanceCount = $instanceCount
environmentName = $environmentName
environmentType = $environmentType
defaultLogConfigFolder = $defaultLogConfigFolder
NugetCredential = $NugetCredential
}
New-AlkamiServiceFabricPackage @arguments;
}
# Copy package to image store.
Write-Host "$loglead : Uploading and Registering $fullNameVersion from package built at $tempOutputFolder";
Copy-ServiceFabricApplicationPackage -ApplicationPackagePath $tempOutputFolder -ApplicationPackagePathInImageStore $fullNameVersion -CompressPackage;
# Register the application with Service Fabric.
Register-ServiceFabricApplicationType -ApplicationPathInImageStore $fullNameVersion -ApplicationPackageCleanupPolicy Automatic;
Write-Host "$loglead : Package publish complete.";
} catch {
Write-Error "$loglead : Failed to publish Service Fabric package:`n $($_.Exception.Message)";
$hasError = $true;
} finally {
if(Test-Path $tempOutputFolder) {
if($hasError) {
Write-Warning "$loglead : Removing incomplete package creation at $tempOutputFolder";
} else {
Write-Host "$loglead : Removing package files at $tempOutputFolder";
}
Invoke-CommandWithRetry -MaxRetries 3 -SecondsDelay 1 -Arguments @($tempOutputFolder) -ScriptBlock {
param($folderPath)
Remove-FileSystemItem $folderPath -Recurse
}
}
}
}
else {
Write-Host "$loglead : Service Fabric Application $name|$version is already registered. Skipping.";
}
$packageStopWatch.Stop();
Write-Verbose "$loglead : Completed $name|$version in $($packageStopWatch.Elapsed.TotalSeconds) seconds.";
}
$StopWatch.Stop();
Write-Verbose "$loglead : Completed in $($StopWatch.Elapsed.TotalSeconds) seconds.";
}