Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for upgrading compose applications #6256

Merged
merged 10 commits into from
May 24, 2018
109 changes: 82 additions & 27 deletions Tasks/ServiceFabricComposeDeployV0/ServiceFabricComposeDeploy.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ try
$deployTimeoutSec = Get-VstsInput -Name deployTimeoutSec
$removeTimeoutSec = Get-VstsInput -Name removeTimeoutSec
$getStatusTimeoutSec = Get-VstsInput -Name getStatusTimeoutSec
$upgrade = (Get-VstsInput -Name upgrade) -eq "true"

$apiVersion = '2.8'
$regKey = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Service Fabric SDK\' -ErrorAction SilentlyContinue
Expand Down Expand Up @@ -172,48 +173,102 @@ try
$getStatusParameters['TimeoutSec'] = $getStatusTimeoutSec
}

$upgrading = $false
$existingApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
if ($existingApplication -ne $null)
{
Write-Host (Get-VstsLocString -Key RemovingApplication -ArgumentList $applicationName)

Remove-ServiceFabricComposeApplicationHelper -ApiVersion $apiVersion -RemoveParameters $removeParameters
do
if ($apiVersion -eq "2.8" -and $upgrade)
{
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $existingApplication.Status)
Start-Sleep -Seconds 3
$existingApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
$upgrading = $true
}
while ($existingApplication -ne $null)
Write-Host (Get-VstsLocString -Key ApplicationRemoved)
}
else
{
Write-Host (Get-VstsLocString -Key RemovingApplication -ArgumentList $applicationName)

Write-Host (Get-VstsLocString -Key CreatingApplication)
New-ServiceFabricComposeApplicationHelper -ApiVersion $apiVersion -DeployParameters $deployParameters
Remove-ServiceFabricComposeApplicationHelper -ApiVersion $apiVersion -RemoveParameters $removeParameters
do
{
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $existingApplication.Status)
Start-Sleep -Seconds 3
$existingApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
}
while ($existingApplication -ne $null)
Write-Host (Get-VstsLocString -Key ApplicationRemoved)
}
}

Write-Host (Get-VstsLocString -Key WaitingForDeploy)
$newApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
while (($newApplication -eq $null) -or `
($newApplication.Status -eq 'Provisioning') -or `
($newApplication.Status -eq 'Creating'))
if ($upgrading)
{
if ($newApplication -eq $null)
$upgradeParameters = New-Object 'System.Collections.Hashtable' $deployParameters
$upgradeParameters.Monitored = $True
$upgradeParameters.FailureAction = 'Rollback'
$upgradeParameters.ConsiderWarningAsError = $True
$upgradeParameters.Force = $True

$upgradeStatus = Get-ServiceFabricComposeDeploymentUpgradeHelper -ApiVersion $apiVersion -GetUpgradeParameters $getStatusParameters
if (($upgradeStatus -ne $null) -and (IsUpgradeRunning $upgradeStatus.UpgradeState))
{
Write-Host (Get-VstsLocString -Key WaitingForDeploy)
Write-Error (Get-VstsLocString -Key UpgradeInProgress -ArgumentList $applicationName)
}
else

Write-Host (Get-VstsLocString -Key UpgradingApplication)
Start-ServiceFabricComposeDeploymentUpgradeHelper -ApiVersion $apiVersion -UpgradeParameters $upgradeParameters

Write-Host (Get-VstsLocString -Key WaitingForUpgrade)
# Wait a minute before checking on the upgrade to avoid getting the status of the last upgrade.
Start-Sleep -Seconds 60
$upgradeStatus = Get-ServiceFabricComposeDeploymentUpgradeHelper -ApiVersion $apiVersion -GetUpgradeParameters $getStatusParameters
while (($upgradeStatus -eq $null) -or (IsUpgradeRunning $upgradeStatus.UpgradeState))
{
if ($upgradeStatus -eq $null)
{
Write-Host (Get-VstsLocString -Key WaitingForUpgrade)
}
else
{
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $upgradeStatus.UpgradeState )
}
Start-Sleep -Seconds 3

$upgradeStatus = Get-ServiceFabricComposeDeploymentUpgradeHelper -ApiVersion $apiVersion -GetUpgradeParameters $getStatusParameters
}
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $upgradeStatus.UpgradeState)

