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

标签 azure azure-resource-manager azure-rm-template

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

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

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

The language expression property array index '0' is out of bounds.. Please see https://aka.ms/arm-template-expressions for usage details.

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

示例模板

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

The copy count must be a postive integer value and cannot exceed '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)]"
            }
        }
    ]
}

可用的示例参数文件

请注意,虽然这看起来不错,但在某些情况下,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}]"
                }
        }
}

将失败的示例参数文件

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

更新了模板

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

此模板生成以下错误 -

Unable to process template language expressions for resource '/subscriptions/**********/resourceGroups/**********/providers/Microsoft.Resources/deployments/api-management-products' at line '1' and column '839'. 'The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified.

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

最佳答案

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

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

关于azure - ARM 资源迭代因空数组而失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53722613/

相关文章:

azure - 如何将 AzureAD 应用程序限制在单个位置

multithreading - 具有分布式后台工作的 Azure Web 角色

angularjs - 从 Azure Blob for Express.js 服务器提供 HTML 文件

azure - 在 Azure 中创建暂存和生产环境的正确方法

c# - 调用 Azure ActiveDirectory 时的任务状态 WaitingForActivation

azure - 用户无权执行操作“Microsoft.Resources/deployments/validate/action”

Azure Databricks CI/CD

azure - 如何在 ARM 中部署具有自定义数据和 'attached' VHD 的 Azure VM?

azure - 将 ARM 模板部署到 Azure 时出错

azure - 不要删除模板中未声明的 AppSettings