Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I loop over properties in ARM templates?

I have an ARM template where I set up a load balancer and I want to add a number of port openings by adding rules and probes to the LB.

This is the template I have so far:

    {
        "type": "Microsoft.Network/loadBalancers",
        "name": "LB-front",
        "apiVersion": "2016-03-30",
        "location": "westeurope",
        "tags": { },
        "properties": {
            "frontendIPConfigurations": [
                {
                    "name": "LoadBalancerIPConfig",
                    "properties": {
                        "privateIPAllocationMethod": "Dynamic",
                        "publicIPAddress": {
                            "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_lbipdev_0_name'))]"
                        }
                    }
                }
            ],
            "backendAddressPools": [
                {
                    "name": "LoadBalancerBEAddressPool"
                }
            ],
            "loadBalancingRules": [
                {
                    "name": "AppPortLBRule1",
                    "properties": {
                        "frontendIPConfiguration": {
                            "id": "[parameters('loadBalancers_LB_dev_id_6')]"
                        },
                        "frontendPort": 80,
                        "backendPort": 80,
                        "enableFloatingIP": false,
                        "idleTimeoutInMinutes": 5,
                        "protocol": "Tcp",
                        "loadDistribution": "Default",
                        "backendAddressPool": {
                            "id": "[parameters('loadBalancers_LB_dev_id_7')]"
                        },
                        "probe": {
                            "id": "[parameters('loadBalancers_LB_dev_id_8')]"
                        }
                    }
                },
                {
                    "name": "AppPortLBRule2",
                    "properties": {
                        "frontendIPConfiguration": {
                            "id": "[parameters('loadBalancers_LB_dev_id_9')]"
                        },
                        "frontendPort": 81,
                        "backendPort": 81,
                        "enableFloatingIP": false,
                        "idleTimeoutInMinutes": 5,
                        "protocol": "Tcp",
                        "loadDistribution": "Default",
                        "backendAddressPool": {
                            "id": "[parameters('loadBalancers_LB_dev_id_10')]"
                        },
                        "probe": {
                            "id": "[parameters('loadBalancers_LB_dev_id_11')]"
                        }
                    }
                },
                {
                    "name": "AppPortLBRule3",
                    "properties": {
                        "frontendIPConfiguration": {
                            "id": "[parameters('loadBalancers_LB_dev_id_12')]"
                        },
                        "frontendPort": 82,
                        "backendPort": 82,
                        "enableFloatingIP": false,
                        "idleTimeoutInMinutes": 5,
                        "protocol": "Tcp",
                        "loadDistribution": "Default",
                        "backendAddressPool": {
                            "id": "[parameters('loadBalancers_LB_dev_id_13')]"
                        },
                        "probe": {
                            "id": "[parameters('loadBalancers_LB_dev_id_14')]"
                        }
                    }
                }
            ],
            "probes": [
                {
                    "name": "AppPortProbe1",
                    "properties": {
                        "protocol": "Tcp",
                        "port": 80,
                        "intervalInSeconds": 5,
                        "numberOfProbes": 2
                    }
                },
                {
                    "name": "AppPortProbe2",
                    "properties": {
                        "protocol": "Tcp",
                        "port": 81,
                        "intervalInSeconds": 5,
                        "numberOfProbes": 2
                    }
                },
                {
                    "name": "AppPortProbe3",
                    "properties": {
                        "protocol": "Tcp",
                        "port": 82,
                        "intervalInSeconds": 5,
                        "numberOfProbes": 2
                    }
                }
            ],
            "inboundNatRules": [],
            "outboundNatRules": [],
            "inboundNatPools": []
        },
        "resources": [],
        "dependsOn": [
            "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_lbipdev_1_name'))]"
        ]
    },

(some details omitted)

What I would like to do is to have an array of the port numbers I want to create rules and probes for and loop over those instead of explicitly having to write each rule and probe as a property for the resource.

Basically I would like a parameter or variable in my template like this:

"ports": [ 80, 81, 82, ...]

and that I could loop over this similar to this: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple.

like image 409
Lee G. Avatar asked Jan 26 '17 20:01

Lee G.


People also ask

How do I use existing resources in arm template?

To modify existing resources using ARM templates, export the template for the resource from within the Azure Portal. Then download it locally. You can then modify it to update settings for Cosmos resources. ARM templates have api-versions.

Can you create a nested loop in an arm template?

Have you ever wanted to create a nested loop in an ARM template? Currently, it’s not possible to create resources within a nested loop. You can use the copy element to create multiple instances of a resource by looping over an array. But you can’t loop over an inner array to create sub-resources.

How do I loop an Azure Resource Manager (ARM) template?

There is only one way to loop in an Azure Resource Manager (ARM) template. By adding the copy element to the resources section of your template, you can set the number of resources to deploy. You also avoid having to repeat template syntax. This is very useful to create multiple instance of a specific resource.

How do you use a copy loop in a template?

By adding copy loop to the properties section of a resource in your template, you can dynamically set the number of items for a property during deployment. You also avoid having to repeat template syntax. You can only use copy loop with top-level resources, even when applying copy loop to a property.

What is the use of reference function in arm templates?

