ARM 资源迭代失败,数组为空
ARM resource iteration failing with an empty array
似乎 ARM 模板中的所有表达式都是预先计算的,所以即使您有资源的条件 false
,也会计算该资源中的表达式。
无论条件是否显式设置为 false
或者它是否是计算结果为 false
.
的表达式,情况似乎都是如此
这种行为在 case 资源迭代中是有问题的,因为资源中的表达式可能引用参数或变量的 copyIndex()
。但是,该变量的参数是一个空数组,这些表达式的计算将失败,并显示类似于以下内容的消息 -
The language expression property array index '0' is out of bounds.. Please see https://aka.ms/arm-template-expressions for usage details.
有什么方法可以修改我的模板以使其工作,而不管是否有任何资源要添加?
示例模板
请注意,我已经必须 'hack' copy
对象的 count
参数。如果它是 0
(因为表达式 length(variables('productsJArray'))
可能计算为),模板验证失败并出现以下错误 -
The copy count must be a postive integer value and cannot exceed '800'.
我觉得如果 count
是 0
,那么不添加任何资源是一个合理的期望 - 但这是一个完全不同的主题!
{
"$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)]"
}
}
]
}
}
}
]
}
解决此问题的两种方法:
if()
hack,所以如果 length == 0
,length = 1
。使用这种方法,你需要有一个你将引用的代理对象,因为引用一个不存在的对象是行不通的。
- 使用嵌套部署,您可以在部署上设置条件,这样如果
length == 0
(并且您 运行 嵌套部署中的循环)它就不会启动。这样你就不会关心零的长度。
这是我将使用的最终模板。这允许我将对象数组或空数组传递给 productsJson
参数。
{
"$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": "[concat('api-management-products-', copyIndex())]",
"apiVersion": "2017-05-10",
"copy": {
"name": "productscopy",
"count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]",
"mode": "Serial"
},
"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()].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]"
}
}
]
}
}
}
]
}
您还可以在空数组中有一个占位符元素,并使用条件忽略占位符元素。像这样
{
"parameters": {
"yourArray": {
"defaultValue": [
{
"name": "placeholder"
}
],
"type": "array"
}
},
"resources": [
{
"condition": "[not(equals(parameters('yourArray')[copyIndex()].name,'placeholder'))]",
"copy": {
"name": "yourArray",
"count": "[length(parameters('yourArray'))]"
}
}
]
}
似乎 ARM 模板中的所有表达式都是预先计算的,所以即使您有资源的条件 false
,也会计算该资源中的表达式。
无论条件是否显式设置为 false
或者它是否是计算结果为 false
.
这种行为在 case 资源迭代中是有问题的,因为资源中的表达式可能引用参数或变量的 copyIndex()
。但是,该变量的参数是一个空数组,这些表达式的计算将失败,并显示类似于以下内容的消息 -
The language expression property array index '0' is out of bounds.. Please see https://aka.ms/arm-template-expressions for usage details.
有什么方法可以修改我的模板以使其工作,而不管是否有任何资源要添加?
示例模板
请注意,我已经必须 'hack' copy
对象的 count
参数。如果它是 0
(因为表达式 length(variables('productsJArray'))
可能计算为),模板验证失败并出现以下错误 -
The copy count must be a postive integer value and cannot exceed '800'.
我觉得如果 count
是 0
,那么不添加任何资源是一个合理的期望 - 但这是一个完全不同的主题!
{
"$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)]"
}
}
]
}
}
}
]
}
解决此问题的两种方法:
if()
hack,所以如果length == 0
,length = 1
。使用这种方法,你需要有一个你将引用的代理对象,因为引用一个不存在的对象是行不通的。- 使用嵌套部署,您可以在部署上设置条件,这样如果
length == 0
(并且您 运行 嵌套部署中的循环)它就不会启动。这样你就不会关心零的长度。
这是我将使用的最终模板。这允许我将对象数组或空数组传递给 productsJson
参数。
{
"$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": "[concat('api-management-products-', copyIndex())]",
"apiVersion": "2017-05-10",
"copy": {
"name": "productscopy",
"count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]",
"mode": "Serial"
},
"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()].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]"
}
}
]
}
}
}
]
}
您还可以在空数组中有一个占位符元素,并使用条件忽略占位符元素。像这样
{
"parameters": {
"yourArray": {
"defaultValue": [
{
"name": "placeholder"
}
],
"type": "array"
}
},
"resources": [
{
"condition": "[not(equals(parameters('yourArray')[copyIndex()].name,'placeholder'))]",
"copy": {
"name": "yourArray",
"count": "[length(parameters('yourArray'))]"
}
}
]
}