Implementación de un recopilador y transformador de propiedades en una plantilla de Azure Resource Manager
En el artículo Uso de objetos como parámetros en un bucle de copia en una plantilla de Azure Resource Manager, puede ver cómo almacenar valores de propiedad de recursos en un objeto y cómo aplicarlos a un recurso durante la implementación. Aunque esta es una forma muy útil de administrar los parámetros, sigue siendo necesario que asigne las propiedades del objeto a las propiedades de los recursos cada vez que lo use en la plantilla.
Para evitar esto, puede implementar una plantilla de recopilador y transformador de propiedades que recorre la matriz de objetos en iteración y los transforma en el esquema JSON para el recurso.
Importante
Esta técnica requiere que conozca a fondo las plantillas y las funciones de Resource Manager.
Veamos un ejemplo que implementa un recopilador de propiedades y un transformador para implementar un grupo de seguridad de red. En el diagrama siguiente se muestra cómo están relacionadas nuestras plantillas con los recursos de esas plantillas:
Nuestra plantilla de llamada incluye dos recursos:
- Un vínculo de plantilla que invoca a nuestra plantilla de recopilador
- Recurso del grupo de seguridad de red que se va a implementar
Nuestra plantilla de recopilador incluye dos recursos:
- Recurso de delimitador
- Vínculo de plantilla que invoca la plantilla de transformador en un bucle de copia
Nuestra plantilla de transformación incluye un único recurso: una plantilla vacía con una variable que transforma nuestro código JSON source
en el esquema JSON que esperaba el recurso del grupo de seguridad de red de la plantilla principal.
Objeto de parámetro
Usamos nuestro objeto de parámetro securityRules
de Uso de objetos como parámetros en un bucle de copia en una plantilla de Azure Resource Manager. Nuestra plantilla de transformación transformará cada objeto de la matriz securityRules
en el esquema JSON que espera el recurso del grupo de seguridad de red de nuestra plantilla de llamadas.
{
"$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"
}
]
}
}
}
}
Veamos primero la plantilla de transformación.
Plantilla de transformación
La Plantilla de transformación incluye dos parámetros que se pasan desde la plantilla de recopilador:
-
source
es un objeto que recibe uno de los objetos de valor de propiedad de la matriz de propiedades. En nuestro ejemplo, los objetos de la matrizsecurityRules
se pasarán uno a uno. -
state
es una matriz que recibe los resultados concatenados de todas las transformaciones anteriores. Esta es la colección de código JSON transformado.
Nuestros parámetros tienen este aspecto:
{
"$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": []
}
},
Nuestra plantilla también define una variable denominada instance
que transforma el objeto source
en el esquema JSON necesario:
"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 último, el valor de output
de nuestra plantilla concatena las transformaciones recopiladas de nuestro parámetro state
con la transformación actual realizada por la variable instance
:
"resources": [],
"outputs": {
"collection": {
"type": "array",
"value": "[concat(parameters('state'), variables('instance'))]"
}
}
A continuación, veamos nuestra plantilla de recopilador para ver cómo pasa los valores de parámetro.
Plantilla de recopilador
La plantilla de recopilador incluye tres parámetros:
-
source
es la matriz completa de objetos de parámetro. La pasa la plantilla de llamadas. Tiene el mismo nombre que el parámetrosource
en nuestra plantilla de transformación, pero hay una diferencia clave: aunque es la matriz completa, solo pasamos un elemento de matriz a la vez a la plantilla de transformación. -
transformTemplateUri
es el URI de nuestra plantilla de transformación. Lo definimos como parámetro para poder volver a usar la plantilla. -
state
es una matriz inicialmente vacía que pasamos a nuestra plantilla de transformación. Almacena la colección de objetos de parámetro transformados cuando el bucle de copia finaliza.
Nuestros parámetros tienen este aspecto:
"parameters": {
"source": {
"type": "array"
},
"transformTemplateUri": {
"type": "string"
},
"state": {
"type": "array",
"defaultValue": []
}
}
A continuación, definimos una variable llamada count
. Su valor es la longitud de la matriz de objetos de parámetro source
:
"variables": {
"count": "[length(parameters('source'))]"
}
Lo usamos para el número de iteraciones en nuestro bucle de copia.
Ahora, echemos un vistazo a nuestros recursos. Se definen dos recursos:
-
loop-0
es el recurso de base cero de nuestro bucle de copia. -
loop-
se concatena con el resultado de la funcióncopyIndex(1)
para generar un nombre único basado en iteración para el recurso, comenzando por1
.
Nuestros recursos tienen este aspecto:
"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]" }
}
}
}
]
Veamos más de cerca los parámetros que pasamos a nuestra plantilla de transformación, en la plantilla anidada. Recuerde que nuestro parámetro source
pasa el objeto actual a la matriz de objetos de parámetro source
. El parámetro state
es donde ocurre la colección, porque toma la salida de la iteración anterior de nuestro bucle de copia y la pasa a la iteración actual. Observe que la función reference()
usa la función copyIndex()
sin ningún parámetro para hacer referencia al valor name
de nuestro objeto de plantilla vinculado anterior.
Por último, el valor de output
de la plantilla devuelve el valor de output
de la última iteración de la plantilla de transformación:
"outputs": {
"result": {
"type": "array",
"value": "[reference(concat('loop-', variables('count'))).outputs.collection.value]"
}
}
Puede parecer extraño devolver el valor de output
de la última iteración de la plantilla de transformación a la plantilla de llamada, porque parecería que lo estamos almacenando en el parámetro source
. Sin embargo, la última iteración de la plantilla de transformación es la que contiene la matriz completa de los objetos de propiedad transformados, y eso es lo que queremos devolver.
Por último, echemos un vistazo a cómo llamar a la plantilla de recopilador desde la plantilla de llamada.
Plantilla de llamada
La plantilla de llamada define un único parámetro llamado networkSecurityGroupsSettings
:
...
"parameters": {
"networkSecurityGroupsSettings": {
"type": "object"
}
}
Después, la plantilla define una sola variable llamada collectorTemplateUri
:
"variables": {
"collectorTemplateUri": "[uri(deployment().properties.templateLink.uri, 'collector.template.json')]"
}
Este es el URI de la plantilla de recopilador que usará el recurso de plantilla vinculada:
{
"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')]"
}
}
}
}
Pasamos dos parámetros a la plantilla de recopilador:
-
source
es la matriz de objetos de propiedad. En nuestro ejemplo, es el parámetronetworkSecurityGroupsSettings
. -
transformTemplateUri
es la variable que acabamos de definir con el URI de la plantilla de recopilador.
Por último, el recurso Microsoft.Network/networkSecurityGroups
asigna directamente el valor de output
del recurso de plantilla vinculada collector
a su propiedad 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]"
}
}
Prueba de la plantilla
GitHub tiene una plantilla de ejemplo a su disposición. Para implementar la plantilla, clone el repositorio y ejecute los siguientes comandos de la CLI de 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
Pasos siguientes
- Azure Resource Manager
- ¿Qué son las plantillas de Resource Manager?
- Tutorial: Creación e implementación de su primera plantilla de Resource Manager
- Tutorial: Incorporación de un recurso a la plantilla de Resource Manager
- Procedimientos recomendados para plantilla de Resource Manager
- Documentación de Azure Resource Manager
- Documentación de las plantillas de Resource Manager