Compartilhar via


Implementar um transformador de propriedade e um coletor em um modelo do Azure Resource Manager

No artigo Usar um objeto como um parâmetro em um modelo do Azure Resource Manager, você viu como armazenar valores de propriedade de recurso em um objeto e como aplicá-los a um recurso durante a implantação. Esta é uma maneira muito útil para gerenciar os parâmetros, mas requer que você mapeie as propriedades do objeto para propriedades de recursos sempre que você usar o objeto em seu modelo.

Para resolver esse problema, você pode implementar uma transformação de propriedade e um modelo de coletor que itere sua matriz de objeto e a transforme no esquema JSON do recurso.

Importante

Essa abordagem requer que você tenha uma compreensão profunda dos modelos e das funções do Resource Manager.

Vamos dar uma olhada em um exemplo que implementa um coletor de propriedade e um transformador para implantar um grupo de segurança de rede. O diagrama abaixo mostra como nossos modelos estão relacionados aos recursos nesses modelos:

property collector and transformer architecture

Nosso modelo de chamada inclui dois recursos:

  • Um link de modelo que invoca nosso modelo de coletor.
  • O recurso de grupo de segurança de rede a ser implantado

Nosso modelo de coletor inclui dois recursos:

  • um recurso de âncora
  • Um link de modelo que invoca o modelo de transformação em um loop de cópia

Nosso modelo de transformação inclui apenas um recurso: um modelo vazio com uma variável que transforma nosso source JSON no esquema JSON esperado por nosso recurso de grupo de segurança de rede no modelo principal.

Objeto Parameter

Usamos nosso securityRules objeto de parâmetro de Usar objetos como parâmetros em um loop de cópia em um modelo do Azure Resource Manager. Nosso modelo de transformação transforma cada objeto na securityRules matriz no esquema JSON esperado pelo recurso de grupo de segurança de rede em nosso modelo de chamada.

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

Vamos examinar nosso modelo de transformação.

Modelo de Transformação

Nosso modelo de transformação inclui dois parâmetros que são passados do modelo de coletor:

  • source é um objeto que recebe um dos objetos de valor de propriedade da matriz de propriedade. Em nosso exemplo, cada objeto da securityRules matriz será transmitido um de cada vez.
  • state é uma matriz que recebe os resultados concatenados de todas as transformações anteriores. Esta é a coleção do JSON transformado.

Nossos parâmetros têm esta aparência:

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

Nosso modelo também define uma variável nomeada instance que transforma nosso source objeto no esquema JSON necessário:

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

Por fim, o output de nosso modelo concatena as transformações coletadas de nosso state parâmetro com a transformação atual executada pela nossa variável instance:

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

Em seguida, vamos dar uma olhada no nosso modelo de coletor para ver como ele informa os valores de parâmetro.

Modelo de coletor

Nosso modelo de coletor inclui três parâmetros:

  • source é nossa matriz de objetos de parâmetro completa. Ele é informado pelo modelo de chamada. Ele tem o mesmo nome que o source parâmetro no nosso modelo de transformação, mas há uma diferença importante que você já deve ter notado: embora essa seja a matriz completa, nós só informamos um elemento da matriz para o modelo de transformação por vez.
  • transformTemplateUri é o URI do nosso modelo de transformação. Nós o definimos como um parâmetro para reutilização do modelo.
  • state é uma matriz inicialmente vazia que podemos passar para o nosso modelo de transformação. Ele armazena a coleção de objetos de parâmetro transformados depois que o loop de cópia for concluído.

Nossos parâmetros têm esta aparência:

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

Em seguida, definimos uma variável chamada count. Seu valor é o comprimento da matriz de objetos de parâmetro source:

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

Nós o usamos para o número de iterações em nosso loop de cópia.

Agora vamos dar uma olhada em nossos recursos. Definimos dois recursos:

  • loop-0 é o recurso com base em zero para o loop de cópia.
  • loop- é concatenado com o resultado da função copyIndex(1) para gerar um nome exclusivo baseado em iteração para nosso recurso, começando com 1.

Nossos recursos têm esta aparência:

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

Vamos examinar mais detalhadamente os parâmetros que informamos para nosso modelo de transformação no modelo aninhado. Você se lembra de que nosso parâmetro source passa o objeto atual na matriz de objetos de parâmetro source. O parâmetro state é onde a coleta acontece, porque ele pega a saída da iteração anterior do nosso loop de cópia e a passa para a iteração atual. Observe que a função reference() usa a função copyIndex() sem nenhum parâmetro para fazer referência ao name nosso objeto de modelo vinculado anterior.

Por fim, o output de nosso modelo retorna o output da última iteração de nosso modelo de transformação:

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

Pode parecer contraintuitivo retornar o output da última iteração de nosso modelo de transformação para nosso modelo de chamada porque ele aparece quando estamos armazenando-o em nosso parâmetro source. No entanto, é a última iteração do nosso modelo de transformação que contém a matriz completa de objetos de propriedade transformados e que é o que queremos retornar.

Por fim, vamos dar uma olhada em como chamar o modelo de coletor do nosso modelo de chamada.

Modelo de chamada

Nosso modelo de chamada define um parâmetro único chamado networkSecurityGroupsSettings:

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

Em seguida, nosso modelo define uma variável denominada collectorTemplateUri:

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

Esse é o URI para o modelo de coletor que é usado pelo nosso recurso de modelo vinculado:

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

Passamos dois parâmetros para o modelo de coletor:

  • source é a nossa matriz de objetos de propriedade. Em nosso exemplo, ele é nosso parâmetro networkSecurityGroupsSettings.
  • transformTemplateUri é a variável que acabamos de definir com o URI do nosso modelo de coletor.

Por fim, nosso recurso Microsoft.Network/networkSecurityGroups atribui diretamente o output do collector vinculado o recurso de modelo para sua propriedade securityRules:

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

Experimentar o modelo

Um modelo de exemplo está disponível no GitHub. Para implantar o modelo, clone o repositório e execute os seguintes comandos da CLI do Azure:

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

Próximas etapas