参数数组中的Azure资源管理器模板网站应用程序设置

问题描述 投票:1回答:2

我试图获取一系列参数 - 特别是电子邮件收件人列表 - 并将这些参数写入我的网络应用程序的应用程序设置。

以下模板可以工作,但显然只会从数组中写入第一个和第二个项目。

我研究了复制功能,但这只能处理对象的创建,但我需要添加到现有的键值对列表中。

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  ... 
  "parameters": {
    "Email:Recipients": {
    "type": "array"
  },
  ...
  "resources": [
    {
      "apiVersion": "2015-08-01",
      "type": "Microsoft.Web/sites",
      ...
      "resources": [
        {
          "apiVersion": "2015-08-01",
          "name": "appsettings",
          "type": "config",
          "properties": {
            ...
            "Email:Recipients:0": "[parameters('Email:Recipients')[0]]",
            "Email:Recipients:1": "[parameters('Email:Recipients')[1]]",
            ...
          }
        }
  ]
}
parameters azure-resource-manager appsettings
2个回答
0
投票

您可以在属性对象中使用复制功能 - 请参阅:https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#property-iteration

在部署模板之前,将此视为复制/粘贴操作类型。


0
投票

我有一个非常相似的用例:我希望用户指定用于分片的存储帐户数量,并希望模板创建所有存储帐户,然后为每个帐户添加一个连接字符串作为应用程序设置一个Web应用程序以及我的所有其他应用程序设置,格式如下:

<other app settings>
...
"STORAGE_CONNECTION_STRING_00": "<connectionString00>",
"STORAGE_CONNECTION_STRING_01": "<connectionString01>",
...

我意识到我可能来不及帮助你,但希望这会帮助别人。

解决方案的关键是,不要将您的应用程序设置指定为Microsoft.Web/sites资源的子资源,而是在属性部分中内联指定它们。至关重要的是,这允许您将它们指定为一个对象数组,每个对象都有namevalue属性,而不是像您的问题中的一个大对象:

{
  "apiVersion": "2015-08-01",
  "type": "Microsoft.Web/sites",
  ...
  "properties": {
    ...
    "siteConfig": {
      "appSettings": [
        { 
          name: "STORAGE_CONNECTION_STRING_00",
          value: "<connectionString00>"
        },
        ...
      ]
  },
  ...
}

对于我的第一次尝试,我尝试使用copy将所有连接字符串添加到此列表中:

{
  "apiVersion": "2015-08-01",
  "type": "Microsoft.Web/sites",
  ...
  "properties": {
    "siteConfig": {
      "copy": [
        {
          "name": "appSettings",
          "count": "[parameters('resultsShardCount')]",
          "input": {
            "name": "[concat('STORAGE_CONNECTION_STRING_', padLeft(copyIndex('appSettings'), 2, '0'))]",
            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageDataAccountNames')[copyIndex('appSettings')],';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageDataAccountNames')[copyIndex('appSettings')]), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
          }
        }
      ]
    }
  },
  ...
}

这有效,但它不允许我在存储连接字符串旁边添加任何其他应用程序设置。

我尝试添加使用单独的appsettings子资源添加其他应用程序设置,如原始问题,希望它们将被合并,但这只是覆盖了连接字符串。

接下来,我尝试使用copy定义两个变量,一个是连接字符串对象的数组,另一个是所有其他应用程序设置对象的静态数组。我想我可以使用union函数来组合它们:

  "apiVersion": "2015-08-01",
  "type": "Microsoft.Web/sites",
  ...
  "properties": {
    "siteConfig": {
      "appSettings": "[union(variables('additionalAppSettings), variables('storageAppSettings'))]"
    }
  },
  ...
}

不幸的是,急切地评估模板变量,这意味着您无法引用任何资源属性。这对于评估连接字符串和我的一些其他应用程序设置都是一个问题,这些设置包含对我在模板中部署的其他资源的引用。

研究该问题导致查看嵌套模板,特别是this Stack Overflow answer,用于在嵌套模板上使用copy构建数组中动态评估对象的列表。

这个方法看起来很有希望,直到我遇到了ARM模板的another limitation

对于嵌套模板,您不能使用嵌套模板中定义的参数或变量。

解决方案是使用链接模板,但这对于应该是一个微不足道的问题来说是一个巨大的过度杀伤力。

在经过一番努力之后,我终于找到了一种方法来调整它以仅使用输出参数,允许它使用嵌套模板工作:

...
{
  "name": "reference0",
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2015-01-01",
  "dependsOn": [
    "storageDataAccountCopy"
  ],
  "properties": {
    "mode": "Incremental",
    "template": {
      "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "resources": [],
      "outputs": {
        "storageAppSettings": {
          "type": "array",
          "value": []
        },
        "storageAppSetting": {
          "type": "object",
          "condition": "[greater(parameters('resultsShardCount'), 0)]",
          "value": {
            "name": "[concat('STORAGE_CONNECTION_STRING_', padLeft(0, 2, '0'))]",
            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageDataAccountNames')[0],';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageDataAccountNames')[0]), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
          }
        },
        "additionalAppSettings": {
          "type": "array",
          "value": [
            {
              "name": "APPLICATION_INSIGHTS_KEY",
              "value": "[reference(concat('Microsoft.Insights/components/', variables('applicationInsightsName'))).InstrumentationKey]"
            }
            ...
          ]
        } 
      }
    }
  }
},
{
  "name": "[concat('reference', copyIndex(1))]",
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2015-01-01",
  "copy": {
    "name": "storageAppSettings",
    "count": "[parameters('resultsShardCount')]"
  },
  "properties": {
    "mode": "Incremental",
    "template": {
      "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "resources": [],
      "outputs": {
        "storageAppSettings": {
          "type": "array",
          "value": "[concat(reference(concat('reference', copyIndex())).outputs.storageAppSettings.value, array(reference(concat('reference', copyIndex())).outputs.storageAppSetting.value))]"
        },
        "storageAppSetting": {
          "type": "object",
          "condition": "[less(copyIndex(1), parameters('resultsShardCount'))]",
          "value": {
            "name": "[concat('STORAGE_CONNECTION_STRING_', padLeft(copyIndex(1), 2, '0'))]",
            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageDataAccountNames')[min(variables('maximumShardIndex'), copyIndex(1))],';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageDataAccountNames')[min(variables('maximumShardIndex'), copyIndex(1))]), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
          }
        }
      }
    }
  }
},
...

解释这是如何工作的:

reference0部署用于:

  • 输出初始storageAppSettings数组作为空数组。
  • 输出第一个连接字符串app设置对象。
  • 输出Web应用程序所需的所有其他应用程序设置对象的数组。

然后使用referenceNcopy部署进行循环,每个shard我要部署一个(或者在每种情况下为每个电子邮件收件人一个)。每个人都做到以下几点:

  • 输出新的storageAppSettings数组作为storageAppSettings数组和前一次迭代storageAppSetting中生成的referenceN-1对象的串联。
  • 输出Nth storageAppSetting对象。

请注意,在最后的referenceN上,我们不需要输出storageAppSetting,因为第一个是在reference0中创建的,所以为了整洁,我们有一个condition来阻止它。不幸的是,即使condition存在,value仍然被评估,导致索引超出界限错误,除非你使用像min(variables('maximumShardIndex'), copyIndex(1))这样的东西来保护它,其中变量maximumShardIndex被定义为[sub(parameters('resultsShardCount'), 1)]。另一个解决方法,但有了它,它工作正常。

因此,最终storageAppSettingsreference数组输出是我们完整的连接字符串应用程序设置对象数组,additionalAppSettingsreference0数组输出是我们想要的所有其他应用程序设置对象连接字符串。

最后,您可以在Web应用程序中创建appSettings数组,作为这两个数组的并集:

{
  "apiVersion": "2015-08-01",
  "type": "Microsoft.Web/sites",
  ...
  "properties": {
    "siteConfig": {
      "appSettings": "[union(reference('reference0').outputs.additionalAppSettings.value, reference(concat('reference', parameters('resultsShardCount'))).outputs.storageAppSettings.value)]"
    }
  },
  ...
}

我已对此进行了测试,并且已成功部署了一个Web应用程序,该应用程序根据resultsShardCount模板参数指定对N个存储帐户进行数据分片。

我认为你的解决方案看起来大致相同,除了建立一个连接字符串name / value对象的数组,你将从传入模板的收件人列表中建立一个类似的数组。

© www.soinside.com 2019 - 2024. All rights reserved.