if…then in ARM Templates


(auch verfügbar in Deutsch)

When working with ARM Templates you sometimes hit a point where you wish to have something like if...then, or, in other words, conditional deployments. Well, actually there are ways to do this, and here is how

Condition

The probably easiest way is to use the condition element for a resource. When you describe a resource in your JSON template file, simply place it somewhere inside the resource definition, like here:

      "condition": "<true-or-false>",
      "type": "<rpnamespace/type>",
      "apiVersion": "<api-version>",
...

It is as simple as it looks: Whenever the expression after the condition-element expands to true, the resource defined in this block will be deployed (well, if the rest of the template syntax is correct etc...), or not deployed. Here is an often used example:

    "condition": "[equals(parameters('sshOrPW'),'password')]",
    "apiVersion": "2016-03-30",
    "type": "Microsoft.Compute/virtualMachines",
    ...
},
{
    "condition": "[equals(parameters('sshOrPW'),'ssh')]",
    "apiVersion": "2016-03-30",
    "type": "Microsoft.Compute/virtualMachines",
    ...
},

All we need now is a parameter named sshOrPW with two possible values. The correct parameter section is left as an exercise to the reader...

We are using here a template function, equals. This function expands to True if both arguments are equal (whow, who would have thought that?), otherwise to False. So when we fill the parameter sshOrPW with "password", only the first resource is deployed, the second is ignored. And the other way round, of course. Pretty easy, or? But be warned: Watch out if you have more then one conditionally deployed resource, especially when there is a dependency between. It might be hard to track your template design. Luckily, there is a second way, especially when you have a set of resources to be deployed depending on a condition, and that is with nested templates.

Nested templates

You might have never used it, but you can use more then one template and call them from within another template. That's called nested templates, and uses the resource type Microsoft.Resources/deployments. You define a name and some properties, and within the properties there is the link to the other template, templatelink. Find more about this on AzureDocs.

  { 
      "apiVersion": "2017-05-10", 
      "name": "linkedTemplate", 
      "type": "Microsoft.Resources/deployments", 
      "properties": { 
        "mode": "incremental", 
        "templateLink": {
          "uri": "[variables('subnetTemplate')]",
          "contentVersion": "1.0.0.0"
        }, 
        "parameters": { 
          ... 
        } 
      } 
  } 

The idea to make this conditional is to call template A or template B, depending on the value of a variable or parameter. Got it? Let's make an example, again with subnets. You find the templates for download in my GitHub repository or use it directly from there (as shown below). First we need a parameter to decide if we should deploy a subnet or not:

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
      "subnetYesNo":{
          "type": "string",
          "defaultValue": "Yes",
          "allowedValues": [
              "Yes",
              "No"
          ]
      }
  },

We need the links to the alternative templates, and we store them in a variable. We also name our deployment depending on the parameter input, that looks nicer.

  "variables": {
    "subnetTemplate": "[concat('https://raw.githubusercontent.com/gitralf/templates/master/test-conditional/deploysubnet-',toLower(parameters('subnetYesNo')),'.json')]",
    "subnetTemplateName": "[concat('Subnet-',parameters('subnetYesNo'))]",
  },

Here a closer look at the main part:

"[concat('https://.../test-conditional/deploysubnet-',toLower(parameters('subnetYesNo')),'.json')]"

We used the functions concat and toLower here. I'm pretty sure you know what they do (if not, read here). So we build the template URI by integrating the parameter into the filename. Depending on the input we are now calling a template subnetTemplate, which is either ending in deploysubnet-yes.json or deploysubnet-no.json:

  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2015-01-01",
      "name": "[variables('subnetTemplateName')]",
      "properties": {
        "mode": "Incremental",
        "templateLink": { "uri": "[variables('subnetTemplate')]" },
      }
    }
  ],
  "outputs": {
  }
}

For this simple test we create identical (empty) templates with the names created above and start the deployment with the -Verbose commandline switch. We see something like this:

PS C:\temp> New-AzureRmResourceGroupDeployment -subnetYesNo No -verbose -Name "conditional02" -ResourceGroupName vstest1-mcd
 -TemplateUri "https://raw.githubusercontent.com/gitralf/templates/master/test-conditional/azuredeploy.json"

AUSFÜHRLICH: Ausführen des Vorgangs "Creating Deployment" für das Ziel "vstest1-mcd".
AUSFÜHRLICH: 14:37:04 - Template is valid.
AUSFÜHRLICH: 14:37:05 - Create template deployment 'conditional02'
AUSFÜHRLICH: 14:37:05 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 14:37:10 - Resource Microsoft.Resources/deployments 'Subnet-No' provisioning status is running
AUSFÜHRLICH: 14:37:10 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 14:37:15 - Resource Microsoft.Resources/deployments 'Subnet-No' provisioning status is succeeded

DeploymentName          : conditional02
ResourceGroupName       : vstest1-mcd
ProvisioningState       : Succeeded
Timestamp               : 10.08.2017 12:37:14
Mode                    : Incremental
TemplateLink            :
Parameters              :
                          Name             Type                       Value
                          ===============  =========================  ==========
                          subnetYesNo      String                     No

As we see, the nested deployment "Subnet-No" was called as expected.

To be continued...

There are other ways to decide wether or not to call a template. For example, fill an array with the alternative URIs, and then use some math tricks to calculate the index and use that array element (see my next article). But the basic idea is always the same: call a nested template with different URLs.

Enough for today. But stay tuned for other articles from the world of Azure Resource Manager Templates! Coming soon.

Meanwhile why not signing up for a free trial to Azure? Here is the link to Azure Germany...


Comments (2)

  1. Sadly this is not “really” an if-then in ARM templates due to the name being a key property in ARM templates that can conflict.
    I made a post about this earlier here: https://social.msdn.microsoft.com/Forums/azure/en-US/a6ab05e0-cad2-4a57-82cb-f97d4eb62c40/why-do-i-get-a-naming-conflict-when-i-provide-a-condition-element-in-my-arm-code?forum=WAVirtualMachinesforWindows

    You could use unique names to get around it, however a “real” if-then function in ARM templates would be major, as this would make templates much more compact.

    1. RalfWi says:

      As you said, sadly this is true. It seems ARM does not evaluate the condition during validation check. Have you tried the second alternative with nested templates?

Skip to main content