你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 Azure 资源管理器模板中实现属性转换器和收集器

将对象用作 Azure 资源管理器模板的复制循环中的参数一文中,了解如何在对象中存储资源属性值并在部署时将其应用到资源。 虽然这样管理参数非常有用,但它仍然要求每次在模板中使用对象时,将对象的属性映射到资源属性。

为了解决此问题,可实现属性转换和收集器模板,循环访问对象数组并将其转换为资源的 JSON 架构。

重要

此方法要求对资源管理器模板和功能有深入的了解。

接下来看一个实现属性收集器和转换器以部署网络安全组的示例。 下图显示了模板与模板中资源的关系:

属性收集器和转换器体系结构

调用模板包含两个资源

  • 调用收集器模板的模板链接
  • 要部署的网络安全组资源

收集器模板包含两个资源

  • 定位点资源
  • 在复制循环中调用转换模板的模板链接

转换模板包含一个资源:带有变量的空模板,该模板能将 source JSON 转换为主模板中网络安全组资源所需要的 JSON 架构。

参数对象

我们使用将对象用作 Azure 资源管理器模板的复制循环中的参数一文中的 securityRules 参数对象。 转换模板将 securityRules 数组中的每个对象转换为调用模板中网络安全组资源所需要的 JSON 架构。

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

我们首先看一下转换模板

转换模板

转换模板包含从收集器模板传递的两个参数

  • source 是接收属性数组的属性值对象的对象。 在本示例中,securityRules 数组的每个对象以一次一个的方式传递。
  • state 是接收所有以前转换的连接结果的数组。 这是转换后的 JSON 的集合。

参数如下所示:

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

该模板还定义了一个名为 instance 的变量,该变量将对象 source 转换为所需的 JSON 架构:

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

最后,模板的 output 将收集的 state 参数的转换与当前由 instance 变量执行的转换相连接:

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

接下来了解收集器模板,了解它如何传递参数值。

收集器模板

收集器模板包含三个参数

  • source 是完整的参数对象数组。 它通过调用模板传递。 它的名称与转换模板中的 source 参数相同,但存在一个重要差异:它是完整的数组,但我们一次只能将一个数组元素传递给转换模板。
  • transformTemplateUri 是转换模板的 URI。 为了让模板可以重复使用,我们将其定义为参数。
  • state 刚开始是空数组,我们将其传递给转换模板。 当复制循环完成时,它存储转换后的参数对象的集合。

参数如下所示:

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

接下来,我们定义一个名为 count 的变量。 其值为 source 参数对象数组的长度:

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

我们在复制循环中将其用于迭代数。

现在我们来看看资源。 我们定义两种资源:

  • loop-0 是复制循环的基于零的资源。
  • loop-copyIndex(1) 函数结果连接,以生成基于迭代且以 1 开头的唯一资源名称。

资源如下所示:

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

下面详细了解在嵌套模板中传递给转换模板的参数。 回想一下,source 参数传递 source 参数对象数组中的当前对象。 state 参数是发生收集的位置,因为它接收复制循环的前一次迭代的输出并将其传递给当前迭代。 请注意,reference() 函数使用无参数的 copyIndex() 函数来引用以前链接的模板对象的 name

最后,模板的 output 返回转换模板的最后一次迭代的 output

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

将转换模板的最后一次迭代的 output 返回到调用模板似乎有悖常理,因为看起来我们是将其存储在了 source 参数中。 但这是转换模板的最后一次迭代,将保存转换后的属性对象的完整数组,并且这就是我们想要返回的内容。

最后,我们看看如何从调用模板中调用收集器模板

调用模板

调用模板定义一个名为 networkSecurityGroupsSettings 的单个参数

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

接下来,模板定义一个名为 collectorTemplateUri 的单个变量:

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

这是收集器模板的 URI,将由链接模板资源使用:

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

我们向收集器模板传递两个参数

  • source 是属性对象数组。 在本示例中是 networkSecurityGroupsSettings 参数。
  • transformTemplateUri 是刚才通过收集器模板的 URI 定义的变量。

最后,Microsoft.Network/networkSecurityGroups 资源直接将 collector 链接模板资源的 output 分配给 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]"
    }
}

尝试模板

GitHub 上提供了一个示例模板。 若要部署该模板,请克隆存储库并运行以下 Azure CLI 命令:

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

后续步骤