ps/Modules/Alkami.PowerShell.ServiceFabric/Public/Install-AlkamiServiceFabricPackages.ps1
2023-05-30 22:51:22 -07:00

168 lines
9.4 KiB
PowerShell

function Install-AlkamiServiceFabricPackages {
<#
.SYNOPSIS
Deploys Microservice Packages to the Service Fabric cluster.
.PARAMETER packages
Package objects for the packages to be deployed to the cluster.
.PARAMETER hostname
The host name of any server in the Service Fabric cluster.
.PARAMETER defaultLogConfigFolder
SOURCE folder for default log4net configs
.PARAMETER nugetCredential
Credential used to authenticate with Proget server
.PARAMETER HealthCheckStableDurationSec
Amount of time after 1st successful HC to require continuing successful HCs
See: https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-application-upgrade-parameters
.PARAMETER HealthCheckRetryTimeoutSec
Max time to keep waiting for successful HC before failing Upgrade
See: https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-application-upgrade-parameters
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true)]
[Alias("PackagesToPublish")]
[AllowNull()]
[object[]]$packages,
[Parameter(Mandatory = $true)]
[Alias("s")]
[string]$hostname,
[Parameter(Mandatory = $false)]
[string]$defaultLogConfigFolder = $null,
[Parameter(Mandatory = $false)]
[pscredential]$nugetCredential = $null,
[Parameter(Mandatory = $false)]
[Int32]$HealthCheckStableDurationSec = 120,
[Parameter(Mandatory = $false)]
[Int32]$HealthCheckRetryTimeoutSec = 600
)
$loglead = Get-LogLeadName;
# Arrange the subscription service and broker to the front of the packages list if they exist.
$packages = ($packages | Sort-Object -Property @{Expression={ $Global:InfrastructureMicroServices -contains $_.Name }} -Descending);
# Remove microservice installers from the list.
$packages = $packages | Where-Object { !(Test-IsPackageInstaller -packageName $_.Name) };
# Write out the packages being installed.
Write-Verbose "$loglead Now installing:";
foreach($package in $packages) {
Write-Verbose "$($package.Name) - $($package.Version)";
}
# Set feeds to packages if they are not already there.
Set-ChocoPackageSourceFeeds -packages $packages -hostname $hostname -Verbose;
# Connect to SF cluster.
Connect-AlkamiServiceFabricCluster -hostname $hostname | Out-Null;
# Get the environment name, and clean it up.
$environmentName = Get-AppSetting -appSettingKey "Environment.Name" -ComputerName $hostname;
# Stage all packages, which it only does fully if they aren't already staged.
Write-Host "$loglead : Staging $($packages.Count) packages.";
if ([String]::IsNullOrEmpty($defaultLogConfigFolder)) {
Publish-AlkamiServiceFabricPackages -packages $packages -hostname $hostname -nugetCredential $NugetCredential
} else {
Write-Host "defaultLogConfigFolder: <$defaultLogConfigFolder>"
Publish-AlkamiServiceFabricPackages -packages $packages -hostname $hostname -defaultLogConfigFolder $defaultLogConfigFolder -nugetCredential $NugetCredential
}
# Deploy all the packages.
Write-Host "$loglead : Deploying $($packages.Count) packages.";
foreach($package in $packages) {
$packageString = "$($package.Name).$($package.Version)";
$packageSource = $package.Feed.Source;
$isReliableService = Test-IsPackageReliableService -feedSource $packageSource -name $package.Name -version $package.Version -Credential $NugetCredential -Verbose
# Determine application name and application type name.
$applicationName = $null;
$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 $package.Name -version $package.Version -nugetCredential $NugetCredential;
# Reliable services are not tied to specific environments.
$applicationName = Format-AlkamiServiceFabricApplicationName -name $applicationTypeName -version $package.Version;
} else {
# For normal microservices the application type name is environment tied, and the application name matches the service name.
$applicationName = Format-AlkamiServiceFabricApplicationName -name $package.Name -version $package.Version -environmentName $environmentName;
$applicationTypeName = Format-AlkamiServiceFabricApplicationName -name $package.Name -environmentName $environmentName; # No version
}
$applicationPath = "fabric:/$applicationName";
# Figure out if we need to create a new application, or an upgrade.
$application = (Get-ServiceFabricApplication -ApplicationName $applicationPath);
$updateAffinity = $true;
$isNewApplication = $false;
if(!($application)) {
Write-Host "$loglead : Application $($package.Name) has never been deployed! Deploying.";
$isNewApplication = $true;
New-ServiceFabricApplication -ApplicationName $applicationPath -ApplicationTypeName $applicationTypeName -ApplicationTypeVersion $package.Version
} elseif($application.ApplicationTypeVersion -ne $package.Version) {
Start-ServiceFabricApplicationUpgrade -ApplicationName $applicationPath -ApplicationTypeVersion $package.Version -Monitored -FailureAction Rollback -Force -UpgradeReplicaSetCheckTimeoutSec 15 -HealthCheckStableDurationSec $HealthCheckStableDurationSec -HealthCheckRetryTimeoutSec $HealthCheckRetryTimeoutSec
Write-Host "$loglead : Application $($package.Name) is running in the cluster on version $($application.ApplicationTypeVersion). Rolling out version $($package.Version).";
} else {
$updateAffinity = $false;
Write-Host "$loglead : Application $packageString is already deployed on the cluster. Skipping.";
}
# Set affinity to the subscription service.
# Only set affinity on the non-infra services. Affinity can't be set on services that run everywhere without errors.
if($updateAffinity -and ($null -eq ($Global:InfrastructureMicroServices | Where-Object { $_ -eq $package.name; }))) {
Write-Verbose "$loglead : Setting Affinity to the Subscription Service";
# Only query for the subscription service once. This only matters if the subscription service is not yet deployed.
if($null -eq $subscriptionService) {
# Query for the subscription service app in SF.
# Grab all apps and wildcard search because we don't know what major version might be running, and SF doesn't do partial searches.
Write-Verbose "$loglead : Searching for subscription service application name in the cluster.";
$subscriptionAppName = (Format-AlkamiServiceFabricApplicationName -name $Global:SubscriptionServiceFabricName -environmentName $environmentName);
$subscriptionAppNameUri = "fabric:/$($subscriptionAppName)*";
$subscriptionApplication = (Get-ServiceFabricApplication | Where-Object { $_.ApplicationName -like $subscriptionAppNameUri} | Select-Object -First 1);
if($null -ne $subscriptionApplication) {
$subscriptionService = Get-ServiceFabricService -ApplicationName $subscriptionApplication.ApplicationName;
}
if($null -eq $subscriptionService) {
Write-Verbose "$loglead : Could not find subscription service to set affinity to.";
} else {
Write-Verbose "$loglead : Found $($subscriptionService.ServiceName)";
}
}
if($null -ne $subscriptionService) {
$affinity = "NonAlignedAffinity";
$affinityRules = @("$($subscriptionService.ServiceName),$affinity");
# Set affinity for every service in the application that was just deployed.
$services = Get-ServiceFabricService -ApplicationName $applicationPath;
foreach($service in $services) {
Update-ServiceFabricService -Stateless -ServiceName $service.ServiceName -Correlation $affinityRules -Force;
}
Write-Verbose "$loglead : Affinity update complete.";
}
}
# If we deployed a new major version, instead of an upgrade of an existing major version, there will be multiple applications running.
# Remove every major version of the application that is not the version we just deployed.
if($isNewApplication) {
$runningApplications = Get-AlkamiServiceFabricApplications -ComputerName $hostname -Name $package.Name;
$oldApplications = $runningApplications | Where-Object { $_.Version -ne $package.Version };
if(!(Test-IsCollectionNullOrEmpty $oldApplications)) {
Write-Host "$loglead : New major version is deployed. Removing other major versions.";
foreach($application in $oldApplications) {
Write-Host "$loglead : Removing $($application.Name) $($application.Version) from cluster.";
Remove-ServiceFabricApplication -ApplicationName $($application.ServiceFabricApplicationName) -Force;
}
}
}
}
}