if()函数对ARM模板中的两个表达式求值

时间:2018-12-06 23:54:59

标签: azure azure-resource-manager 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表达式中产生否定结果。

但是,根据此处的答案,这应该在所有区域中都得到解决:

How the if() function executes in Azure Resource Manager Templates

有人知道为什么会这样吗?

我确实注意到ARM模板中AKV资源的最新API版本是2018-02-14,这早于上述问题中的bmoore-msft提到已修复该错误之前。我不确定API版本是否可以准确指示代码何时发布,或者仅仅是标签。

3 个答案:

答案 0 :(得分:0)

这意味着您的状况评估结果并非您认为的那样。 api版本无关紧要。同样,这是评估为-1的部分(据我了解):

sub(copyIndex('myLoop'), variables('users'))

答案 1 :(得分:0)

好吧,您遇到的问题是在复制前先评估var,在if之前先评估copy-因此,您仍然需要if()语句中的有效索引。我们也许可以解决这个问题,但短期内您需要另一种方法。在您的情况下,由于您刚好有2个批次,并且正在创建保管库,因此可以在保管库上另外添加“通过”以添加更多访问策略。

基本上,您可以首先创建保管库并添加MSI访问策略,然后在完成后可以添加额外的用户。如果您需要两个以上的“通行证”,或者您没有创建保管库,那么您将不得不使用嵌套部署进行多次通行证(有效,只是更多工作)。

以下是基于您的上述代码段的示例:

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

有帮助吗?

答案 2 :(得分:0)

我再试一次,现在可以了。我确实在代码中发现了一些语法错误。我最初写道:

"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”提供了错误的值。因此,不幸的是,我不确定根本原因是什么。可能是我的语法错误,某些服务器端问题或两者兼而有之。