That brought me to the reference function in ARM templates. This can create a reference to any object and you can refer to the properties of these objects. It’s very simple actually, using this, to figure out what properties an object has. For instance, I want to find the key URL.


3 Answers

Indeed you can! Copy does work with properties!

Create a parameter or variable like this (this example will use parameter array):

"lbRules": {
  "type": "array",
  "defaultValue": [
    {
      "name": "httpPort",
      "frontendPort": "80",
      "backendPort": "80",
      "protocol": "tcp"
    },
    {
      "name": "customAppPort",
      "frontendPort": "8080",
      "backendPort": "8888",
      "protocol": "tcp"
    },
    {
      "name": "httpsPort",
      "frontendPort": "443",
      "backendPort": "443",
      "protocol": "tcp"
    }
  ]
}

Use this parameter in the Loadbalancer resource using copy like this that will create that many probes and rules that you defined in your parameter array:

{
  "apiVersion": "[variables('lbApiVersion')]",
  "type": "Microsoft.Network/loadBalancers",
  "name": "[parameters('myLoadBalancer')]",
  "location": "[parameters('computeLocation')]",
  "dependsOn": [
    "[concat('Microsoft.Network/publicIPAddresses/',concat(parameters('lbIPName'),'-','0'))]"
  ],
  "properties": {
    "frontendIPConfigurations": [
      {
        "name": "LoadBalancerIPConfig",
        "properties": {
          "publicIPAddress": {
            "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPName'),'-','0'))]"
          }
        }
      }
    ],
    "backendAddressPools": [
      {
        "name": "LoadBalancerBEAddressPool",
        "properties": {}
      }
    ],

    "copy": [
      {
        "name": "probes",
        "count": "[length(parameters('lbRules'))]",
        "input": {
          "name": "[concat(parameters('lbRules')[copyIndex('probes')].name,'Probe')]",
          "properties": {
            "intervalInSeconds": 5,
            "numberOfProbes": 2,
            "port": "[parameters('lbRules')[copyIndex('probes')].backendPort]",
            "protocol": "[parameters('lbRules')[copyIndex('probes')].protocol]"

          }
        }
      },

      {
        "name": "loadBalancingRules",
        "count": "[length(parameters('lbRules'))]",
        "input": {
          "name": "[parameters('lbRules')[copyIndex('loadBalancingRules')].name]",
          "properties": {
            "frontendIPConfiguration": {
              "id": "[concat(resourceId('Microsoft.Network/loadBalancers', parameters('myLoadBalancer')),'/frontendIPConfigurations/LoadBalancerIPConfig')]"
            },
            "frontendport": "[parameters('lbRules')[copyIndex('loadBalancingRules')].frontendport]",
            "backendport": "[parameters('lbRules')[copyIndex('loadBalancingRules')].backendport]",
            "enableFloatingIP": false,
            "idleTimeoutInMinutes": "5",
            "protocol": "[parameters('lbRules')[copyIndex('loadBalancingRules')].protocol]",
            "backendAddressPool": {
              "id": "[concat(resourceId('Microsoft.Network/loadBalancers', parameters('myLoadBalancer')),'/backendAddressPools/LoadBalancerBEAddressPool')]"
            },
            "probe": {
              "id": "[concat(variables('lbID0'),'/probes/', parameters('lbRules')[copyIndex('loadBalancingRules')].name,'Probe')]"
            }
          }
        }
      }
    ],


    "inboundNatPools": []
  },

  }
}

More info can be found here:

  • https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#property-iteration
  • https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/copy-properties
like image 106
HobPet Avatar answered Oct 10 '22 16:10

HobPet


It is now possible to loop on properties or on child resources as stated in https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#property-iteration or in https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#create-multiple-instances-of-a-child-resource

You can a child resource extension (e.g. WebSite/Extension) as a top-level resource by following the format for the type: {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}. For instance Microsoft.Web/sites/siteextensions

You have also to reference the parent resource in the child resource by a concat. For instance: "name": "[concat('mywebsite', '/', 'myextension', copyIndex())]"

like image 45
user3214451 Avatar answered Oct 10 '22 15:10

user3214451


You can only apply the copy object to a top-level resource.

You cannot apply it to a property on a resource type, or to a child resource.

"resources": [
  {
    "type": "{provider-namespace-and-type}",
    "name": "parentResource",
    "copy": {  
      /* yes, copy can be applied here */
    },
    "properties": {
      "exampleProperty": {
        /* no, copy cannot be applied here */
      }
    },
    "resources": [
      {
        "type": "{provider-type}",
        "name": "childResource",
        /* copy can be applied if resource is promoted to top level */ 
      }
    ]
  }
] 

Source of Quotation: Deploy multiple instances of resources in Azure Resource Manager templates

You can loop over properties in ARM Template ONLY IF the copy object is applied to a top-level resource, which is in your case the "Microsoft.Network/loadBalancers", but that will also create multiple copy of the said resource.

If this is not what you want to achieve, I would recommend you to keep your existing way until ARM Template support copy object to property on a resource type in the future.

like image 5
juvchan Avatar answered Oct 10 '22 14:10

juvchan