使用内部变量或参数的 ARM 模板中的 listKeys 问题

listKeys problems in ARM template using inside variables or parameters

我正在为我的 Azure Functions 设置一个 ARM 模板。我有 functions_app.json,它将作为“主要”模板,并将用于其他发布管道。

然后会有项目特定的参数模板,例如:

等等

但是我卡在了这一部分,它在 functions_app.json 模板中创建了实际的函数资源:

"resources": [
{
    "apiVersion": "2018-11-01",
    "name": "[variables('resourceName')]",
    "type": "Microsoft.Web/sites",
    "properties": {
        "name": "[variables('resourceName')]",
        "siteConfig": {
            "appSettings": [
                {
                    "name": "FUNCTIONS_EXTENSION_VERSION",
                    "value": "~4"
                },
                {
                    "name": "FUNCTIONS_WORKER_RUNTIME",
                    "value": "dotnet"
                },
                {
                    "name": "AzureWebJobsStorage",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('xxxx-xxxx','MyResourceGroup','Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                },
                {
                    "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('xxxx-xxxx','MyResourceGroup','Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                },
                {
                    "name": "WEBSITE_CONTENTSHARE",
                    "value": "[toLower(variables('resourceName'))]"
                }
            ]
        }
    }
}

为简洁起见,我省略了一些内容。导入部分是 appSettings 部分。

我最初的想法是将 array 放在 variables 中。这些将是“默认”设置。然后从我的 counter_function_arm.parameters.test.json 文件中,我将添加另一个特定于该应用程序的数组,然后 union 将这两个组合在一起,以便所有 AppSettings 都已配置。

像这样:

counter_function_arm.parameters.test.json

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "customAppSettings":{
            "value": [
                {
                    "name": "CustomProperty",
                    "value": "some value"
                }
            ]
        }
    }
}

functions_app.json

"variables": {
    "defaultAppSettings": [
                {
                    "name": "FUNCTIONS_EXTENSION_VERSION",
                    "value": "~4"
                },
                {
                    "name": "FUNCTIONS_WORKER_RUNTIME",
                    "value": "dotnet"
                },
                {
                    "name": "AzureWebJobsStorage",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('xxxx-xxxx','MyResourceGroup','Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                },
                {
                    "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('xxxx-xxxx','MyResourceGroup','Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                },
                {
                    "name": "WEBSITE_CONTENTSHARE",
                    "value": "[toLower(variables('resourceName'))]"
                }
            ]
},
"resources": [
{
    "apiVersion": "2018-11-01",
    "name": "[variables('resourceName')]",
    "type": "Microsoft.Web/sites",
    "properties": {
        "name": "[variables('resourceName')]",
        "siteConfig": {
            "appSettings": "[union(variables('defaultAppSettings'), parameters('customAppSettings'))]"
        }
    }
}

所以在这种情况下,我 union 变量 variables('defaultAppSettings')parameters('customAppSettings') 放在一起。

但是,问题是我无法在 variables 部分使用 listKeys。我也不能将它移到 parameters 部分并将其设置为 defaultValue 因为那里也不允许 listKeys

将硬编码数组添加到 union 也不起作用:

"appSettings": "[union([1,2,3], parameters('customAppSettings'))]"

所以我没主意了。

有办法吗?

我找到了解决这个问题的方法,它不是很漂亮,但它确实有效...基本上我有一组纯静态应用程序设置(在你的情况下 FUNCTIONS_EXTENSION_VERSION、FUNCTIONS_WORKER_RUNTIME、 WEBSITE_CONTENTSHARE),你可以在变量中创建,一个来自参数的 customAppSettings 数组,以及另一个我必须写成原始数组 JSON。 这是一个例子:

"resources": [
    {
        "apiVersion": "2018-11-01",
        "name": "[variables('resourceName')]",
        "type": "Microsoft.Web/sites",
        "properties": {
            "name": "[variables('resourceName')]",
            "siteConfig": {
                "appSettings": "[union(variables('staticAppSettings'), parameters('customAppSettings'), json(concat('[{\"name\": \"AzureWebJobsStorage\",\"value\": \"', concat('DefaultEndpointsProtocol=https;AccountName=', parameters('azureFunctionParameters').functionStorageName,';AccountKey=', listKeys(resourceId(parameters('azureFunctionParameters').mainStorageResourceGroup, 'Microsoft.Storage/storageAccounts', parameters('azureFunctionParameters').functionStorageName), '2021-08-01').keys[1].value, ';EndpointSuffix=core.windows.net'),'\"}]')))]"
            }
        }
    }
]

遗憾的是,这是我能想到的最好的,它很容易出现语法错误,但如果你使用 multi-line strings,你可以以一种避免错误的方式格式化它(但如果你要小心我正在使用 Azure Devops,它不兼容)。

编辑: 还有另一种方法可能更适合您,即使用 linkedTemplate :

主模板

"resources": [
    {
        "type": "Microsoft.Resources/deployments",
        "apiVersion": "2021-04-01",
        "name": "yourResourceDeployment",
        "properties": {
            "mode": "Incremental",
            "templateLink": {
                "uri": "[concat(parameters('blobBaseUrl'), '/', parameters('resourceGroupName'), '/azurefunctions/baseazurefunction.json')]",
                "contentVersion": "1.0.0.0"
            },
            "parameters": {
                "azureFunctionParameters": {
                    "value": "[parameters('baseAzureFunctionParameters')]"
                },
                "appSettings": {
                    "value" : "[union(variables('staticAppSettings'), parameters('customAppSettings'))]"
                },
                "someMoreAppSettings": {
                    "value" : [
                        {
                            "name": "AzureWebJobsStorage",
                            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('xxxx-xxxx','MyResourceGroup','Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                        },
                        {
                            "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('xxxx-xxxx','MyResourceGroup','Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value,';EndpointSuffix=','core.windows.net')]"
                        }
                    ]
                }
            }
        }
    }
]

在 baseazurefunction.json linkedTemplate 中你可以只使用

{
    "apiVersion": "2018-11-01",
    "name": "[variables('resourceName')]",
    "type": "Microsoft.Web/sites",
    "properties": {
        "name": "[variables('resourceName')]",
        "siteConfig": {
            "appSettings": "[union(parameters('appSettings'), parameters('moreAppSettings'))]"
        }
    }
}

如果您对将连接字符串作为参数发送到其他模板有安全顾虑,您可以将您的应用程序设置包装在一个带有 属性 调用数组的安全对象中,该数组将包含您的所有设置,然后像这样使用它相反

    "appSettings": {
        "type": "secureobject",
        "metadata": {
            "description": "Secure object with an array property which contains the appsettings"
        }
    },
    "moreAppSettings": {
        "type": "secureobject",
        "metadata": {
            "description": "Secure object with an array property which contains more appsettings"
        }
    }

    .
    .
    .

    "appSettings": "[union(parameters('appSettings').array, parameters('moreAppSettings').array)]"