Azure ARM 模板如何对多个部分使用副本

Azure ARM template how to use copy for multiple parts

我有一个问题找不到解决方案,当我尝试使用复制在我的仪表板 ARM 模板中动态创建多个部分时。

当我尝试在其中一个键中使用“[copyIndex()]”时出现错误,正如我从错误消息中了解到的那样,这是行不通的。但我不确定如何解决这个问题,所以任何想法将不胜感激。

"copy": [
  {
    "name": "servers",
    "count": "[length(parameters('locationKeys'))]",
    "input": {
      "[copyIndex('servers')]": {
        "position": {
          "x": "[mul(copyIndex('servers'), 4)]",
          "y": 1,
          "colSpan": 2,
          "rowSpan": 1
        }
      }
    }
  }
]

正如您在上面的示例中看到的那样,这就是失败的地方

"[copyIndex('servers')]": {

我收到这个错误

Error: Code=InvalidTemplate; Message=Deployment template validation failed: 
'Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject.'.

创建仪表板的结构如下所示

"properties": {
  "lenses": {
    "0": {
      "order": 0,
      "parts": {
        "0": {},
        "1": {},
        ...

而且我在"parts"键下有复制功能

解决这个问题的方法是删除复制功能并复制代码,但是我很难让它与任何给定数量的 "locations" 一起工作,因为我需要对它们进行硬编码.

基本上这就是我最终想要得到的。

还有其他好的解决方案可以解决这个问题吗?

更新

这是我在管道中的 Azure DevOps 任务中引用的两个模板。请注意,我现在需要执行 parameters('locationKeys')[0] 并复制所有块,而不是使用 parameters('locationKeys')[copyIndex()].

进行复制

parameters.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "locationNames": {
      "value": "#{locationNames}"
    }
  }
}

deploy.json

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appName": {
      "type": "string",
      "defaultValue" : "myApp"
    },
    "locationNames": {
      "type": "array"
    }
  },
  "variables": {
    "dashboardName": "[concat(parameters('appName'), '-dashboard')]"
  },
  "resources": [
    {
      "name": "[variables('dashboardName')]",
      "type": "Microsoft.Portal/dashboards",
      "apiVersion": "2015-08-01-preview",
      "location": "westeurope",
      "tags": {
        "hidden-title": "24/7 Operations"
      },
      "properties": {
        "lenses": {
          "0": {
            "order": 0,
            "parts": {
              "0": {
                "position": {
                  "x": 0,
                  "y": 0,
                  "colSpan": 4,
                  "rowSpan": 1
                },
                "metadata": {
                  "inputs": [],
                  "type": "Extension/HubsExtension/PartType/MarkdownPart",
                  "settings": {
                    "content": {
                      "settings": {
                        "content": "[concat('# ', parameters('locationNames')[0])]",
                        "title": "",
                        "subtitle": ""
                      }
                    }
                  }
                }
              },
              "1": {
                "position": {
                  "x": 4,
                  "y": 0,
                  "colSpan": 4,
                  "rowSpan": 1
                },
                "metadata": {
                  "inputs": [],
                  "type": "Extension/HubsExtension/PartType/MarkdownPart",
                  "settings": {
                    "content": {
                      "settings": {
                        "content": "[concat('# ', parameters('locationNames')[1])]",
                        "title": "",
                        "subtitle": ""
                      }
                    }
                  }
                }
              },
              "2": {
                "position": {
                  "x": 8,
                  "y": 0,
                  "colSpan": 4,
                  "rowSpan": 1
                },
                "metadata": {
                  "inputs": [],
                  "type": "Extension/HubsExtension/PartType/MarkdownPart",
                  "settings": {
                    "content": {
                      "settings": {
                        "content": "[concat('# ', parameters('locationNames')[2])]",
                        "title": "",
                        "subtitle": ""
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "dependsOn": []
    }
  ],
  "outputs": {
    "resourceGroupId": {
      "type": "string",
      "value": "[resourceGroup().id]"
    }
  }
}

更新 2

这是使用对象而不是数组的工作示例。我通过将 collector.json 和 transform.json 上传到 http://myjson.com 并在 运行 部署时将它们作为属性包括在内,使用 PowerShell 在本地进行了验证。

parameters.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "azureEnvironment": {
      "value": "#{azureEnvironment}"
    },
    "locationKeys": {
      "value": "#{locationKeys}"
    },
    "locationNames": {
      "value": "#{locationNames}"
    },
    "transformTemplateLink": {
      "value": "#{transform}"
    },
    "collectorTemplateLink": {
      "value": "#{collector}"
    }
  }
}

deploy.json

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appName": {
      "type": "string",
      "defaultValue": "myApp"
    },
    "azureEnvironment": {
      "type": "string"
    },
    "locationKeys": {
      "type": "array"
    },
    "locationNames": {
      "type": "array"
    },
    "transformTemplateLink": {
      "type": "string",
      "defaultValue": "[uri(deployment().properties.templateLink.uri, 'transform.json')]"
    },
    "collectorTemplateLink": {
      "type": "string",
      "defaultValue": "[uri(deployment().properties.templateLink.uri, 'collector.json')]"
    }
  },
  "resources": [
    {
      "apiVersion": "2015-01-01",
      "name": "collector",
      "type": "Microsoft.Resources/deployments",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[parameters('collectorTemplateLink')]",
          "contentVersion": "1.0.0.0"
        },
        "parameters": {
          "transformTemplateUri": {
            "value": "[parameters('transformTemplateLink')]"
          },
          "locationNames": {
            "value": "[parameters('locationNames')]"
          }
        }
      }
    },
    {
      "name": "[concat(parameters('appName'), '-dash-', parameters('azureEnvironment'))]",
      "type": "Microsoft.Portal/dashboards",
      "apiVersion": "2015-08-01-preview",
      "location": "westeurope",
      "tags": {
        "hidden-title": "[concat('24/7 Operations - (', parameters('azureEnvironment'), ')')]"
      },
      "properties": {
        "lenses": {
          "0": {
            "order": 0,
            "parts": "[reference('collector').outputs.result.value]"
          }
        }
      },
      "dependsOn": [
        "collector"
      ]
    }
  ],
  "outputs": {
    "resourceGroupId": {
      "type": "string",
      "value": "[resourceGroup().id]"
    }
  }
}

collector.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "transformTemplateUri": {
      "type": "string"
    },
    "locationNames": {
      "type": "array"
    }
  },
  "variables": {
    "count": "[length(parameters('locationNames'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2015-01-01",
      "name": "loop-0",
      "properties": {
        "mode": "Incremental",
        "parameters": {},
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {},
          "variables": {},
          "resources": [],
          "outputs": {
            "collection": {
              "type": "object",
              "value": {}
            }
          }
        }
      }
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2015-01-01",
      "name": "[concat('loop-', copyIndex(1))]",
      "copy": {
        "name": "iterator",
        "count": "[variables('count')]",
        "mode": "serial"
      },
      "dependsOn": [
        "[concat('loop-', copyIndex())]"
      ],
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[parameters('transformTemplateUri')]"
        },
        "parameters": {
          "state": {
            "value": "[reference(concat('loop-', copyIndex())).outputs.collection.value]"
          },
          "index": {
            "value": "[copyIndex()]"
          },
          "locationNames": {
            "value": "[parameters('locationNames')]"
          }
        }
      }
    }
  ],
  "outputs": {
    "result": {
      "type": "object",
      "value": "[reference(concat('loop-', variables('count'))).outputs.collection.value]"
    }
  }
}

