Blog Post

Azure Database Support Blog
3 MIN READ

Add wait operation to ARM template deployment

Holger_Linke's avatar
Holger_Linke
Icon for Microsoft rankMicrosoft
Nov 02, 2021

Problem Description:

On the Azure Database for PostgreSQL support team, we recently received reports about failed server deployments. The deployments were initiated through Azure Resource Manager (ARM) JSON templates and then failed when overriding server parameters with user-defined configuration settings.

 

Further analysis showed that the PostgreSQL server instance was created, but then waiting on a backup task to complete. Meanwhile the ARM deployment continued with the next template step. After two minutes it failed the execution because the server instance was still waiting on the background task and unable to process the configuration request.

 

The workaround is to introduce a Wait operation into the ARM template for delaying the script execution until the background task has finished. But this raised the question:

 

How can an ARM JSON template be forced to wait for a specific time?

 

Solution:

The Wait can be achieved by using the deploymentScripts feature; deploymentScripts allows you to inject script commands into the ARM deployment and, for example, execute a PowerShell sleep command.

 

The key is to set the dependencies of the steps correctly. You need to make the wait/sleep operation depend on the preceding deployment step, then have the next deployment step depending on the wait/sleep operation. You usually declare dependencies by referring to the resourceId of the object that was deployed on the preceding step, but you can also use the name of the preceding step.

 

Let me demonstrate this on an excerpt from a PostgreSQL deployment template:

  • The first section is the PG server deployment itself with its required parameters
  • The second section is the deploymentScripts operation, which calls the start-sleep PowerShell cmdlet and requests 300 seconds of wait. Note the dependsOn attribute: it defines that the command is executed after the deployment of the PG server has succeeded.
  • The third section is the configuration of a PG server parameter. It requires that the PG server is available and fails if it is not. Note again the dependsOn attribute: instead of referring to the PG server deployment, it sets the name of the deploymentScripts section. This forces the step to wait until the PowerShell script has finished executing.

 

    "resources": [

    {

        "type": "Microsoft.DBforPostgreSQL/servers",

        "apiVersion": "2017-12-01",

        "name": "[parameters('server_name')]",

        "location": "[parameters('location')]",

        "sku": { ... more config details ...}

        },

    },

    {

      "type": "Microsoft.Resources/deploymentScripts",

      "apiVersion": "2020-10-01",

      "kind": "AzurePowerShell",

      "name": "WaitSection",

      "location": "[parameters('location')]",

      "dependsOn": [

          "[resourceId('Microsoft.DBforPostgreSQL/servers', parameters('server_name'))]"

            ],

      "properties": {

        "azPowerShellVersion": "3.0",

        "scriptContent": "start-sleep -Seconds 300",

        "cleanupPreference": "Always",

        "retentionInterval": "PT1H"

      }

    },

    {

        "type": "Microsoft.DBforPostgreSQL/servers/configurations",

        "apiVersion": "2017-12-01",

        "name": "[concat(parameters('server_name'), '/client_encoding')]",

        "dependsOn": ["WaitSection"],

        "properties": {

            "value": "UTF8",

            "source": "user-override"

        }

    }, ... further template options ...

 

Additional details:

  • During deployment, an additional storage account and a container are created; these will be removed again once the script has completed execution. See Clean up deployment script resources for further details.
  • The deployment will also create a deployment script resource. Its retention is controlled by the retentionInterval property. The example above is using a retention of 1 hour. The property is following the ISO 8601 pattern and the retention interval is between 1 (PT1H) and 26 hours (PT26H). To learn more, see Clean up deployment script resources.

 

References:

Use deployment scripts in ARM templates

https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/deployment-script-template

 

Deployment Scripts for ARM Templates is now Generally Available

https://techcommunity.microsoft.com/t5/azure-governance-and-management/deployment-scripts-for-arm-templates-is-now-generally-available/ba-p/1989172

 

Define the order for deploying resources in ARM templates

Depend on resources in a loop

https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/resource-dependency#depend-on-resources-in-a-loop

 

Updated Nov 02, 2021
Version 2.0
  • Tomasz Olędzki's avatar
    Tomasz Olędzki
    Copper Contributor

    Great idea about using "Microsoft.Resources/deploymentScripts"!

     

    If you're introducing a PS script in your ARM Template, instead hard coding some value in seconds, it would be more elegant and resilient to check the state of your PostgreSQL resource by calling Azure Rest Api?

    https://docs.microsoft.com/en-us/rest/api/postgresql/singleserver/servers/get

     

    Not sure which attribute to check, perhaps when first backup is complete "properties.earliestRestoreDate" is filled? If true, then we could use value in "properties.earliestRestoreDate" as a condition to end PowerShell script and continue ARM Template deployment.

     

    What do you think about this idea?