if() 函数计算 ARM 模板中的两个表达式
if() function evaluates both expressions in ARM template
我在 Azure KeyVault 的复制操作中使用 if() 函数:
"variables": {
"users": 3,
"user1": {
"tenantId": "[variables('tenantId')]",
"objectId": "abcd",
"permissions": {
"keys": [
"get"
],
"secrets": [
"get"
],
"certificates": [
"get"
]
}
},
"user2": {
"tenantId": "[variables('tenantId')]",
"objectId": "efgh",
"permissions": {
"keys": [
"get"
],
"secrets": [
"get"
],
"certificates": [
"get"
]
}
},
"user3": {
"tenantId": "[variables('tenantId')]",
"objectId": "ijkl",
"permissions": {
"secrets": [
"get"
]
}
},
"extraUsers": [
"[variables('user1')]",
"[variables('user2')]",
"[variables('user3')]"
]
"resources": [
{
"name": "myKeyVault",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "some_location",
"tags": {
"displayName": "KeyVault"
},
"properties": {
"copy": [
{
"name": "accessPolicies",
"count": "[add(variables('users'), length(variables('extraUsers')))]",
"input": {
"tenantId": "[variables('tenantId')]",
"objectId": "[if(less(copyIndex('myLoop'), variables('users')), reference(concat('Microsoft.Compute/virtualMachines/myVm', copyIndex('myLoop'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId, variables('extraUsers')[sub(copyIndex('myLoop'), variables('users'))].objectId)]",
"permissions": "[if(less(copyIndex('myLoop'), variables('users')), json($null), variables('extraUsers')[sub(copyIndex('myLoop'), variables('users'))].permissions)]"
}
}
],
以上归结为:
if((index < A), <some object>.principalId, myArray[index - A].objectId)
但是,当我尝试部署它时,出现错误,指出不允许索引为 -1。看来 ARM 对 true 和 false 表达式都求值,所以减法运算当然会在 false 表达式中产生负结果。
但是,根据这里的回答,这应该在所有地区都已解决:
有人知道为什么会这样吗?
我确实注意到 ARM 模板中 AKV 资源的最新 API 版本是 2018-02-14,这早于上述问题中的 bmoore-msft 提到该错误已修复。我不确定 API 版本是代码发布时间的准确指标,还是只是一个标签。
这意味着您的条件评估不是您认为的评估。 api 版本无关紧要。另外,这是评估为 -1 的部分(据我所知):
sub(copyIndex('myLoop'), variables('users'))
好的,您 运行 遇到的问题是 vars 在 copy 之前求值,而 copy 在 if 之前求值 - 所以您仍然需要 if() 语句中的有效索引。我们或许可以解决这个问题,但短期内您需要另一种方法。在您的情况下,因为您正好有 2 个批次并且正在创建保管库,所以您可以在保管库上添加 "pass" 以添加更多访问策略。
基本上您可以先创建保管库并添加 MSI 访问策略,然后在完成后您可以添加额外的用户。如果您需要超过 2 个 "passes" 或者您没有创建保管库,那么您将不得不使用嵌套部署来执行多个传递(有效,只是更多的工作)。
以下是基于您上面的代码段的示例:
{
"name": "myKeyVault",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "some_location",
"tags": {
"displayName": "KeyVault"
},
"properties": {
"copy": [
{
"name": "myLoop",
"count": "[variables('users')]",
"input": {
"name": "accessPolicies",
"properties": {
"tenantId": "[variables('tenantId')]",
"objectId": "[reference(concat('Microsoft.Compute/virtualMachines/myVm', copyIndex('myLoop'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]",
"permissions": "[json('null')]"
}
}
}
]
}
},
{
"name": "[concat('myKeyVault', '/add')]",
"type": "Microsoft.KeyVault/vaults/accessPolicies",
"apiVersion": "2018-02-14",
"location": "some_location",
"dependsOn": [
"myKeyVault"
],
"tags": {
"displayName": "MoreAccessPolicies"
},
"properties": {
"copy": [
{
"name": "myLoop2",
"count": "[length(variables('extraUsers'))]",
"input": {
"name": "accessPolicies",
"properties": {
"tenantId": "[variables('tenantId')]",
"objectId": "[variables('extraUsers')[copyIndex('myLoop2')].objectId]",
"permissions": "[variables('extraUsers')[copyIndex('myLoop2')].permissions]"
}
}
}
]
}
}
有帮助吗?
我又试了一次,现在可以了。我确实在我的代码中发现了一些语法错误。我最初写道:
"copy": [
{
"name": "loopName",
"count": 3,
"input": {
"name": accessPolicies",
"properties": { /* accessPolicies properties */ }
}
}
]
我认为 copy.name 是循环的名称,而 copy.input.name 是要复制的 属性 的名称。实际上应该是:
"copy": [
{
"name": accessPolicies",
"count": 3,
"input": {
/* accessPolicies properties */
}
}
]
循环没有名称。您只需提供要复制的 属性 的名称。我已经更新了问题中的代码。
然而,即使我恢复到原来的错误版本,我也不会得到关于负索引的相同错误。相反,我得到一个错误,指出为 "accessPolicies" 提供了错误的值。所以不幸的是,我不确定根本原因是什么。这可能是我的语法错误、某些 server-side 问题或两者兼而有之。
我在 Azure KeyVault 的复制操作中使用 if() 函数:
"variables": {
"users": 3,
"user1": {
"tenantId": "[variables('tenantId')]",
"objectId": "abcd",
"permissions": {
"keys": [
"get"
],
"secrets": [
"get"
],
"certificates": [
"get"
]
}
},
"user2": {
"tenantId": "[variables('tenantId')]",
"objectId": "efgh",
"permissions": {
"keys": [
"get"
],
"secrets": [
"get"
],
"certificates": [
"get"
]
}
},
"user3": {
"tenantId": "[variables('tenantId')]",
"objectId": "ijkl",
"permissions": {
"secrets": [
"get"
]
}
},
"extraUsers": [
"[variables('user1')]",
"[variables('user2')]",
"[variables('user3')]"
]
"resources": [
{
"name": "myKeyVault",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "some_location",
"tags": {
"displayName": "KeyVault"
},
"properties": {
"copy": [
{
"name": "accessPolicies",
"count": "[add(variables('users'), length(variables('extraUsers')))]",
"input": {
"tenantId": "[variables('tenantId')]",
"objectId": "[if(less(copyIndex('myLoop'), variables('users')), reference(concat('Microsoft.Compute/virtualMachines/myVm', copyIndex('myLoop'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId, variables('extraUsers')[sub(copyIndex('myLoop'), variables('users'))].objectId)]",
"permissions": "[if(less(copyIndex('myLoop'), variables('users')), json($null), variables('extraUsers')[sub(copyIndex('myLoop'), variables('users'))].permissions)]"
}
}
],
以上归结为:
if((index < A), <some object>.principalId, myArray[index - A].objectId)
但是,当我尝试部署它时,出现错误,指出不允许索引为 -1。看来 ARM 对 true 和 false 表达式都求值,所以减法运算当然会在 false 表达式中产生负结果。
但是,根据这里的回答,这应该在所有地区都已解决:
有人知道为什么会这样吗?
我确实注意到 ARM 模板中 AKV 资源的最新 API 版本是 2018-02-14,这早于上述问题中的 bmoore-msft 提到该错误已修复。我不确定 API 版本是代码发布时间的准确指标,还是只是一个标签。
这意味着您的条件评估不是您认为的评估。 api 版本无关紧要。另外,这是评估为 -1 的部分(据我所知):
sub(copyIndex('myLoop'), variables('users'))
好的,您 运行 遇到的问题是 vars 在 copy 之前求值,而 copy 在 if 之前求值 - 所以您仍然需要 if() 语句中的有效索引。我们或许可以解决这个问题,但短期内您需要另一种方法。在您的情况下,因为您正好有 2 个批次并且正在创建保管库,所以您可以在保管库上添加 "pass" 以添加更多访问策略。
基本上您可以先创建保管库并添加 MSI 访问策略,然后在完成后您可以添加额外的用户。如果您需要超过 2 个 "passes" 或者您没有创建保管库,那么您将不得不使用嵌套部署来执行多个传递(有效,只是更多的工作)。
以下是基于您上面的代码段的示例:
{
"name": "myKeyVault",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "some_location",
"tags": {
"displayName": "KeyVault"
},
"properties": {
"copy": [
{
"name": "myLoop",
"count": "[variables('users')]",
"input": {
"name": "accessPolicies",
"properties": {
"tenantId": "[variables('tenantId')]",
"objectId": "[reference(concat('Microsoft.Compute/virtualMachines/myVm', copyIndex('myLoop'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]",
"permissions": "[json('null')]"
}
}
}
]
}
},
{
"name": "[concat('myKeyVault', '/add')]",
"type": "Microsoft.KeyVault/vaults/accessPolicies",
"apiVersion": "2018-02-14",
"location": "some_location",
"dependsOn": [
"myKeyVault"
],
"tags": {
"displayName": "MoreAccessPolicies"
},
"properties": {
"copy": [
{
"name": "myLoop2",
"count": "[length(variables('extraUsers'))]",
"input": {
"name": "accessPolicies",
"properties": {
"tenantId": "[variables('tenantId')]",
"objectId": "[variables('extraUsers')[copyIndex('myLoop2')].objectId]",
"permissions": "[variables('extraUsers')[copyIndex('myLoop2')].permissions]"
}
}
}
]
}
}
有帮助吗?
我又试了一次,现在可以了。我确实在我的代码中发现了一些语法错误。我最初写道:
"copy": [
{
"name": "loopName",
"count": 3,
"input": {
"name": accessPolicies",
"properties": { /* accessPolicies properties */ }
}
}
]
我认为 copy.name 是循环的名称,而 copy.input.name 是要复制的 属性 的名称。实际上应该是:
"copy": [
{
"name": accessPolicies",
"count": 3,
"input": {
/* accessPolicies properties */
}
}
]
循环没有名称。您只需提供要复制的 属性 的名称。我已经更新了问题中的代码。
然而,即使我恢复到原来的错误版本,我也不会得到关于负索引的相同错误。相反,我得到一个错误,指出为 "accessPolicies" 提供了错误的值。所以不幸的是,我不确定根本原因是什么。这可能是我的语法错误、某些 server-side 问题或两者兼而有之。