if ($upgradeStatus.UpgradeState -ne 'RollingForwardCompleted')
{
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $newApplication.Status)
Write-Error (Get-VstsLocString -Key UpgradeFailed -ArgumentList @($upgradeStatus.UpgradeState.ToString(), $upgradeStatus.UpgradeStatusDetails))
}
Start-Sleep -Seconds 3
$newApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
}
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $newApplication.Status)

if ($newApplication.Status -ne 'Created' -and $newApplication.Status -ne 'Ready')
else
{
Write-Error (Get-VstsLocString -Key DeployFailed -ArgumentList @($newApplication.Status.ToString(), $newApplication.StatusDetails))
Write-Host (Get-VstsLocString -Key CreatingApplication)
New-ServiceFabricComposeApplicationHelper -ApiVersion $apiVersion -DeployParameters $deployParameters

Write-Host (Get-VstsLocString -Key WaitingForDeploy)
$newApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
while (($newApplication -eq $null) -or `
($newApplication.Status -eq 'Provisioning') -or `
($newApplication.Status -eq 'Creating'))
{
if ($newApplication -eq $null)
{
Write-Host (Get-VstsLocString -Key WaitingForDeploy)
}
else
{
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $newApplication.Status)
}
Start-Sleep -Seconds 3
$newApplication = Get-ServiceFabricComposeApplicationStatusHelper -ApiVersion $apiVersion -GetStatusParameters $getStatusParameters
}
Write-Host (Get-VstsLocString -Key CurrentStatus -ArgumentList $newApplication.Status)

if ($newApplication.Status -ne 'Created' -and $newApplication.Status -ne 'Ready')
{
Write-Error (Get-VstsLocString -Key DeployFailed -ArgumentList @($newApplication.Status.ToString(), $newApplication.StatusDetails))
}
}

}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"loc.input.help.registryPassword": "Password for the Docker registry. If the password is not encrypted, it is recommended that you use a custom release definition secret variable to store it.",
"loc.input.label.passwordEncrypted": "Password Encrypted",
"loc.input.help.passwordEncrypted": "It is recommended to encrypt your password using [Invoke-ServiceFabricEncryptText](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-application-secret-management#encrypt-application-secrets). If you do not, and a certificate matching the Server Certificate Thumbprint in the Cluster Connection is installed on the build agent, it will be used to encrypt the password; otherwise an error will occur.",
"loc.input.label.upgrade": "Upgrade",
"loc.input.help.upgrade": "Upgrade an existing deployment rather than removing it.",
"loc.input.label.deployTimeoutSec": "Deploy Timeout (s)",
"loc.input.help.deployTimeoutSec": "Timeout in seconds for deploying the application.",
"loc.input.label.removeTimeoutSec": "Remove Timeout (s)",
Expand All @@ -39,11 +41,15 @@
"loc.messages.ApplicationRemoved": "Application removed.",
"loc.messages.EncryptingPassword": "Encrypting the password with the Server Certificate.",
"loc.messages.CreatingApplication": "Creating application",
"loc.messages.UpgradingApplication": "Upgrading application",
"loc.messages.WaitingForDeploy": "Waiting for deploy...",
"loc.messages.WaitingForUpgrade": "Waiting for upgrade...",
"loc.messages.CurrentStatus": "Current Status: {0}",
"loc.messages.DeployFailed": "Deploy Failed\nStatus: {0}\nDetails: {1}",
"loc.messages.UpgradeFailed": "Upgrade Failed\nStatus: {0}\nDetails: {1}",
"loc.messages.CheckingComposeFile": "Checking compose file",
"loc.messages.UnsupportedAPIVersion": "Service Fabric SDK version {0} is not supported.",
"loc.messages.UsingAPIVersion": "Using cmdlets for Service Fabric SDK version {0}.",
"loc.messages.InvalidApplicationNameWarning": "Latest Service Fabric has stopped supporting compose application name starting with 'fabric:/' and hence compose deployment might fail with ServiceDnsName error for application name '{0}'. You can provide a different application name and re-run if required."
"loc.messages.InvalidApplicationNameWarning": "Latest Service Fabric has stopped supporting compose application name starting with 'fabric:/' and hence compose deployment might fail with ServiceDnsName error for application name '{0}'. You can provide a different application name and re-run if required.",
"loc.messages.UpgradeInProgress": "An upgrade for the application '{0}' is already in progress."
}
1 change: 1 addition & 0 deletions Tasks/ServiceFabricComposeDeployV0/Tests/Deploy.2.8.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Register-Mock Get-VstsInput { $null } -Name deployTimeoutSec
Register-Mock Get-VstsInput { $null } -Name removeTimeoutSec
Register-Mock Get-VstsInput { $null } -Name getStatusTimeoutSec
Register-Mock Get-VstsInput { "None" } -Name registryCredentials -Require
Register-Mock Get-VstsInput { "false" } -Name upgrade

