Bedingte Verzweigungen Teil 2

(also available in english)

Wie angekündigt in meinem letzten Artikel zu ARM Templates folgt hier eine weitere Möglichkeit, in einem ARM Template zu verzweigen, basierend auf einer Bedingung. Wir verwenden wieder die Idee mit den verschachtelten Deployments, aber diesmal füllen wir einen Array mit alternativen URLs und entscheiden uns - mit etwas Mathe-Magie - für eines der Arrayelemente.

Für unser Beispiel möchten wir uns zwischen einem Availability Set (bei mehr als einer VM) oder keinem Availability Set (bei nur einer VM) entscheiden. Die Bedingung ist also klar. Aber leider gibt es sowas wie if (vmCount -gt 1) then... hier nicht. Ok, hier ist der Trick (und Danke an AzureCAT für die Demonstration in den buildingblock templates ). Es gibt eine Funktion namens "mod", steht für das lateinische "modulo", und liefert den Rest bei einer Division zweier ganzer Zahlen. Wenn man zum Beispiel "8" durch "5" teilt, dann ergibt das "1" und ein Rest von "3", eben mod(8,5)=3. Wie uns das hilft? Ganz einfach. Teilt man eine Zahl durch die nächstkleinere, dann ergibt das immer einen Rest von "1", außer die erste Zahl ist eine "2". Wie man hier sehen kann:

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

Also ganz egal, was unsere Zahl ist, wir bekommen entweder eine "0" oder eine "1". Und jetzt? Na, bitte mitdenken! Ich hab doch oben schon verraten, dass wir mit einem Array arbeiten wollen, und hier haben wir etwas, dass sich prima als Index eignet...

Hier mal der erste Teil des Templates (gibt es auch auf GitHub mit dem Rest für diese 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')]]"
},

Keine Panik! Wir schauen uns das im Einzelnen an, dieser nette Trick ist es wert...

Wir haben einen Parameter "vmCount" als Integer (Zeilen 5-7). Geben wir eine "1" vor, dann brauchen wir kein Availability Set, aber für alles größer als "1" wollen wir das. Die erste Variable, die wir definieren, ist "index" (Zeile 11), und die regelt das. Wir addieren "1" zu "vmCount", teilen durch "vmCount", und erhalten als Rest (wir erinnern uns an unserer Tabelle von oben) eine "0" bei "vmCount" von "1" (mod(1+1,1)=0) oder eine "1", wenn "vmCount" größer als "1" ist (mod(2+1,2)=1).

Als nächstes definieren wir einen Array mit den alternativen URLs, basierend auf der aktuellen URL. Für unser Beispiel verwenden wir das Template "availabilitySet-empty.json" (ein leeres Template, wir wollen ja nix tun) und "availabilitySet-new.json" (hier würde dann die Definition für das Availability Set stehen - in unserem Beispiel ist das aber ebenfalls leer).

Jetzt fügen wir alles zusammen (Zeile 16) und definieren das nächste zu verwendende Template als das Element aus dem Array mit dem Index, den wir gerade ausgerechnet haben. Wir speichern das in der Variable "avSetTemplate" (ohne "s" am Ende). Und (Zeilen 17-21) dann definieren wir noch einen Deployment Namen, der auf dem gleichen Index basiert. Hier ist der Rest des Templates:

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

"outputs": {
}
}

Zeit für einen (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

"vmCount" haben wir in der Kommandozeile auf "1" gesetzt, wir brauchen also kein Availability Set (Deployment "nop"). Setzen wir "vmCount" auf "2", erhalten wir:

[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

Wie erwartet wird das Deployment "new" verwendet.

Das war's auch schon. Ich bin mir sicher, dass - zusammen mit meinem anderen Artikel zu Bedingten Verzweigungen in ARM Templates - der Weg offen steht für neue Templates und Deployments. Und nochmal Danke an AzureCAT!

Wer das testen möchte und zu den wenigen gehört, die noch kein Azure Account haben, hier ist zum Beispiel ein Link zu einem kostenlosen Testabo für Azure Deutschland.