0
votes

When deploying an ARM template using resource iteration, I'd like to pass the resource properties as an object.

Doing this would allow for a different set of parameters to exist within each element the copy array. The reason for this is because some properties may need to be conditionally included or excluded depending on the values of others. For example, in the case of an API Management product, the documentation states the following with regard to the subscriptionsLimit property -

Can be present only if subscriptionRequired property is present and has a value of false.

However, when deploying the example template below the deployment hangs in Azure. Looking in to the related events, I can see that the action the deploy the resource keeps failing with an Internal Server Error (500), but there are no additional details.

If I refer to each parameter in the properties object using variables('productsJArray')[copyIndex()].whatever then the deployment succeeds. However, this is undesirable as it means that every properties object would have to contain identical parameters, which is not always permissible and may cause the deployment to fail.

Example template

Note that I've output variables('productsJArray')[copyIndex()] and it is a valid object. I've even copied the output in to the template and deployed it successfully.

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "apiManagementServiceName": {
            "type": "string",
            "metadata": {
                "description": "The name of the API Management instance."
            }
        },
        "productsJson": {
            "type": "string",
            "metadata": {
                "description": "A JSON representation of the Products to add."
            }
        }
    },
    "variables": {
        "productsJArray": "[json(parameters('productsJson'))]"
    },
    "resources": [
        {
            "condition": "[greater(length(variables('productsJArray')), 0)]",
            "type": "Microsoft.ApiManagement/service/products",
            "name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex()].name)]",
            "apiVersion": "2018-06-01-preview",
            "properties": "[variables('productsJArray')[copyIndex()]]",
            "copy": {
                "name": "productscopy",
                "count": "[if(greater(length(variables('productsJArray')), 0), length(variables('productsJArray')), 1)]"
            }
        }
    ]
}

Example parameters

{
        "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
                "apiManagementServiceName": {
                        "value": "my-api-management"
                },
                "productsJson": {
                        "value": "[{\"name\":\"my-product\",\"displayName\":\"My Product\",\"description\":\"My product is awesome.\",\"state\":\"published\",\"subscriptionRequired\":true,\"approvalRequired\":false}]"
                }
        }
}

Output of variable 'productsJArray[0]'

"outputs": {
        "properties": {
                "type": "Object",
                "value": {
                        "approvalRequired": false,
                        "description": "My product is awesome.",
                        "displayName": "My Product",
                        "name": "my-product",
                        "state": "published",
                        "subscriptionRequired": true
                }
        }
}
1
you are not showing the relevant part of the template, show your object, just want to be sure i understand you correctly4c74356b41
You're quite right, I got a little trigger happy. I've added an example parameters file, showing how I'm passing the data in. I've also added the output of [variables('productsJArray')[copyIndex()]], showing that it is a valid object. Thanks.David Gard
subscriptionsLimit doesnt exist here, although you said it should be there? I think I know where this is going anyway4c74356b41
To confirm, using the value of the output object properties results in a working deployment - however referencing variables('productsJArray')[copyIndex()] results in a failed deployment. subscriptionsLimit doesn't need to exist; I just used it as an example of a parameter that either must or must not exist in the properties object depending on the value of another parameter. In my example, subscriptionRequired has a value of true, and so subscriptionsLimit must not exist. Thanks.David Gard

1 Answers

0
votes

The issue here was that I was passing including name parameter along with other parameters when setting resource properties. This is obviously wrong, but it would have been helpful if MS had handled the error in a more human friendly way (guess they can't think of everything).

I've updated my incoming productsJson parameter -

[{\"name\":\"cs-automation\",\"properties\":{\"displayName\":\"CS Automation Subscription\",\"state\":\"published\",\"description\":\"Allows access to the ConveyorBot v1 API.\",\"subscriptionRequired\":true,\"approvalRequired\":false}}]

And I'm now passing only the required 'properties' -

"resources": [
    {
        "type": "Microsoft.ApiManagement/service/products",
        "name": "[concat(parameters('apiManagementServiceName'), '/', variables('productsJArray')[copyIndex()].name)]",
        "apiVersion": "2018-06-01-preview",
        "properties": "[variables('productsJArray')[copyIndex()].properties]"
    }
]