ARM 资源迭代因空数组而失败

Dav*_*ard 5 azure azure-resource-manager azure-rm-template

ARM 模板中的所有表达式似乎都是预先计算的,因此即使您有false资源的条件,也会计算该资源中的表达式。

false无论条件是否显式设置为或是否是计算结果为 的表达式,情况似乎都是如此false

这种行为在资源迭代的情况下是有问题的,因为资源内的表达式可能引用copyIndex()参数或变量的。但是,变量的参数是一个空数组,这些表达式的计算将失败,并显示类似于以下内容的消息 -

语言表达式属性数组索引“0”超出范围。有关使用详细信息,请参阅https://aka.ms/arm-template-expressions 。

有什么方法可以修改我的模板以使其工作,无论是否有任何资源要添加?

示例模板

请注意,我已经必须“破解”对象count的参数copy。如果是0(正如表达式length(variables('productsJArray'))可能评估的那样),模板验证将失败并出现以下错误 -

复制计数必须是正整数值并且不能超过“800”。

我觉得这是一个合理的期望,如果count0,则不添加任何资源 - 但这是一个完全不同的主题!

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "apiManagementServiceName": {
            "type": "string",
            "metadata": {
                "description": "The name of the API Management instance."
            }
        },
        "productsJson": {
            "type": "string",
            "metadata": {
                "description": "A JSON representation of the Products to add."
            }
        }
    },
    "variables": {
        "productsJArray": "[json(parameters('productsJson'))]"
    },
    "resources": [
        {
            "condition": "[greater(length(variables('productsJArray')), 0)]",
            "type": "Microsoft.ApiManagement/service/products",
            "name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex()].name)]",
            "apiVersion": "2018-06-01-preview",
            "properties": {
                "displayName": "[variables('productsJArray')[copyIndex()].displayName]",
                "description": "[variables('productsJArray')[copyIndex()].description]",
                "state": "[variables('productsJArray')[copyIndex()].state]",
                "subscriptionRequired": "[variables('productsJArray')[copyIndex()].subscriptionRequired]",
                "approvalRequired": "[variables('productsJArray')[copyIndex()].approvalRequired]"
            },
            "copy": {
                "name": "productscopy",
                "count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]"
            }
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

可用的示例参数文件

请注意,虽然这看起来不错,但在某些情况下,productsJson参数值可能是任何空数组,[]这就是我的问题出现的地方。

{
        "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
                "apiManagementServiceName": {
                        "value": "my-api-management"
                },
                "productsJson": {
                        "value": "[{\"name\":\"my-product\",\"displayName\":\"My Product\",\"description\":\"My product is awesome.\",\"state\":\"published\",\"subscriptionRequired\":true,\"approvalRequired\":false}]"
                }
        }
}
Run Code Online (Sandbox Code Playgroud)

将失败的示例参数文件

{
        "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
                "apiManagementServiceName": {
                        "value": "lmk-bvt-conveyorbot"
                },
                "productsJson": {
                        "value": "[]"
                }
        }
}
Run Code Online (Sandbox Code Playgroud)

更新了模板

源自用户“4c74356b41”的建议之一。

该模板生成以下错误 -

无法处理资源“/subscriptions/************/resourceGroups/************/providers/Microsoft.Resources/deployments/api-management-products”的模板语言表达式在“1”行和“839”列。'此位置不需要模板函数'copyIndex'。该函数只能在指定了副本的资源中使用。

{
        "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
                "apiManagementServiceName": {
                        "type": "string",
                        "metadata": {
                                "description": "The name of the API Management instance."
                        }
                },
                "productsJson": {
                        "type": "string",
                        "metadata": {
                                "description": "A JSON representation of the Products to add."
                        }
                }
        },
        "variables": {
                "productsJArray": "[json(parameters('productsJson'))]"
        },
        "resources": [
                {
                        "condition": "[greater(length(variables('productsJArray')), 0)]",
                        "type": "Microsoft.Resources/deployments",
                        "name": "api-management-products",
                        "apiVersion": "2017-05-10",
                        "properties": {
                                "mode": "Incremental",
                                "template": {
                                        "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
                                        "contentVersion": "1.0.0.0",
                                        "resources": [
                                                {
                                                        "type": "Microsoft.ApiManagement/service/products",
                                                        "name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex('productscopy')].name)]",
                                                        "apiVersion": "2018-06-01-preview",
                                                        "properties": {
                                                                "displayName": "[variables('productsJArray')[copyIndex('productscopy')].displayName]",
                                                                "description": "[variables('productsJArray')[copyIndex('productscopy')].description]",
                                                                "state": "[variables('productsJArray')[copyIndex('productscopy')].state]",
                                                                "subscriptionRequired": "[variables('productsJArray')[copyIndex('productscopy')].subscriptionRequired]",
                                                                "approvalRequired": "[variables('productsJArray')[copyIndex('productscopy')].approvalRequired]"
                                                        },
                                                        "copy": {
                                                                "name": "productscopy",
                                                                "count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]"
                                                        }
                                                }
                                        ]
                                }
                        }
                }
        ]
}
Run Code Online (Sandbox Code Playgroud)

4c7*_*b41 4

有两种方法可以解决这个问题:

  1. if()黑客,所以如果length == 0, length = 1. 使用这种方法,您需要有一个要引用的代理对象,因为引用不存在的对象是行不通的。
  2. 使用嵌套部署,您可以在部署上放置一个条件,这样它就不会启动length == 0(并且您在嵌套部署内运行循环)。这样你就不必关心零的长度。