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

Parameters 参数数组中的Azure资源管理器模板网站应用程序设置,parameters,azure-resource-manager,appsettings,Parameters,Azure Resource Manager,Appsettings,我正在尝试获取一系列参数——特别是电子邮件收件人列表——并将其写入我的web应用程序的应用程序设置中 下面的模板可以工作,但显然只写入数组中的第一项和第二项 我已经研究了复制函数,但它似乎只处理对象的创建,但我需要添加到现有的键值对列表中 { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", ... "parameters": { "Em

我正在尝试获取一系列参数——特别是电子邮件收件人列表——并将其写入我的web应用程序的应用程序设置中

下面的模板可以工作,但显然只写入数组中的第一项和第二项

我已经研究了复制函数,但它似乎只处理对象的创建,但我需要添加到现有的键值对列表中

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

您可以在properties对象中使用copy函数-请参阅:


可以将此视为部署模板之前的复制/粘贴操作。

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

<other app settings>
...
"STORAGE_CONNECTION_STRING_00": "<connectionString00>",
"STORAGE_CONNECTION_STRING_01": "<connectionString01>",
...
在我的第一次尝试中,我尝试使用
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'))]"
    }
  },
  ...
}
不幸的是,模板变量被急切地求值,这意味着您不能引用任何资源属性。这对于评估连接字符串和我的一些其他应用程序设置都是一个问题,其中包含对我在模板中部署的其他资源的引用

研究该问题会导致查看嵌套模板,尤其是在嵌套模板上使用
copy
在数组中建立动态评估对象的列表

这种方法看起来很有前途,直到我偶然发现了ARM模板:

...
{
  "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)]"
          }
        }
      }
    }
  }
},
...
对于嵌套模板,不能使用在嵌套模板中定义的参数或变量

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

经过一番深思熟虑,我最终找到了一种方法,使其仅使用输出参数,从而使其能够使用嵌套模板工作:

...
{
  "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 settings对象
  • 输出web应用程序所需的所有其他应用程序设置对象的数组
然后使用
copy
循环
referenceN部署,我要部署的每个碎片一个(或者在您的情况下,每个电子邮件收件人一个)。每个人都做以下工作:

  • 将新的
    storageAppSettings
    数组作为
    storageAppSettings
    数组和在上一次迭代
    referenceN-1
    中生成的
    storageAppSetting
    对象的串联输出
  • 输出第n个
    storageAppSetting
    对象
请注意,在最终的
referenceN
上,我们不需要输出
storageAppSetting
,因为第一个是在
reference0
中创建的,因此对于整洁性,我们有一个
条件来阻止它。不幸的是,即使存在
条件
,仍然会计算
,导致索引越界错误,除非您使用
min(变量('maximumShardIndex')、copyIndex(1))
,其中变量
maximumShardIndex
定义为
[sub(参数('resultsShardCount'),1)]
。另一种解决方法,但有了它,就可以正常工作了

因此,来自最终
引用的
storageAppSettings
数组输出是连接字符串应用程序设置对象的完整数组,而来自
reference0
additionalAppSettings
数组输出则是我们希望连接字符串旁边的所有其他应用程序设置对象

最后,您可以在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
template参数指定的N个存储帐户对数据进行切分


我认为您的解决方案大致相同,除了不构建连接字符串
名称
/
对象数组之外,您将从传递到模板的收件人列表中构建一个类似的数组。

我看不出如何使用复制函数。它需要三个参数。第一个是名称。该名称将成为“粘贴”属性的名称。但我不需要新属性。我要添加到现有的“属性”属性。第三个参数是一个类。但我不想要类。我想要一个键值对。你是对的,我认为这在这里不起作用-你正在尝试从数组转换为JSON的其他blob。我想不出一个简单的方法来实现这一点(我甚至不确定嵌套部署是否可行,因为属性名称不确定)一个选项是将整个properties对象作为参数传入,并在模板之外进行“计算”。