Azure templates: Dynamically output all items created in CopyIndex() iteration

Viewed 838

Taking the following simple template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  },
  "variables": {
    "nicName": "TESTNIC-",
    "ipConfigName": "ipconfig",
    "subnetRef": "/subscriptions/90a34ad-46aa-01a3-a3d4-223ac11bd6b3/resourceGroups/aResourceGroup/providers/Microsoft.Network/virtualNetworks/aVirtualNetwork/subnets/subnet-032"
  },
  "resources": [
    {
      "apiVersion": "2017-03-01",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('nicName'),copyIndex())]",
      "location": "[resourceGroup().location]",
      "tags": {
        "displayName": "[concat(variables('nicName'),copyIndex())]"
      },
      "dependsOn": [],
      "copy": {
        "count": 2,
        "name": "nicLoop"
      },
      "properties": {
        "ipConfigurations": [
          {
            "name": "[variables('ipconfigName')]",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      }
    }
  ],
  "outputs": {
    "oNic": {
      "type": "string",
      "value": "[concat(variables('nicName'),0)]"
      //"value": "[resourceGroup().name]"
    }
  }
}

As copyIndex() is not allowed in outputs.oNIC.value, how do I output all networkInterfaces created in the copy, without specifically naming them?

In the above template, I have specified two nics, but in reality, there will be other resource types and I don't know how many there will be.

Even being able to return all instances of /networkInterfaces in a given resource would be a step in the right direction but I can't even seem to do that:

"outputs": {
  "oNic": {
    "type": "object",
    "value": "[reference(concat(resourceGroup().id,'Microsoft.Network/networkInterfaces'))]"
  }
}

or

"outputs": {
  "oNic": {
    "type": "object",
    "value": "[reference('Microsoft.Network/networkInterfaces')]"
  }
}

I'm at a loss on this one. TIA

Update: reasoning:

As brief as possible: Part of the IP address is in the VMs hostname (client requirement), so the name of the VM is generated at deploy time. The template hierarchy looks something like:

#Deploy VM
DeployVM.json
    └ createNIC.json
        └ CreateVM.json
            └ createDataDisks.json

#Configure VM
ConfigureVM.json

CreateDataDisks actual template is "written out" by powershell (due to complexities of different types of data disks)

In order to simplify things (believe it or not), I have split the deployment into two separate deployment calls from PowerShell / VSTS / RunBook. The first actually deploys the VM(s) and the second configures it, using DSC and customScriptExtension resources. A complete deployment may have multiple servers with different roles, such as DB, WEB, client, although one set of templates / call will deploy only one role. A complete powershell script might look like:

$oDeploy = New-AzureRmResourceGroupDeployment -TemplateFile deployDatabase.json -role "Database" -Quantity 1
New-AzureRmResourceGroupDeployment -TemplateFile configureDatabase.json -role "Database" -VMName $oDeploy.vmNames

$oDeploy = New-AzureRmResourceGroupDeployment -TemplateFile deployWeb.json -role "Web" -Quantity 4
New-AzureRmResourceGroupDeployment -TemplateFile configureWeb.json -role "Web" -VMName $oDeploy.vmNames

$oDeploy = New-AzureRmResourceGroupDeployment -TemplateFile deployClientTypeA.json -role "ClientTypeA" -Quantity 1
New-AzureRmResourceGroupDeployment -TemplateFile configureClientTypeA.json -role "ClientTypeA" -VMName $oDeploy.vmNames

$oDeploy = New-AzureRmResourceGroupDeployment -TemplateFile deployClientTypeB.json -role "ClientTypeB" -Quantity 2
New-AzureRmResourceGroupDeployment -TemplateFile configureClientTypeB.json -role "ClientTypeB" -VMName $oDeploy.vmNames

Although I might have to do something like this, unless I can use CopyIndex to iterate over an array within the template (which I think I can. Just putting it out there):

$oDeploy = New-AzureRmResourceGroupDeployment -TemplateFile deployWeb.json -role "Web" -Quantity 4
foreach($vm in $oDeploy.vm)
{
    New-AzureRmResourceGroupDeployment -TemplateFile configureWeb.json -role "Web" -VMName $vm
}

Good plan (I thought) until realising that I couldn't get all the VM names out of deploy{Role}.json to pass to configure{role}.json.

The other problem is to do with these pesky datadisks. The idea is that the deployment can be rerun with modifications / additions , so perhaps the first run creates three data disks, whereas the second one creates a fourth data disk. The real issue is with keeping the LUN ID unique. On the first deployment run, it starts at zero and increments to 2. On the second run, it again starts at zero, but zero is already taken. What I need to be able to do is sum the total number of datadisk resources and offset the count (by three) so on the second run, the LUN ID starts at two. There is no way that I know of to sum the number of resources in pure templates, so I use powershell, but as there may be more that one VM with multiple datadisks, I need to target the specific VM, which I need the name for, which needs to be outputted from the parent template, so powershell can pick it up and use it.

1 Answers
Related