182 lines
8.8 KiB
PowerShell
182 lines
8.8 KiB
PowerShell
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.";
|
|
}
|