# Setup file resolution
Register-Mock Find-VstsFiles { $composeFilePath } -- -LegacyPattern $composeFilePath
Expand Down
3 changes: 3 additions & 0 deletions Tasks/ServiceFabricComposeDeployV0/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ describe('ServiceFabricComposeDeploy Suite', function () {
it('Deploy Preview', (done) => {
psr.run(path.join(__dirname, 'DeployPreview.ps1'), done);
})
it('Replace 2.8', (done) => {
psr.run(path.join(__dirname, 'Replace.2.8.ps1'), done);
})
it('Upgrade 2.7', (done) => {
psr.run(path.join(__dirname, 'Upgrade.2.7.ps1'), done);
})
Expand Down
148 changes: 148 additions & 0 deletions Tasks/ServiceFabricComposeDeployV0/Tests/Replace.2.8.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
[CmdletBinding()]
param()

. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1

$serviceConnectionName = "random connection name"
$composeFilePath = "docker-compose.yml"
$deploymentName = "fabric:/Application1"
$applicationName = "fabric:/fabric:/Application1"
$serverCertThumbprint = "random thumbprint"
$userName = "random user"
$password = "random password"
$connectionEndpointFullUrl = "https://mycluster.com:19000"
$connectionEndpoint = ([System.Uri]$connectionEndpointFullUrl).Authority

# Setup input arguments
Register-Mock Get-VstsInput { $serviceConnectionName } -Name serviceConnectionName -Require
Register-Mock Get-VstsInput { $composeFilePath } -Name composeFilePath -Require
Register-Mock Get-VstsInput { $deploymentName } -Name applicationName -Require
Register-Mock Get-VstsInput { $null } -Name deployTimeoutSec
Register-Mock Get-VstsInput { $null } -Name removeTimeoutSec
Register-Mock Get-VstsInput { $null } -Name getStatusTimeoutSec
Register-Mock Get-VstsInput { "None" } -Name registryCredentials -Require
Register-Mock Get-VstsInput { "false" } -Name upgrade

# Setup file resolution
Register-Mock Find-VstsFiles { $composeFilePath } -- -LegacyPattern $composeFilePath

Register-Mock Assert-VstsPath
Register-Mock Test-Path { $true } -- "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK"

# Setup mock VSTS service endpoint
$vstsEndpoint = @{
"url" = $connectionEndpointFullUrl
"Auth" = @{
"Scheme" = "UserNamePassword"
"Parameters" = @{
"ServerCertThumbprint" = $serverCertThumbprint
"Username" = $userName
"Password" = $password
}
}
}
Register-Mock Get-VstsEndpoint { $vstsEndpoint } -- -Name $serviceConnectionName -Require

# Setup mock Registry for Service Fabric
$SfRegistry = @{
"FabricSDKVersion" = "2.8.1.2"
}
Register-Mock Get-ItemProperty { $SfRegistry } -- -Path 'HKLM:\SOFTWARE\Microsoft\Service Fabric SDK\' -ErrorAction SilentlyContinue

# Setup mock results of cluster connection
Register-Mock Connect-ServiceFabricClusterFromServiceEndpoint { } -- -ClusterConnectionParameters @{} -ConnectedServiceEndpoint $vstsEndpoint

$deploymentStatus = @{
"ApplicationName" = $applicationName
"DeploymentName" = $deploymentName
"ComposeDeploymentStatus" = "Ready"
"StatusDetails" = ""
}

$deploymentUpgraded = @{
"ApplicationName" = $applicationName
"DeploymentName" = $deploymentName
"UpgradeState" = "RollingForwardCompleted"
"UpgradeStatusDetails" = ""
}
$applicationUpgraded = @{
"ApplicationName" = $applicationName
"UpgradeState" = "RollingForwardCompleted"
}

$deploymentUpgrading = @{
"ApplicationName" = $applicationName
"DeploymentName" = $deploymentName
"UpgradeState" = "RollingForwardInProgress"
"UpgradeStatusDetails" = ""
}
$applicationUpgrading = @{
"ApplicationName" = $applicationName
"UpgradeState" = "RollingForwardInProgress"
}

# Need to store the bool in an object so the lambdas will share the reference
$removed = New-Object 'System.Collections.Generic.Dictionary[string, bool]'
$removed.Value = $false
$isUpgrading = New-Object 'System.Collections.Generic.Dictionary[string, bool]'
$isUpgrading.Value = $false

Register-Mock Get-ServiceFabricComposeDeploymentStatus {
if (($removed.Value -eq $true))
{
return $null;
}
else
{
return $deploymentStatus
}
} -DeploymentName: $deploymentName

Register-Mock Remove-ServiceFabricComposeDeployment {
$removed.Value = $true
} -DeploymentName: $deploymentName -Force: $true

Register-Mock Test-ServiceFabricApplicationPackage { } -- -ComposeFilePath $composeFilePath -ErrorAction Stop

Register-Mock New-ServiceFabricComposeDeployment {
$removed.Value = $false
} -- -DeploymentName: $deploymentName -Compose: $composeFilePath

Register-Mock Get-ServiceFabricComposeDeploymentUpgrade {
if ($isUpgrading.Value -eq $true)
{
return $deploymentUpgrading;
}
else
{
return $deploymentUpgraded
}
} -DeploymentName: $deploymentName

Register-Mock Get-ServiceFabricApplicationUpgrade {
if ($isUpgrading.Value -eq $true)
{
$isUpgrading.Value = $false
return $applicationUpgrading;
}
else
{
return $applicationUpgraded
}
} -ApplicationName: $applicationName

Register-Mock Start-ServiceFabricComposeDeploymentUpgrade {
$isUpgrading.Value = $true
} -Force: True -ConsiderWarningAsError: True -FailureAction: Rollback -DeploymentName: $deploymentName -Monitored: True -Compose: $composeFilePath

Register-Mock Start-Sleep { } -ParametersEvaluator { $true }

# Act
. $PSScriptRoot\..\..\..\Tasks\ServiceFabricComposeDeployV0\ps_modules\ServiceFabricHelpers\Connect-ServiceFabricClusterFromServiceEndpoint.ps1
@( & $PSScriptRoot/../../../Tasks/ServiceFabricComposeDeployV0/ServiceFabricComposeDeploy.ps1 )

# Assert
Assert-WasCalled Get-ServiceFabricComposeDeploymentStatus -Times 3
Assert-WasCalled Get-ServiceFabricComposeDeploymentUpgrade -Times 0
Assert-WasCalled Remove-ServiceFabricComposeDeployment -Times 1
Assert-WasCalled New-ServiceFabricComposeDeployment -Times 1
Loading