transform.json

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "state": {
      "type": "object",
      "defaultValue": {}
    },
    "index": {
      "type": "int"
    },
    "locationNames": {
      "type": "array"
    }
  },
  "variables": {
    "instance": {
      "[string(parameters('index'))]": {
        "position": {
          "x": "[mul(parameters('index'), 4)]",
          "y": 0,
          "colSpan": 4,
          "rowSpan": 1
        },
        "metadata": {
          "inputs": [],
          "type": "Extension/HubsExtension/PartType/MarkdownPart",
          "settings": {
            "content": {
              "settings": {
                "content": "[concat('# ', parameters('locationNames')[parameters('index')])]",
                "title": "",
                "subtitle": ""
              }
            }
          }
        }
      }
    }
  },
  "resources": [],
  "outputs": {
    "collection": {
      "type": "object",
      "value": "[union(parameters('state'), variables('instance'))]"
    }
  }
}

如果您只是在变量部分尝试相同(但经过简化)的方法,您会收到此错误:

The variable name cannot be an expression.

我认为这同样适用于任何地方,你不能使用表达式来计算 属性 名称,只能计算值。话虽如此,如果你想创建一个循环,你需要使用嵌套部署作为迭代器。您将根据输入将需要的部分 inside\assemble 传递到那里并创建结果数组:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {
        "locations": [
            "eastus",
            "westeurope"
        ],
        "eastus": {
            "red": 1
        },
        "westeurope": {
            "blue": 2
        },
        "empty": []
    },
    "resources": [
        {
            "apiVersion": "2017-05-10",
            "name": "[concat('iterator-', copyIndex(1))]",
            "type": "Microsoft.Resources/deployments",
            "copy": {
                "name": "someName",
                "count": "[length(variables('locations'))]"
            },
            "properties": {
                "mode": "Incremental",
                "templateLink": {
                    "uri": "https://paste.ee/r/t5ca9/0"
                },
                "parameters": {
                    "source": {
                        "value": "[variables(variables('locations')[copyIndex()])]"
                    },
                    "state": {
                        "value": "[if(equals(copyIndex(), 0), variables('empty'), reference(concat('iterator-', copyIndex())).outputs.collection.value)]"
                    }
                }
            }
        }
    ],
    "outputs": {
        "results": {
            "type": "array",
            "value": "[reference(concat('iterator-', string(length(variables('locations'))))).outputs.collection.value]"
        }
    } }

您的迭代器如下所示:

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "source": {
            "type": "object"
        },
        "state": {
            "type": "array",
            "defaultValue": []
        }
    },
    "resources": [],
    "outputs": {
        "collection": {
            "type": "array",
            "value": "[concat(array(parameters('source')), parameters('state'))]"
        }
    }
}

ps。 link 是临时的(1 个月),但您可以在任何地方上传迭代器模板并进行硬编码,它不包含 secrets\no 数据。 pps。更简单的方法 - 在模板外构造它 (powershell\python\whatever) 并作为模板内的参数传递