Batman does not deploy again. He rolls back like a boss.

How to roll back an Azure IoT Edge layered deployment?

This post was most recently updated on November 24th, 2022.

3 min read.

Have you ever wondered how you could roll back the latest layered Azure IoT Edge deployment? I have – it’s actually pretty useful. But what for?

Well, perhaps it’s useful as the last step or whatever interesting Azure DevOps pipelines you have to deploy changes to an Edge device, run tests, and then remove the deployment. You could possibly have it as an optional parameter in case you want to do a dry run for the deployment – see if everything works well but not actually leave your stuff on the device. Or, perchance, it could be used as a separate pipeline that you can run when you notice that your malformed, and completely broken, manifest was deployed to an environment that then proceeded to not function quite as expected. And to be fair, the same Azure CLI commands that I’ve added into the AzureCLI task in my YAML below can simply be run in your terminal of choice to remove the deployment without involving Azure DevOps at all!

So many options! So much YAML!

Solution

Let’s get to it, then!

We built a simple template for rolling back the latest deployment for any single module. We especially wanted to figure out the latest deployment by creation time from all deployments deployed to a target environment (a JMESPATH query) and remove it from the IoT Hub.

So, long story short here’s the code, and a bit below you can find the solution as to what it is and how it works!

YAML for a rollback step template:

parameters:
- name: sub
  type: string
  displayName: Name of the subscription to use
- name: connection
  type: string
  displayName: Azure Subscription Service Connection to use
- name: iothub
  type: string
  displayName: Name of the IoT Hub to use for the deployment
- name: imageName
  type: string
  displayName: Image Name of the container that the module-to-be-deployed uses - this string is used to query for old deployments (to tell deployments for different modules apart from one another)
- name: target
  type: string
  displayName: Target Condition for your deployment

steps:

- task: AzureCLI@2
  displayName: ${{ parameters.targetLocation }} (${{ parameters.targetEnvironment }}) - Roll back the latest Edge deployment using az CLI
  inputs:
    azureSubscription: ${{ parameters.connection }}
    scriptType: 'pscore'
    scriptLocation: 'inlineScript'
    inlineScript: |
      az config set extension.use_dynamic_install=yes_without_prompt
      az account set --subscription "${{ parameters.sub }}"
      $latestDeploymentId = az iot edge deployment list -n ${{ parameters.iothub }} --query "reverse(sort_by([? targetCondition!=null && your-JMESPATH-Query-using-${{parameters.target }})], &createdTimeUtc))|[*]|[0]|[id][0]"
      az iot edge deployment delete -n ${{ parameters.iothub }} -d $latestDeploymentId
    addSpnToEnvironment: true
    useGlobalConfig: true

And then you can use this template from your pipeline shown below:

- ${{ if eq(parameters.rollback, true) }}:
    - stage: Rollback
      dependsOn:
      displayName: Roll back 

      jobs:

      - job: RollbackDeployment
        displayName: Roll back 

        pool:
          vmImage: $(Your.Pool)

        steps:

        - template: ci/Tasks/Rollback.yml
          parameters:
            sub: $(Your.SubscriptionName)
            connection: $(Your.ServiceConnectionId)
            iothub: $(Your.IoTHubName)
            imageName: $(Your.ImageName)
            target: $(Your.TargetCondition)

But what kind of configuration do we need to make use of this template? Let’s see…

Time needed: 20 minutes

How to roll back an Azure IoT Edge deployment in Azure DevOps Pipelines?

  1. Create your pipeline

    Creating the pipeline is your first step. It doesn’t really matter how and where you do that, but this guide presumes you’ll create the YAML file for the pipeline to the root of the project.

  2. (OPTIONAL) Define a pipeline parameter for your rollback

    You will now need a pipeline parameter for rollback – because we’ll want it to be optional (not every build needs to be a rollback after all!)

    Add this at the top of your pipeline YAML:
    parameters:
    - name: rollback
    displayName: Roll back?
    type: boolean
    default: false


    If you want to roll back after each deployment (after running tests, for example), simply ignore this step.

  3. Add your rollback template file

    We’ll be adding a new file for the rollback template (see the YAML above).

    In my example, we have the pipeline YAML files in the root of the repository and all YAML templates in a folder structure like ci/{templatetype}/{templatename}.yml

    So let’s add a new file to path ci/Tasks/Rollback.yml, and paste the content from the YAML above to it.

  4. Add your rollback step

    When you have the files (1 for your pipeline, one for your rollback template), you can add the step to your pipeline. If you want to have the step as optional (something you can select for each run of your pipeline), you can wrap it in:
    - ${{ if eq(parameters.rollback, true) }}:

    Otherwise, it’ll just be something like this:
    - template: ci/Tasks/Rollback.yml
    parameters:
    sub: $(Your.SubscriptionName)
    connection: $(Your.ServiceConnectionId)
    iothub: $(Your.IoTHubName)
    imageName: $(Your.ImageName)
    target: $(Your.TargetCondition)


Et voilà ! Hopefully, it’s clear and helpful enough. Let me know in any case!

References

mm
0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments