Implementieren eines Transformers und Collectors für Eigenschaften in eine Azure Resource Manager-Vorlage

Im Artikel Verwenden von Objekten als Parameter in einer Kopierschleife in einer Azure Resource Manager-Vorlage erfahren Sie, wie die Werte von Ressourceneigenschaften in einem Objekt gespeichert und bei der Bereitstellung auf eine Ressource angewendet werden. Dies ist eine sehr gute Möglichkeit, um Ihre Parameter zu verwalten. Bei jeder Verwendung des Objekts in Ihrer Vorlage müssen Sie aber trotzdem weiterhin die Eigenschaften des Objekts den Ressourceneigenschaften zuordnen.

Zur Umgehung dieses Problems können Sie eine Vorlage für die Transformation und Sammlung von Eigenschaften (Transformer und Collector) implementieren, mit der das Objektarray durchlaufen und in das JSON-Schema für die Ressource transformiert wird.

Wichtig

Für diesen Ansatz ist es erforderlich, dass Sie eingehend mit Resource Manager-Vorlagen und -Funktionen vertraut sind.

Sehen wir uns ein Beispiel an, das einen Eigenschaften-Collector und -Transformer für die Bereitstellung einer Netzwerksicherheitsgruppe implementiert. Das folgende Diagramm veranschaulicht die Beziehungen unserer Vorlagen zu den Ressourcen in diesen Vorlagen:

Architektur für Collectors und Transformers für Eigenschaften

Unsere aufrufende Vorlage enthält zwei Ressourcen:

  • Ein Vorlagenlink, über den die Collector-Vorlage aufgerufen wird
  • Die bereitzustellende Ressource der Netzwerksicherheitsgruppe

Unsere Collector-Vorlage enthält zwei Ressourcen:

  • Eine anchor-Ressource
  • Ein Vorlagenlink, über den die Transformer-Vorlage in einer Kopierschleife aufgerufen wird

Unsere Transformer-Vorlage enthält eine einzelne Ressource: eine leere Vorlage mit einer Variablen, die den source-JSON-Code in das JSON-Schema transformiert, der von der Netzwerksicherheitsgruppen-Ressource in der Hauptvorlage erwartet wird.

Parameterobjekt

Wir verwenden unser securityRules-Parameterobjekt aus Verwenden von Objekten als Parameter in einer Kopierschleife in einer Azure Resource Manager-Vorlage. Mit der Transformer-Vorlage wird jedes Objekt im Array securityRules in das JSON-Schema transformiert, das von der Netzwerksicherheitsgruppen-Ressource in unserer aufrufenden Vorlage erwartet wird.

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "networkSecurityGroupsSettings": {
            "value": {
                "securityRules": [
                    {
                        "name": "RDPAllow",
                        "description": "allow RDP connections",
                        "direction": "Inbound",
                        "priority": 100,
                        "sourceAddressPrefix": "*",
                        "destinationAddressPrefix": "10.0.0.0/24",
                        "sourcePortRange": "*",
                        "destinationPortRange": "3389",
                        "access": "Allow",
                        "protocol": "Tcp"
                    },
                    {
                        "name": "HTTPAllow",
                        "description": "allow HTTP connections",
                        "direction": "Inbound",
                        "priority": 200,
                        "sourceAddressPrefix": "*",
                        "destinationAddressPrefix": "10.0.1.0/24",
                        "sourcePortRange": "*",
                        "destinationPortRange": "80",
                        "access": "Allow",
                        "protocol": "Tcp"
                    }
                ]
            }
        }
    }
}

Wir sehen uns zuerst die Transformer-Vorlage an.

Transformer-Vorlage

Die Transformer-Vorlage enthält zwei Parameter, die von der Collector-Vorlage übergeben werden:

  • source ist ein Objekt, das eines der Eigenschaftswertobjekte aus dem Eigenschaftenarray empfängt. In unserem Beispiel wird jedes Objekt aus dem securityRules-Array einzeln übergeben.
  • state ist ein Array, das die verketteten Ergebnisse aller vorherigen Transformationen empfängt. Dies ist die Sammlung mit dem transformierten JSON-Code.

Unsere Parameter sehen wie folgt aus:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "source": {
            "type": "object"
        },
        "state": {
            "type": "array",
            "defaultValue": []
        }
    },

Unsere Vorlage definiert auch eine Variable namens instance, die unser source-Objekt in das erforderliche JSON-Schema transformiert:

"variables": {
    "instance": [
        {
            "name": "[parameters('source').name]",
            "properties": {
                "description": "[parameters('source').description]",
                "protocol": "[parameters('source').protocol]",
                "sourcePortRange": "[parameters('source').sourcePortRange]",
                "destinationPortRange": "[parameters('source').destinationPortRange]",
                "sourceAddressPrefix": "[parameters('source').sourceAddressPrefix]",
                "destinationAddressPrefix": "[parameters('source').destinationAddressPrefix]",
                "access": "[parameters('source').access]",
                "priority": "[parameters('source').priority]",
                "direction": "[parameters('source').direction]"
            }
        }
    ]
}

Abschließend werden in der Ausgabe (output) unserer Vorlage die gesammelten Transformationen des Parameters state mit der aktuellen Transformation verkettet, die von der Variablen instance durchgeführt wird:

"resources": [],
"outputs": {
    "collection": {
        "type": "array",
        "value": "[concat(parameters('state'), variables('instance'))]"
    }
}

Als Nächstes sehen wir uns unsere Collector-Vorlage an, um zu sehen, wie die Parameterwerte übergeben werden.

Collector-Vorlage

Die Collector-Vorlage enthält drei Parameter:

  • source ist unser vollständiges Parameterobjektarray. Es wird von der aufrufenden Vorlage übergeben. Es weist den gleichen Namen wie der source-Parameter in unserer Transformer-Vorlage auf. Es gibt jedoch einen wichtigen Unterschied: Obwohl es sich um das vollständige Array handelt, wird jeweils nur ein Arrayelement an die Transformer-Vorlage übergeben.
  • transformTemplateUri ist der URI der Transformer-Vorlage. Wir definieren ihn als Parameter, um die Vorlage wiederverwenden zu können.
  • state ist ein ursprünglich leeres Array, das wir an die Transformer-Vorlage übergeben. Darin wird die Sammlung mit den transformierten Parameterobjekten gespeichert, nachdem die Kopierschleife beendet wurde.

Unsere Parameter sehen wie folgt aus:

"parameters": {
    "source": {
        "type": "array"
    },
    "transformTemplateUri": {
        "type": "string"
    },
    "state": {
        "type": "array",
        "defaultValue": []
    }
}

Als Nächstes definieren wir eine Variable mit dem Namen count. Ihr Wert ist die Länge des Parameterobjektarrays source:

"variables": {
    "count": "[length(parameters('source'))]"
}

Wir verwenden sie für die Anzahl von Iterationen in unserer Kopierschleife.

Wir sehen uns nun die Ressourcen an. Es werden zwei Ressourcen definiert:

  • loop-0 ist die nullbasierte Ressource für unsere Kopierschleife.
  • loop- wird mit dem Ergebnis der Funktion copyIndex(1) verkettet, um einen eindeutigen iterationsbasierten Namen für die Ressource zu generieren, der mit 1 beginnt.

Unsere Ressourcen sehen wie folgt aus:

"resources": [
    {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2015-01-01",
        "name": "loop-0",
        "properties": {
            "mode": "Incremental",
            "parameters": { },
            "template": {
                "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": { },
                "variables": { },
                "resources": [ ],
                "outputs": {
                    "collection": {
                        "type": "array",
                        "value": "[parameters('state')]"
                    }
                }
            }
        }
    },
    {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2015-01-01",
        "name": "[concat('loop-', copyindex(1))]",
        "copy": {
            "name": "iterator",
            "count": "[variables('count')]",
            "mode": "serial"
        },
        "dependsOn": [
            "loop-0"
        ],
        "properties": {
            "mode": "Incremental",
            "templateLink": { "uri": "[parameters('transformTemplateUri')]" },
            "parameters": {
                "source": { "value": "[parameters('source')[copyindex()]]" },
                "state": { "value": "[reference(concat('loop-', copyindex())).outputs.collection.value]" }
            }
        }
    }
]

