Search code examples
azure-rm-templateazure-deployment

Iterate list using copy in ARM Template


I have an ARM template in which I provision a number of web apps. I want to add IP restrictions on these web apps allowing access only between theses. I can retrieve the IPs using:

reference(resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('appName1')),'2015-08-01').PossibleOutboundIpAddresses

It's the following that I don't know how to solve in a good manner.

  1. I have replaced the resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('appName1')) part with a variable instead to shorten it a bit. Can I shorten it even more somehow? It becomes even more complex as you'll see soon.

  2. I have created a resources section for each web app in which there is a properties section. In this section the ipSecurityRestrictions resides. As the PossibleOutboundIpAddresses returns a string I use split to create a list and copy to iterate the IP addresses. But it does not work for me and returns the following error message: The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified

The section looks like this:

"resources": [
            {
                "type": "config",
                "name": "web",
                "apiVersion": "2016-08-01",
                "properties": {
                    "copy": [
                        {
                            "name": "ipSecurityRestrictions",
                            "count": "[length(split(reference(variables('appName1'),'2015-08-01').PossibleOutboundIpAddresses, ','))]",
                            "input": {
                                "ipAddress": "[split(reference(variables('appName1'),'2015-08-01').PossibleOutboundIpAddresses, ',')[copyIndex('ipSecurityRestrictions')]]",
                                "subnetMask": "255.255.255.254"
                            }
                        }
                    ],
                },
                "dependsOn": [
                    "[resourceId('Microsoft.Web/sites', parameters('appName1'))]"
                ]
            }
        ]

I feel like I follow all examples I can find online exactly. Another problem with this is the many characters I'll have to write every time I want to reference the IP list. To make things worse, this list should be the merged one from all the provisioned web apps. So if I have 3 web apps the line is going to be incredible long and complicated.

  1. Is there a better solution to this?

Solution

  • ok, first question: can I make it shorter.
    answer: it really depends, judging on what you show, not really (you can drop api-version if the resources are in the same template).

    second question: The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified.
    answer: you cant do that, unfortunately (runtime\compile time drama). You'd have to use nested templates to achieve same outcome.

    third question: Is there a better solution to this?
    answer: probably. I'd create all 3 web apps as a nested deployment (NOT inline) and return an array of strings (similar to what you do)

    "outputs" : {
        "array": {
             "type": "array",
             "value": "[split(reference(variables('appName')]"
        }
    }
    

    then I'd process those in a single run with concat and something like what you are doing (but this have to be in a nested template as well). something like:

    "[concat(reference('deployment1').outputs.array.value, reference('deployment2').outputs.array.value, reference('deployment3').outputs.array.value)]"
    

    and then in the nested template you can do:

                    "copy": [
                        {
                            "name": "ipSecurityRestrictions",
                            "count": "[length(parameters('myArray'))]",
                            "input": {
                                "ipAddress": "[parameters('myArray')[copyIndex('ipSecurityRestrictions')]]]",
                                "subnetMask": "255.255.255.254"
                            }
                        }
                    ],