another if...then in ARM templates

(auch verfügbar in Deutsch)

As promised in my last article about ARM templates here is another way to trigger a deployment based on a condition. We again use the idea of having nested deployments, but this time we fill an array with alternative template links and decide - based on math - which one to use.

In this example we want to decide if an availability set should be created or not. This obviously only makes sense when we have more than one VM, so this will be our condition. But how to use it? There is nothing like if (vmCount -gt 1) then.... Well, here is the trick (and thanks to the AzureCAT buildingblock templates for the idea). There is a function called "mod", which stands for the latin "modulo" and returns the rest when you divide two numbers. For example, when you divide "8" by "5", you get "1" and a rest of "3", so mod(8,5)=3. How does this help us? Easy. When you divide a number by the next smaller one, you always get a rest of "1", except when the first number is a "2". See here:

[code gutter="false"]
mod(2,1)=0
mod(3,2)=1
mod(4,3)=1
mod(5,4)=1
...

No matter what your number is, when you use the "mod" function with the next smaller number, you either get "0" or "1". Any idea, how to go on? You should! I already taked about using an array, and here we have something that we can use as an index... Have a look at this part of a template (available on GitHub with the rest for this demo):
[code]
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vmCount": {
"type": "int"
}
},

"variables": {
"index": "[mod(add(parameters('vmCount'), 1), parameters('vmCount'))]",
"avSetTemplates": [
"[uri(deployment().properties.templateLink.uri, 'availabilitySet-empty.json')]",
"[uri(deployment().properties.templateLink.uri, 'availabilitySet-new.json')]"
],
"avSetTemplate": "[variables('avSetTemplates')[variables('index')]]",
"templateNamePart": [
"nop",
"new"
],
"deploymentName": "[variables('templateNamePart')[variables('index')]]"
},

Don't be shocked when you don't understand it first, we go through it here. This awesome trick is worth it...

We have a parameter "vmCount" as an integer (line 5-7). When we enter "1" as number of VMs, we don't need an availability set, but for "vmCount" greater than "1" we want it. The first variable we create is "index" (line 11). We add "1" to "vmCount" and divide it by "vmCount". According to our table this gives us a "0" when vmCount is "1" (mod(1+1,1)=0) or "1" (mod(2+1,2)=1) when "vmCount" is greater than "1".

Next step (lines 12-15) is to define an array of alternative URLs, based on the current URL. For our example we (like in the last article) use two empty templates and name them "availabilitySet-empty.json" (this would be the empty template to do nothing) and "availabilitySet-new.json" (which would normally hold the definition for the availability set - in our example it is empty, too).

Now we put it together (line 16) and define the next template where the deployment should continue as the element in this array with the index that we calculated, and store it in variable "avSetTemplate" (without the "s" at the end). And (line 17-21) we define a deployment name also based on an array using the same index again. Here is the rest of the template:

[code firstline="24"]
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"name": "[variables('deploymentName')]",
"properties": {
"mode": "Incremental",
"templateLink": { "uri": "[variables('avSetTemplate')]" },
"parameters": {
}
}
}
],

"outputs": {
}
}

Time for a (verbose) test...

[code gutter="false" highlight="1,2,8"]
PS C:\temp> New-AzureRmResourceGroupDeployment -vmcount 1 -verbose -Name "conditional11" -ResourceGroupName vstest1-mcd
-TemplateUri "https://raw.githubusercontent.com/gitralf/templates/master/test-conditional-2/azuredeploy.json"

AUSFÜHRLICH: Ausführen des Vorgangs "Creating Deployment" für das Ziel "vstest1-mcd".
AUSFÜHRLICH: 10:45:40 - Template is valid.
AUSFÜHRLICH: 10:45:40 - Create template deployment 'conditional11'
AUSFÜHRLICH: 10:45:40 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 10:45:45 - Resource Microsoft.Resources/deployments 'nop' provisioning status is running
AUSFÜHRLICH: 10:45:45 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 10:45:51 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 10:45:56 - Resource Microsoft.Resources/deployments 'nop' provisioning status is succeeded

DeploymentName : conditional11
ResourceGroupName : vstest1-mcd
ProvisioningState : Succeeded
Timestamp : 15.08.2017 08:45:52
Mode : Incremental
TemplateLink :
Uri : https://raw.githubusercontent.com/gitralf/templates/master/test-conditional-2/azuredeploy.json
ContentVersion : 1.0.0.0

Parameters :
Name Type Value
=============== ========================= ==========
vmCount Int 1

We set the "vmCount" to "1", so no availability set was needed (deployment "nop"). Using a "vmCount" of "2" (or "42") gives us:

[code gutter="false" highlight="1,2,8"]
PS C:\temp> New-AzureRmResourceGroupDeployment -vmcount 2 -verbose -Name "conditional11" -ResourceGroupName vstest1-mcd
-TemplateUri "https://raw.githubusercontent.com/gitralf/templates/master/test-conditional-2/azuredeploy.json"

AUSFÜHRLICH: Ausführen des Vorgangs "Creating Deployment" für das Ziel "vstest1-mcd".
AUSFÜHRLICH: 10:46:11 - Template is valid.
AUSFÜHRLICH: 10:46:12 - Create template deployment 'conditional11'
AUSFÜHRLICH: 10:46:12 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 10:46:17 - Resource Microsoft.Resources/deployments 'new' provisioning status is running
AUSFÜHRLICH: 10:46:17 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 10:46:22 - Checking deployment status in 5 seconds
AUSFÜHRLICH: 10:46:28 - Resource Microsoft.Resources/deployments 'new' provisioning status is succeeded

DeploymentName : conditional11
ResourceGroupName : vstest1-mcd
ProvisioningState : Succeeded
Timestamp : 15.08.2017 08:46:27
Mode : Incremental
TemplateLink :
Uri : https://raw.githubusercontent.com/gitralf/templates/master/test-conditional-2/azuredeploy.json
ContentVersion : 1.0.0.0

Parameters :
Name Type Value
=============== ========================= ==========
vmCount Int 2

As expected the deployment "new" was used, since we want an availability set here.

That's it. I'm sure that - together with the last article about if...then in ARM templates - you will find ways to use this nice little trick, and again thanks to the AzureCAT team for demonstrating it.

If you want to test it and you are one of the few guys out there without an Azure subscription, here for example is where you get a free Azure Germany trial!