Use the Copy function to deploy multiple resources after each other
A while ago I was confronted with the fact one of our Azure App Services needed multiple hostname bindings.
I was planning to do this by making multiple Microsoft.Web/sites/hostNameBindings
resources, for this specific App Service, in our ARM template. When deploying I was confronted with the following error
{
"ErrorEntity": {
"Code": "Conflict",
"Message": "Cannot modify this site because another operation is in progress. [some more details]",
"ExtendedCode": "59203",
"MessageTemplate": "Cannot modify this site because another operation is in progress. Details: {0}",
"Parameters": [
"Id: {guid}, OperationName: {someName}, CreatedTime: 3/21/2020 11:13:54 PM, RequestId:{guid}, EntityType: 1"
],
"InnerErrors": null
}
}
],
"Innererror": null
}
This is because adding a hostnameBinding
can’t be done simultaneously. The way to solve this is by using the copy()
function.
To work with this function, you first need an array with data. I’ve named mine hostenameBindings
as you can see below.
"variables": {
"hostnameBindings": [
"[concat(variables('appServiceCname') ,'.customer.com')]",
"[concat(variables('appServiceCname') ,'-seconddomain.customer.com')]",
"[concat(variables('appServiceCname') ,'-another.customer.nl')]"
]
}
Now continue creating your ARM template like you’re used to, but when defining the hostnameBindings
resource(s), check out this sample.
{
"type": "Microsoft.Web/sites/hostNameBindings",
"apiVersion": "2019-08-01",
"name": "[concat(variables('appServiceName'), '/', variables('hostnameBindings')[copyIndex()])]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('appServiceName'))]",
"[resourceId('Microsoft.Web/certificates', variables('certificate').name)]"
],
"copy": {
"name": "hostNameBindingsEndpointLoop",
"mode": "serial",
"batchSize": 1,
"count": "[length(variables('hostnameBindings'))]"
},
"properties": {
"siteName": "Sitecore",
"hostNameType": "Verified",
"sslState": "SniEnabled",
"thumbprint": "[parameters('certificateThumbprint')]"
}
},
Over here I’m telling the resource manager to deploy these resources in serial
with a batchSize
of 1. This will make sure all hostnameBindings
resources will be deployed after each other.
You can use the copyIndex()
function to get the N-th element from your array.
This is really powerful stuff.
You can use the copy
function for other purposes also. If you need to create multiple, similar, resources define the differences in the variables
and use the copy
function to create them. This will make your templates overall a bit smaller and more maintainable in the end.