Implementera en egenskapsomvandel och insamlare i Azure Resource Manager mall

I Använda ett objekt som en parameter i en Azure Resource Manager mallhar du lärt dig att lagra resursegenskapsvärden i ett objekt och tillämpa dem på en resurs under distributionen. Detta är ett mycket användbart sätt att hantera parametrarna, men det kräver fortfarande att du mappar objektets egenskaper till resursegenskaper varje gång du använder det i mallen.

Du kan komma runt detta genom att implementera en egenskapstransform och en insamlarmall som itererar objektmatrisen och transformerar den till det JSON-schema som förväntas av resursen.

Viktigt

Den här metoden kräver att du har en djup förståelse Resource Manager mallar och funktioner.

Låt oss ta en titt på hur vi kan implementera en egenskapsinsamlare och transformering med ett exempel som distribuerar en nätverkssäkerhetsgrupp. Diagrammet nedan visar relationen mellan våra mallar och våra resurser i dessa mallar:

arkitektur för egenskapsinsamlare och transformering

Vår anropsmall innehåller två resurser:

  • En malllänk som anropar vår insamlarmall.
  • Nätverkssäkerhetsgruppens resurs som ska distribueras.

Vår insamlingsmall innehåller två resurser:

  • En fästpunktsresurs.
  • En malllänk som anropar transformeringsmallen i en kopieringsloop.

Vår transformeringsmall innehåller en enskild resurs: en tom mall med en variabel som omvandlar vår JSON till det JSON-schema som förväntas av nätverkssäkerhetsgruppens resurs i huvudmallen.

Parameterobjekt

Vi använder parameterobjektet securityRules från objekt som securityRules. Vår transformeringsmall omvandlar varje objekt i matrisen till det JSON-schema som förväntas av nätverkssäkerhetsgruppens resurs i vår anropande mall.

{
    "$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"
                    }
                ]
            }
        }
    }
}

Låt oss titta på vår transformeringsmall först.

Transformera mall

Vår transformeringsmall innehåller två parametrar som skickas från insamlarmallen:

  • source är ett objekt som tar emot ett av egenskapsvärdets objekt från egenskapsmatrisen. I vårt exempel skickas varje objekt "securityRules" från matrisen i ett i taget.
  • state är en matris som tar emot de sammanfogade resultaten från alla tidigare transformeringar. Det här är samlingen med transformerade JSON.

Våra parametrar ser ut så här:

{
    "$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": []
        }
    },

Vår mall definierar också en variabel med namnet instance . Den utför den faktiska transformeringen av objektet source till det JSON-schema som krävs:

"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]"
            }
        }
    ]
}

Slutligen sammanfogar för vår mall de insamlade transformeringarna av parametern med den aktuella outputstate transformeringen som utförs av instance variabeln:

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

Nu ska vi ta en titt på vår insamlarmall för att se hur den skickar in våra parametervärden.

Mall för insamlare

Vår insamlarmall innehåller tre parametrar:

  • source är vår fullständiga parameterobjektmatris. Den skickas via den anropande mallen. Detta har samma namn som parametern i vår transformeringsmall, men det finns en viktig skillnad som du kanske redan har märkt: det här är den fullständiga matrisen, men vi skickar bara ett element i matrisen till transformeringsmallen source i taget. source
  • transformTemplateUri är URI:en för vår transformTemplateUri. Vi definierar det som en parameter här för återanvändning av mallar.
  • state är en ursprungligen tom matris som vi skickar till state. Den lagrar samlingen med transformerade parameterobjekt när kopieringsloopen är klar.

Våra parametrar ser ut så här:

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

Därefter definierar vi en variabel med namnet count . Dess värde är längden på source parameterobjektmatrisen:

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

Som du misstänker använder vi den för antalet iterationer i vår kopieringsloop.

Nu ska vi ta en titt på våra resurser. Vi definierar två resurser:

  • loop-0 är den nollbaserade resursen för vår kopieringsloop.
  • loop- sammanfogas med resultatet av funktionen för att generera ett unikt iterationsbaserat namn för vår resurs, med copyIndex(1) början från 1 .

Våra resurser ser ut så här:

"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]" }
            }
        }
    }
]

Låt oss ta en närmare titt på de parametrar som vi vidarebefordrar till transformeringsmallen i den kapslade mallen. Kom ihåg att parametern source skickar det aktuella objektet i source parameterobjektmatrisen. Parametern är den plats där samlingen sker, eftersom den tar utdata från den tidigare iterationen av vår kopieringsloop – observera att funktionen använder funktionen utan parameter för att referera till för vårt tidigare länkade mallobjekt – och skickar den till den aktuella statereference()copyIndex()name iterationen.

Slutligen returnerar output för vår mall den senaste output iterationen av output:

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

Det kan verka kontraintuitivt att returnera den senaste iterationen av transformeringsmallen till vår anropande mall eftersom den visade sig att vi lagrar den output i output parametern. Kom dock ihåg att det är den senaste iterationen av vår transformeringsmall som innehåller hela matrisen med transformerade egenskapsobjekt, och det är vad vi vill returnera.

Slutligen tar vi en titt på hur du anropar insamlarmallen från vår anropande mall.

Anropa mall

Vår anropsmall definierar en enda parameter med namnet :

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

Sedan definierar mallen en enskild variabel med namnet collectorTemplateUri :

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

Som förväntat är detta URI:en för insamlarmallen som ska användas av vår länkade mallresurs:

{
    "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')]"
            }
        }
    }
}

Vi skickar två parametrar till insamlarmallen:

  • source är vår egenskapsobjektmatris. I vårt exempel är det vår networkSecurityGroupsSettings parameter.
  • transformTemplateUri är variabeln som vi precis definierade med URI:en för vår transformTemplateUri.

Slutligen Microsoft.Network/networkSecurityGroups tilldelar vår resurs den länkade outputcollector mallresursens egenskap securityRules direkt:

"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]"
    }
}

Testa mallen

En exempelmall finns på GitHub. Om du vill distribuera mallen klonar du lagringsplatsen och kör följande Azure CLI-kommandon:

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