Lassen Sie uns einen genaueren Blick auf die Parameter werfen, die an die Transformer-Vorlage in der geschachtelten Vorlage übergeben werden. Sie erinnern sich, dass mit dem Parameter source das aktuelle Objekt im Parameterobjektarray source übergeben wird. Die Sammlung erfolgt im state-Parameter, da er die Ausgabe der vorherigen Iteration der Kopierschleife übernimmt und an die aktuelle Iteration übergibt. Beachten Sie, dass die reference()-Funktion die copyIndex() Funktion ohne Parameter verwendet, um auf das name-Element des vorherigen verknüpften Vorlagenobjekts zu verweisen.

Abschließend gibt die Ausgabe (output) unserer Vorlage die Ausgabe (output) des letzten Durchlaufs unserer Transformer-Vorlage zurück:

"outputs": {
    "result": {
        "type": "array",
        "value": "[reference(concat('loop-', variables('count'))).outputs.collection.value]"
    }
}

Es kann ungewöhnlich erscheinen, dass die Ausgabe (output) der letzten Iteration der Transformer-Vorlage an die aufrufende Vorlage übergeben wird, da sie anscheinend im Parameter source gespeichert wurde. Allerdings handelt es sich um die letzte Iteration der Transformer-Vorlage, die das gesamte Array mit den Eigenschaftsobjekten enthält, und dass dies die Daten sind, die wir zurückgeben möchten.

Zum Schluss sehen wir uns noch an, wie die Collector-Vorlage aus der aufrufenden Vorlage aufgerufen wird.

Aufrufende Vorlage

Mit der aufrufenden Vorlage wird ein einzelner Parameter mit dem Namen networkSecurityGroupsSettings definiert:

...
"parameters": {
    "networkSecurityGroupsSettings": {
        "type": "object"
    }
}

Als Nächstes definiert unsere Vorlage eine einzelne Variable mit dem Namen collectorTemplateUri:

"variables": {
    "collectorTemplateUri": "[uri(deployment().properties.templateLink.uri, 'collector.template.json')]"
}

Dies ist der URI für die Collector-Vorlage, die von der verknüpften Vorlagenressource verwendet wird:

{
    "apiVersion": "2020-06-01",
    "name": "collector",
    "type": "Microsoft.Resources/deployments",
    "properties": {
        "mode": "Incremental",
        "templateLink": {
            "uri": "[variables('collectorTemplateUri')]",
            "contentVersion": "1.0.0.0"
        },
        "parameters": {
            "source": {
                "value": "[parameters('networkSecurityGroupsSettings').securityRules]"
            },
            "transformTemplateUri": {
                "value": "[uri(deployment().properties.templateLink.uri, 'transform.json')]"
            }
        }
    }
}

Wir übergeben zwei Parameter an die Collector-Vorlage:

  • source ist unser Eigenschaftsobjektarray. In unserem Beispiel ist dies der Parameter networkSecurityGroupsSettings.
  • transformTemplateUri ist die Variable, die wir soeben mit dem URI der Collector-Vorlage definiert haben.

Zuletzt weist die Ressource Microsoft.Network/networkSecurityGroups die Ausgabe (output) der verknüpften Vorlagenressource collector direkt der dazugehörigen securityRules-Eigenschaft zu:

"resources": [
    {
        "apiVersion": "2020-05-01",
        "type": "Microsoft.Network/networkSecurityGroups",
        "name": "networkSecurityGroup1",
        "location": "[resourceGroup().location]",
        "properties": {
            "securityRules": "[reference('collector').outputs.result.value]"
        }
    }
],
"outputs": {
    "instance": {
        "type": "array",
        "value": "[reference('collector').outputs.result.value]"
    }
}

Testen der Vorlage

Eine Beispielvorlage finden Sie auf GitHub. Klonen Sie zum Bereitstellen der Vorlage das Repository, und führen Sie die folgenden Befehle der Azure-Befehlszeilenschnittstelle aus:

git clone https://github.com/mspnp/template-examples.git
cd template-examples/example4-collector
az group create --location <location> --name <resource-group-name>
az deployment group create -g <resource-group-name> \
    --template-uri https://raw.githubusercontent.com/mspnp/template-examples/master/example4-collector/deploy.json \
    --parameters deploy.parameters.json

Nächste Schritte