Database Deployments with Automatic Rollbacks, part IV: Adding automatic rollbacks of application services

This post is part of a series on deploying database updates with automatic rollbacks using EF Core Migrations and Octopus Deploy. In this part of the series, we’ll add automatic rollbacks to a known good release in case of failure. We’ll also add a retention policy to the database backup files.

All posts in the series:

Part I: Where We Are, and Where We Want To Be
Part II: Packaging the Database Updates
Part III: Deploying the Database Updates
Part IV: Adding Automatic Rollback of Application Services (this post)
Part V: Summary of the Series

  1. All the scripts in this series are available in this gist.

In Octopus Deploy, Rollbacks Are Not Special

There’s actually no built-in concept of a rollback in Octopus Deploy. Instead, what we’ll do is figure out which release was last successfully deployed to the environment, and deploy that release again.

At the time of writing, Octopus Deploy has a built-in step for deploying a release, but it only supports deploying releases of other deployment projects. We want to deploy this project again, so we’ll have to make a request to the Octopus REST API. For that, we’ll use some more PowerShell.

First, we need to figure out the ID of the last successful release

$ProjectId = $OctopusParameters['Octopus.Project.ID']
$EnvironmentId = $OctopusParameters['Octopus.Environment.ID']

$progression = Invoke-RestMethod `
  -Method Get `
  -Uri "$OctopusURL/api/progression/$ProjectId" `
  -Headers @{ "X-Octopus-ApiKey" = $octopusAPIKey }

$lastSuccessfulRelease = $progression.Releases `
  | ? { $_.Deployments.$EnvironmentID -ne $null } `
  | select -ExpandProperty Deployments `
  | select -ExpandProperty $EnvironmentID `
  | ? { $_.State -eq 'Success' } `
  | sort -Descending CompletedTime `
  | select -First 1 `
  | select -ExpandProperty ReleaseId

Next, we create a new deployment referencing that release:

Invoke-RestMethod `
  -Method Post `
  -Uri "$OctopusURL/api/deployments" `
  -Body (@{ ReleaseId = $lastSuccessfulRelease; EnvironmentId = $EnvironmentId } | ConvertTo-Json) `
  -ContentType 'application/json' `
  -Headers @{ "X-Octopus-ApiKey" = $octopusAPIKey }

Configuring Octopus to Run the Script

In order to run the script above, create a step template in your library, based on “Run a Script”. Paste the script above into the “Script Content” box (you can also use the variant in the gist), and add two parameters: OctopusApiKey  and OctopusUrl .

Next, add a deployment step to your project’s deployment process, and reference the script template. Enter the parameter values for the API Key (create one if you haven’t already), and the URL to your octopus server.

Finally, configure the step to run only if a previous step failed.

Retention Policy for Backup Files

If you take a database backup on every deployment and never clean up, your disk will fill up pretty quickly. To prevent that, we apply a retention policy for the backup files using the following script:

  $Folder = $OctopusParameters['Folder'],
  $IncludePattern = $OctopusParameters['IncludePattern'],
  $RetainCount = $OctopusParameters['RetainCount']

Write-Host "Applying retention policy..."

Get-ChildItem "$Folder" -Filter "$IncludePattern" `
| Sort-Object LastWriteTime -Descending `
| Select-Object -Skip $RetainCount `
| % {
	Write-Host "Deleting $_"
    Remove-Item "$Folder\$_"

Write-Host "Done"

Configuring the script to run is done the same way as for the automatic rollback; create a step template and provide the appropriate parameters.

Leave a Reply