ARM Templates - Resource Delay
Delay for Free

ARM Templates - Resource Delay

I really love the ARM templates, how they are structured, their functions and usability. But like with every thing in this world, it can get better and richer - we just have to think of a way to make it so.

There was a time when I needed to put a delay between two resource deployments. Searching the web gave me few results, however, each and everyone of them required a VM/Service deployment for a simple 'Start-Sleep' PowerShell one-liner. This wasn't going to fly, and only because it is an exaggerated way of executing a one-liner. Secondly, because it can eventually cost you more than required or expected. And to add to the frustration, Microsoft itself is not rushing to help you with a native method for now...

For anyone curious about other method please read the following article:

Introducing a Simple, Cheap (free) and Fast Delay method

My quest for the 'Delay' brought me to a simple, yet native way of delaying an ARM template. Only one culprit - it is not so accurate...

It first starts with a resource group dedicated solely to the 'Delay' function. This resource group is free and can have deployments executed in a procedural manner.

Now, when creating a deployment in a template, we will only name it and leave it empty with 0 resources. This way, it will just take time to create a deployment, and literally will not create anything but a cover.

Considering the time it took to create that deployment (between 5 to 10 seconds), we can now multiply it to create a longer creation time.

  • Side-Note: Since the time for a deployment creation is not a constant, this method is not so accurate as a one-liner. On the other hand, there you will need to deploy a service/VM, which takes a random time, and the one-liner extension, which also take the 5-10 seconds if not more to deploy.

To summarize what will be required:

  1. Empty Resource Group
  2. ARM template JSON code for empty deployments
  3. Happiness

The Code

The code is really simple, and uses a 'nested template' approach. It is divided into two parts, as I couldn't get them to run together without assigning it through a blueprint.

First part - Resource Group deployment

{? 
? "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
? ? "contentVersion": "1.0.0.0",
? ? "parameters": {},
? ? "variables": {
? ? ? ? "locationSettings": {
? ? ? ? ? ? "westeurope": {
? ? ? ? ? ? ? ? "abbreviation": "weu"
? ? ? ? ? ? },
? ? ? ? ? ? "switzerlandnorth": {
? ? ? ? ? ? ? ? "abbreviation": "chn"
? ? ? ? ? ? },
? ? ? ? ? ? "eastus2": {
? ? ? ? ? ? ? ? "abbreviation": "eus2"
? ? ? ? ? ? },
? ? ? ? ? ? "eastasia": {
? ? ? ? ? ? ? ? "abbreviation": "ea"
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? "rgLocation": "[resourceGroup().location]",
? ? ? ? "rgName": "[concat('rg-delay-', variables('locationSettings')[resourceGroup().location].abbreviation)]"
? ? },
? ? "resources": [
? ? ? ? {
? ? ? ? ? ? "type": "Microsoft.Resources/deployments",
? ? ? ? ? ? "apiVersion": "2021-04-01",
? ? ? ? ? ? "name": "[concat('DeployRG--', variables('rgName'))]",
? ? ? ? ? ? "location": "[variables('rgLocation')]",
? ? ? ? ? ? "subscriptionId": "[subscription().subscriptionId]",
? ? ? ? ? ? "properties": {
? ? ? ? ? ? ? ? "mode": "Incremental",
? ? ? ? ? ? ? ? "expressionEvaluationOptions": {
? ? ? ? ? ? ? ? ? ? "scope": "Outer"
? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? "template": {
? ? ? ? ? ? ? ? ? ? "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
? ? ? ? ? ? ? ? ? ? "contentVersion": "1.0.0.1",
? ? ? ? ? ? ? ? ? ? "parameters": {},
? ? ? ? ? ? ? ? ? ? "variables": {},
? ? ? ? ? ? ? ? ? ? "resources": [
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? "type": "Microsoft.Resources/resourceGroups",
? ? ? ? ? ? ? ? ? ? ? ? ? ? "apiVersion": "2018-05-01",
? ? ? ? ? ? ? ? ? ? ? ? ? ? "name": "[variables('rgName')]",
? ? ? ? ? ? ? ? ? ? ? ? ? ? "location": "[variables('rgLocation')]",
? ? ? ? ? ? ? ? ? ? ? ? ? ? "properties": {}
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ],
? ? ? ? ? ? ? ? ? ? "outputs": {}
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ]
}        

Second part - Delay loop

{? ? 
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  ? ? "contentVersion": "1.0.0.0",
  ? ? "parameters": {
  ? ? ? ? "counter": {
  ? ? ? ? ? ? "type": "int",
  ? ? ? ? ? ? "defaultValue": 5
  ? ? ? ? }
  ? ? },
  ? ? "variables": {
  ? ? ? ? "locationSettings": {
  ? ? ? ? ? ? "westeurope": {
  ? ? ? ? ? ? ? ? "abbreviation": "weu"
  ? ? ? ? ? ? },
  ? ? ? ? ? ? "switzerlandnorth": {
  ? ? ? ? ? ? ? ? "abbreviation": "chn"
  ? ? ? ? ? ? },
  ? ? ? ? ? ? "eastus2": {
  ? ? ? ? ? ? ? ? "abbreviation": "eus2"
  ? ? ? ? ? ? },
  ? ? ? ? ? ? "eastasia": {
  ? ? ? ? ? ? ? ? "abbreviation": "ea"
  ? ? ? ? ? ? }
  ? ? ? ? },
  ? ? ? ? "rgName": "[concat('rg-delay-', variables('locationSettings')[resourceGroup().location].abbreviation)]"
  ? ? },
  ? ? "resources": [
  ? ? ? ? {
  ? ? ? ? ? ? "type": "Microsoft.Resources/deployments",
  ? ? ? ? ? ? "apiVersion": "2021-04-01",
  ? ? ? ? ? ? "name": "[concat('DelayDeployment--', variables('rgName'))]",
  ? ? ? ? ? ? "resourceGroup": "[variables('rgName')]",
  ? ? ? ? ? ? "properties": {
  ? ? ? ? ? ? ? ? "mode": "Incremental",
  ? ? ? ? ? ? ? ? "expressionEvaluationOptions": {
  ? ? ? ? ? ? ? ? ? ? "scope": "Inner"
  ? ? ? ? ? ? ? ? },
  ? ? ? ? ? ? ? ? "template": {
  ? ? ? ? ? ? ? ? ? ? "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  ? ? ? ? ? ? ? ? ? ? "contentVersion": "1.0.0.0",
  ? ? ? ? ? ? ? ? ? ? "parameters": {
  ? ? ? ? ? ? ? ? ? ? ? ? "counter": {
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? "type": "int"
  ? ? ? ? ? ? ? ? ? ? ? ? }
  ? ? ? ? ? ? ? ? ? ? },
  ? ? ? ? ? ? ? ? ? ? "resources": [
  ? ? ? ? ? ? ? ? ? ? ? ? {
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? "type": "Microsoft.Resources/deployments",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? "apiVersion": "2021-04-01",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? "copy": {
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "count": "[parameters('counter')]",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "name": "delayLoop",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "mode": "Serial",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "batchSize": 1
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? },
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? "name": "[concat('Delay-Loop-', copyIndex('delayLoop'))]",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? "properties": {
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "mode": "Incremental",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "template": {
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "contentVersion": "1.0.0.0",
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "resources": []
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
  ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
  ? ? ? ? ? ? ? ? ? ? ? ? }
  ? ? ? ? ? ? ? ? ? ? ]
  ? ? ? ? ? ? ? ? },
  ? ? ? ? ? ? ? ? "parameters": {
  ? ? ? ? ? ? ? ? ? ? "counter": {
  ? ? ? ? ? ? ? ? ? ? ? ? "value": "[parameters('counter')]"
  ? ? ? ? ? ? ? ? ? ? }
  ? ? ? ? ? ? ? ? }
  ? ? ? ? ? ? }
  ? ? ? ? }
  ? ? ]
  }        

Now lets break it down so it is clearly understood what's the result and how it exactly works.

The deployment works by regions, so there are no parameters to select except a resource group, and counter:

  • The resource group selection is what defines a region - Any resource group will work
  • counter is what defines the delay length

The code has a built-in abbreviation for regions that creates the names for the 'delay' resource groups:

? ? "variables": {
? ? ? ? "locationSettings": {
? ? ? ? ? ? "westeurope": {
? ? ? ? ? ? ? ? "abbreviation": "weu"
? ? ? ? ? ? },
? ? ? ? ? ? "switzerlandnorth": {
? ? ? ? ? ? ? ? "abbreviation": "chn"
? ? ? ? ? ? },
? ? ? ? ? ? "eastus2": {
? ? ? ? ? ? ? ? "abbreviation": "eus2"
? ? ? ? ? ? },
? ? ? ? ? ? "eastasia": {
? ? ? ? ? ? ? ? "abbreviation": "ea"
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? "rgName": "[concat('rg-delay-', variables('locationSettings')[resourceGroup().location].abbreviation)]"
? ? }        

This is an example for 4 regions. It is possible to add more.

  • Tip: To quickly test and run the deployments use 'Template specs' service in Azure. It is very convenient to play with deployments by creating new versions of the templates.

With this method the final result will be a resource group name 'rg-delay-weu' or 'rg-delay-chn', etc.

These variables are present in both deployment scripts, and are used to keep the deployments clean without human errors.

The result of running the first RG deployment will look similar to this:

No alt text provided for this image
No alt text provided for this image

The result of running the 'Delay' deployment will look similar to this:

No alt text provided for this image
No alt text provided for this image

Conclusion and Takeaways

With this method you can easily integrate a delay into any deployment without spending money on expensive services.

Once a 'Delay' resource group is deployed, you will not need to redeploy it each time you use the delay, but make sure it exists in the correct region before trying to delay deployments.

It is possible to bind the delay resource group to a single location, however, that may result in higher deployment delays if the resources are different locations, but that may be something irrelevant and totally subject to individual opinion and use cases.

Lastly, keep the delay resource group clean and separate from everything else. The deployments history shows the deployments like 'Delay-Loop-0', 'Delay-Loop-1', etc. These deployments are replaceable and repeatable, and show only what you need. Deploying other things to the resource group will pollute the log.

要查看或添加评论,请登录

Pavel Rosenberg的更多文章

社区洞察

其他会员也浏览了