Azure ARM template for ServiceBus: cannot reference itself - azure

I wrote an ARM template to script the deploy and configuration of ServiceBus. One of the goals of the script was to make it easy to manage topics and subscriptions. In order to accomplish this, the script uses variables that are arrays.
This all works fine, but I'm seeing an issue whenever I try to use the same subscription name for two different topics. Now, I understand that a subscription can only be mapped to a single topic. The script attempts to account for that by joining the subscription name to the topic.
I should also note that the Azure UI will allow you to use the same subscription name beneath two topics. This script was derived from setting up this scenario via the azure console then exporting the ARM.
I have been over this script several dozen times and I'm not seeing the cause. Hoping new eyes will help.
Here is the script:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"envType": {
"type": "string",
"allowedValues": [ "dev", "prod" ],
"defaultValue": "dev",
"metadata": { "description": "The environment type being created" }
},
"sbSku": {
"type": "string",
"allowedValues": [ "Standard", "Premium" ],
"defaultValue": "Standard",
"metadata": { "description": "The messaging tier for service Bus namespace" }
}
},
"variables": {
"defaultSASKeyName": "RootManageSharedAccessKey",
"authRuleResourceId": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', variables('sbNamespaceName'), variables('defaultSASKeyName'))]",
"sbNamespaceName": "[concat(parameters('envType'), 'eventbus')]",
"sbVersion": "2017-04-01",
"sbTopics": [
"mytopic1",
"mytopic2",
"mytopic3",
"mytopic4"
],
"sbSubscriptions": [
{ "Name": "mysubA", "Topic": "mytopic1" },
{ "Name": "mysubB", "Topic": "mytopic2" },
{ "Name": "mysubB", "Topic": "mytopic3" },
{ "Name": "mysubC", "Topic": "mytopic4" }
]
},
"resources": [
{
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"name": "[variables('sbNamespaceName')]",
"properties": {},
"sku": {
"name": "[parameters('sbSku')]"
},
"tags": {},
"type": "Microsoft.ServiceBus/Namespaces"
},
{
"type": "Microsoft.ServiceBus/namespaces/topics",
"name": "[concat(variables('sbNamespaceName'), '/', variables('sbTopics')[copyIndex()])]",
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', variables('sbNamespaceName'))]"
],
"properties": {
"defaultMessageTimeToLive": "P14D",
"maxSizeInMegabytes": 1024,
"requiresDuplicateDetection": false,
"enablePartitioning": true
},
"copy": {
"name": "topiccopy",
"count": "[length(variables('sbTopics'))]",
"mode": "Serial",
"batchSize": 3
}
},
{
"type": "Microsoft.ServiceBus/namespaces/topics/subscriptions",
"name": "[concat(variables('sbNamespaceName'), '/', variables('sbSubscriptions')[copyIndex()].Topic, '/', variables('sbSubscriptions')[copyIndex()].Name)]",
"apiVersion": "2017-04-01",
"location": "East US",
"dependsOn": [
"[resourceId('Microsoft.ServiceBus/namespaces', variables('sbNamespaceName'))]",
"[resourceId('Microsoft.ServiceBus/namespaces/topics', variables('sbNamespaceName'), variables('sbSubscriptions')[copyIndex()].Topic)]"
],
"properties": {
"maxDeliveryCount": 10
},
"copy": {
"name": "subscriptioncopy",
"count": "[length(variables('sbSubscriptions'))]",
"mode": "Serial",
"batchSize": 1
}
}
],
"outputs": {
"NamespaceConnectionString": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryConnectionString]"
},
"SharedAccessPolicyPrimaryKey": {
"type": "string",
"value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryKey]"
},
"Topics": {
"type": "array",
"value": "[concat(variables('sbTopics'))]"
},
"Subscriptionss": {
"type": "array",
"value": "[concat(variables('sbSubscriptions'))]"
}
}
}
When executed with:
New-AzureRmResourceGroupDeployment -ResourceGroupName {xxx} -TemplateFile arm.servicebus.example.json
It returns:
New-AzureRmResourceGroupDeployment : 2:58:05 PM - Error: Code=InvalidTemplate; Message=Deployment template validation
failed: 'The template resource 'Microsoft.ServiceBus/namespaces/deveventbus/topics/mytopic3/subscriptions/mysubB'
cannot reference itself. Please see https://aka.ms/arm-template-expressions/#reference for usage details.'.
At line:1 char:1
+ New-AzureRmResourceGroupDeployment -ResourceGroupName Wiretappers_Ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
loymentCmdlet
New-AzureRmResourceGroupDeployment : The deployment validation failed
At line:1 char:1
+ New-AzureRmResourceGroupDeployment -ResourceGroupName Wiretappers_Ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [New-AzureRmResourceGroupDeployment], InvalidOperationException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
loymentCmdlet
The issue is caused by the third entry in the 'sbSubscriptions' array (mysubB/mytopic3). This is being processed in the third object beneath 'resources'.
If anyone can see my oversight, it would be appreciated.
PS. If anyone knows how to get the Azure tools to output the template json after it has expanded the "copy" node and the functions (resourceId, concat) that would be helpful as well.
UPDATE:2018-03-01
Here is a working template for future reference. See all comments below for details.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"envType": {
"type": "string",
"allowedValues": [ "dev", "prod" ],
"defaultValue": "dev",
"metadata": { "description": "The environment type being created" }
},
"sbSku": {
"type": "string",
"allowedValues": [ "Standard", "Premium" ],
"defaultValue": "Standard",
"metadata": { "description": "The messaging tier for service Bus namespace" }
}
},
"variables": {
"sbNamespaceName": "[concat(parameters('envType'), 'eventbus')]",
"sbVersion": "2017-04-01",
"sbTopics": [
"mytopic1",
"mytopic2",
"mytopic3",
"mytopic4"
],
"sbSubscriptions": [
{ "Name": "mysubA", "Topic": "mytopic1" },
{ "Name": "mysubB", "Topic": "mytopic2" },
{ "Name": "mysubB", "Topic": "mytopic3" },
{ "Name": "mysubC", "Topic": "mytopic4" }
]
},
"resources": [
{
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"name": "[variables('sbNamespaceName')]",
"properties": {},
"sku": {
"name": "[parameters('sbSku')]"
},
"tags": {},
"type": "Microsoft.ServiceBus/Namespaces"
},
{
"type": "Microsoft.ServiceBus/namespaces/topics",
"name": "[concat(variables('sbNamespaceName'), '/', variables('sbTopics')[copyIndex()])]",
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('sbNamespaceName')]"
],
"properties": {
"defaultMessageTimeToLive": "P14D",
"maxSizeInMegabytes": 1024,
"requiresDuplicateDetection": false,
"enablePartitioning": true
},
"copy": {
"name": "topiccopy",
"count": "[length(variables('sbTopics'))]",
"mode": "Serial",
"batchSize": 3
}
},
{
"type": "Microsoft.ServiceBus/namespaces/topics/subscriptions",
"name": "[concat(variables('sbNamespaceName'), '/', variables('sbSubscriptions')[copyIndex()].Topic, '/', variables('sbSubscriptions')[copyIndex()].Name)]",
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.ServiceBus/namespaces', variables('sbNamespaceName'))]",
"[resourceId('Microsoft.ServiceBus/namespaces/topics', variables('sbNamespaceName'), variables('sbSubscriptions')[copyIndex()].Topic)]"
],
"properties": {
"maxDeliveryCount": 10
},
"copy": {
"name": "subscriptioncopy",
"count": "[length(variables('sbSubscriptions'))]"
}
}
],
"outputs": {
"Topics": {
"type": "array",
"value": "[concat(variables('sbTopics'))]"
},
"Subscriptionss": {
"type": "array",
"value": "[concat(variables('sbSubscriptions'))]"
}
}
}

Ok, i dont know what the issue is\was, but this works:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"envType": {
"type": "string",
"allowedValues": [
"dev",
"prod",
"zlp"
],
"defaultValue": "zlp",
"metadata": {
"description": "The environment type being created"
}
},
"sbSku": {
"type": "string",
"allowedValues": [
"Standard",
"Premium"
],
"defaultValue": "Standard",
"metadata": {
"description": "The messaging tier for service Bus namespace"
}
}
},
"variables": {
"sbNamespaceName": "[concat(parameters('envType'), 'eventbus')]",
"sbVersion": "2017-04-01",
"sbTopics": [
"mytopic1",
"mytopic2",
"mytopic3",
"mytopic4"
],
"sbSubscriptions": [
{
"Name": "mysubA",
"Topic": "mytopic1"
},
{
"Name": "mysubB",
"Topic": "mytopic2"
},
{
"Name": "mysubB",
"Topic": "mytopic3"
},
{
"Name": "mysubC",
"Topic": "mytopic4"
}
]
},
"resources": [
{
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"name": "[variables('sbNamespaceName')]",
"properties": {},
"sku": {
"name": "[parameters('sbSku')]"
},
"tags": {},
"type": "Microsoft.ServiceBus/Namespaces"
},
{
"type": "Microsoft.ServiceBus/namespaces/topics",
"name": "[concat(variables('sbNamespaceName'), '/', variables('sbTopics')[copyIndex()])]",
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[variables('sbNamespaceName')]"
],
"properties": {
"defaultMessageTimeToLive": "P14D",
"maxSizeInMegabytes": 1024,
"requiresDuplicateDetection": false,
"enablePartitioning": true
},
"copy": {
"name": "topiccopy",
"count": "[length(variables('sbTopics'))]"
}
},
{
"type": "Microsoft.ServiceBus/namespaces/topics/subscriptions",
"name": "[concat(variables('sbNamespaceName'), '/', variables('sbSubscriptions')[copyIndex()].Topic, '/', variables('sbSubscriptions')[copyIndex()].Name)]",
"apiVersion": "[variables('sbVersion')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"topiccopy"
],
"properties": {
"maxDeliveryCount": 10
},
"copy": {
"name": "subscriptioncopy",
"count": "[length(variables('sbSubscriptions'))]"
}
}
]
}
You can also use this to debug:
Test-AzureRmResourceGroupDeployment -verbose or -debug

Related

ARM template fails when creating event hub in multiple regions with multiple auth rules

I have an ARM template that creates Event Hub namespaces in two regions (eastus and westus2) with a event hub and multiple auth rules (on the even hub). This was working until ~16-Nov-2020 12:00PM.
Arm template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location-region1": {
"type": "string",
"defaultValue": "eastus",
"metadata": {
"description": "Name of an azure region"
}
},
"location-region2": {
"type": "string",
"defaultValue": "westus2",
"metadata": {
"description": "Name of an Azure region"
}
},
"appName": {
"type": "string",
"defaultValue": "jklm",
"metadata": {
"description": "Short name of the app or service"
}
},
"uniqueSuffix": {
"type": "string",
"defaultValue": "tst",
"metadata": {
"description": "Unique Suffix to use for the azure resources of the app or service"
}
},
"environment": {
"type": "string",
"defaultValue": "int",
"allowedValues": [
"poc",
"dev",
"int",
"uat",
"prod"
],
"metadata": {
"description": "The name of the environment"
}
},
"progressRecordsEventHubName": {
"type": "string",
"defaultValue": "progressrecords"
}
},
"variables": {
"eventHubNMApiVersion": "2018-01-01-preview",
"eventHubApiVersion": "2017-04-01",
"parentResourceGroupName": "[resourceGroup().name]",
"regionCount": 2,
"location": [
"[parameters('location-region1')]",
"[parameters('location-region2')]"
],
"appName": "[concat(parameters('appName'),'-',parameters('uniqueSuffix'),'-')]",
"copy": [
{
"name": "regionSuffix",
"count": "[variables('regionCount')]",
"input": "[concat('r',copyIndex('regionSuffix',1))]"
},
{
"name": "eventHubName",
"count": "[variables('regionCount')]",
"input": "[concat(variables('appName'),'ehub-',variables('regionSuffix')[copyIndex('eventHubName')],'-',parameters('environment'))]"
}
]
},
"resources": [
{
"type": "Microsoft.EventHub/namespaces",
"apiVersion": "[variables('eventHubNMApiVersion')]",
"name": "[variables('eventHubName')[copyIndex()]]",
"copy": {
"name": "resourceLoop",
"count": "[variables('regionCount')]"
},
"location": "[variables('location')[copyIndex()]]",
"sku": {
"name": "Standard",
"tier": "Standard",
"capacity": 1
},
"properties": {
"zoneRedundant": false,
"isAutoInflateEnabled": true,
"maximumThroughputUnits": 1,
"kafkaEnabled": true
},
"resources": [
{
"type": "Microsoft.EventHub/namespaces/eventhubs",
"apiVersion": "[variables('eventHubApiVersion')]",
"name": "[concat(variables('eventHubName')[copyIndex()], '/',parameters('progressRecordsEventHubName'))]",
"location": "[variables('location')[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/namespaces', variables('eventHubName')[copyIndex()])]"
],
"properties": {
"messageRetentionInDays": 3,
"partitionCount": 1,
"status": "Active"
},
"resources": [
{
"type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules",
"apiVersion": "[variables('eventHubApiVersion')]",
"name": "[concat(variables('eventHubName')[copyIndex('resourceLoop')], '/',parameters('progressRecordsEventHubName'),'/Listen')]",
"location": "[variables('location')[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/namespaces/eventhubs', variables('eventHubName')[copyIndex()],parameters('progressRecordsEventHubName'))]"
],
"properties": {
"rights": [
"Listen"
]
}
},
{
"type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules",
"apiVersion": "[variables('eventHubApiVersion')]",
"name": "[concat(variables('eventHubName')[copyIndex('resourceLoop')], '/',parameters('progressRecordsEventHubName'),'/Send')]",
"location": "[variables('location')[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/namespaces/eventhubs', variables('eventHubName')[copyIndex()], parameters('progressRecordsEventHubName'))]"
],
"properties": {
"rights": [
"Send"
]
}
}
]
}
]
}
],
"functions": [
],
"outputs": {}
}
Now this template fails when I run Test-AzureRmResourceGroupDeployment (add -Debug to see real error)
Error:
Test-AzureRmResourceGroupDeployment : Encountered internal server error. Diagnostic information: timestamp '20201119T072227Z' ......
After some troubleshooting I identified that removing the second auth rule in the template fixes the issue.
I actually need more than 1 auth rule. What could be causing the above template to fail? I can't seem to find anything wrong with it.
Below you can find successful template - With 1 auth rule on the Event Hub
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location-region1": {
"type": "string",
"defaultValue": "eastus"
},
"location-region2": {
"type": "string",
"defaultValue": "westus2"
},
"appName": {
"type": "string",
"defaultValue": "jklm",
"metadata": {
"description": "Short name of the app or service"
}
},
"uniqueSuffix": {
"type": "string",
"defaultValue": "tst",
"metadata": {
"description": "Unique Suffix to use for the azure resources of the app or service"
}
},
"environment": {
"type": "string",
"defaultValue": "int",
"allowedValues": [
"poc",
"dev",
"int",
"uat",
"prod"
],
"metadata": {
"description": "The name of the environment"
}
},
"progressRecordsEventHubName": {
"type": "string",
"defaultValue": "progressrecords"
}
},
"variables": {
"eventHubNMApiVersion": "2018-01-01-preview",
"eventHubApiVersion": "2017-04-01",
"parentResourceGroupName": "[resourceGroup().name]",
"regionCount": 2,
"location": [
"[parameters('location-region1')]",
"[parameters('location-region2')]"
],
"appName": "[concat(parameters('appName'),'-',parameters('uniqueSuffix'),'-')]",
"copy": [
{
"name": "regionSuffix",
"count": "[variables('regionCount')]",
"input": "[concat('r',copyIndex('regionSuffix',1))]"
},
{
"name": "eventHubName",
"count": "[variables('regionCount')]",
"input": "[concat(variables('appName'),'ehub-',variables('regionSuffix')[copyIndex('eventHubName')],'-',parameters('environment'))]"
}
]
},
"resources": [
{
"type": "Microsoft.EventHub/namespaces",
"apiVersion": "[variables('eventHubNMApiVersion')]",
"name": "[variables('eventHubName')[copyIndex()]]",
"copy": {
"name": "resourceLoop",
"count": "[variables('regionCount')]"
},
"location": "[variables('location')[copyIndex()]]",
"sku": {
"name": "Standard",
"tier": "Standard",
"capacity": 1
},
"properties": {
"zoneRedundant": false,
"isAutoInflateEnabled": true,
"maximumThroughputUnits": 1,
"kafkaEnabled": true
},
"resources": [
{
"type": "Microsoft.EventHub/namespaces/eventhubs",
"apiVersion": "[variables('eventHubApiVersion')]",
"name": "[concat(variables('eventHubName')[copyIndex()], '/',parameters('progressRecordsEventHubName'))]",
"location": "[variables('location')[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/namespaces', variables('eventHubName')[copyIndex()])]"
],
"properties": {
"messageRetentionInDays": 3,
"partitionCount": 1,
"status": "Active"
},
"resources": [
{
"type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules",
"apiVersion": "[variables('eventHubApiVersion')]",
"name": "[concat(variables('eventHubName')[copyIndex('resourceLoop')], '/',parameters('progressRecordsEventHubName'),'/Listen')]",
"location": "[variables('location')[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/namespaces/eventhubs', variables('eventHubName')[copyIndex()],parameters('progressRecordsEventHubName'))]"
],
"properties": {
"rights": [
"Listen"
]
}
}
]
}
]
}
],
"functions": [
],
"outputs": {}
}
Worked with Azure support on this. There was an issue on the Azure side. It auto resolved today (11/19/2020). Template no longer fails with multiple auth rules.
This article may be useful: https://www.rickvandenbosch.net/blog/error-creating-service-bus-authorization-rules-using-arm/.
I think the template is not expecting the same resource twice, because these Listen, Send authorization rules can be combined like below:
"resources": [
{
"type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules",
"apiVersion": "[variables('eventHubApiVersion')]",
"name": "[concat(variables('eventHubName')[copyIndex('resourceLoop')], '/',parameters('progressRecordsEventHubName'),'/Listen')]",
"location": "[variables('location')[copyIndex()]]",
"dependsOn": [
"[resourceId('Microsoft.EventHub/namespaces/eventhubs', variables('eventHubName')[copyIndex()],parameters('progressRecordsEventHubName'))]"
],
"properties": {
"rights": [
"Listen",
"Send"
]
}
},

Private Endpoint for a Storage Queue in ARM

I can create a Private Endpoint for a Storage Queue through the portal just fine and it works as intended when checking with nameresolver.exe from KUDU. However, I am struggling to find an ARM template that does this in one go.
I have made this template work but I can see that the A record entry does not get generated in the Private DNS Zone that is generated. I don't know how to create that A record entry and cannot seem to find a ARM template online that describes this:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"privateEndpointName": {
"type": "string",
"defaultValue": "privendpoint-sapriv01-queue"
},
"vnetName": {
"type": "string",
"defaultValue": "vn-myvnet01"
},
"subnetName": {
"type": "string",
"defaultValue": "sn-private-endpoints"
},
"groupId": {
"type": "string",
"defaultValue": "queue"
}
},
"variables": {
"privateDNSZone_name": "[concat('privatelink', '.queue.', environment().suffixes.storage)]"
},
"resources": [
{
"apiVersion": "2019-04-01",
"name": "[parameters('privateEndpointName')]",
"type": "Microsoft.Network/privateEndpoints",
"location": "[resourceGroup().Location]",
"properties": {
"privateLinkServiceConnections": [
{
"name": "[parameters('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', 'saprivendpointdemo')]",
"groupIds": [
"[parameters('groupId')]"
]
}
}
],
"manualPrivateLinkServiceConnections": [],
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('subnetName') )]"
}
}
},
{
"type": "Microsoft.Network/privateDnsZones",
"apiVersion": "2018-09-01",
"name": "[variables('privateDNSZone_name')]",
"location": "global",
"tags": {},
"properties": {}
},
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2018-09-01",
"name": "[concat(variables('privateDNSZone_name'), '/', parameters('vnetName'), 'link' )]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZone_name'))]"
],
"properties": {
"virtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
},
"registrationEnabled": false
}
}
],
"outputs": {
}
}
I think Microsoft overcomplicated this. The Private IP is auto generated and I don't know how one would reference this IP in the ARM template.
If you want to add A record in your Azure Private DNS Zone, you can define Microsoft.Network/privateEndpoints/privateDnsZoneGroups in your template.
For example
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"privateEndpointName": {
"type": "string",
"defaultValue": "testqueue"
},
"vnetName": {
"type": "string",
"defaultValue": "teststorage"
},
"subnetName": {
"type": "string",
"defaultValue": "default"
},
"groupId": {
"type": "string",
"defaultValue": "queue"
}
},
"variables": {
"privateDNSZone_name": "[concat('privatelink', '.queue.', environment().suffixes.storage)]"
},
"resources": [
{
"apiVersion": "2019-04-01",
"name": "[parameters('privateEndpointName')]",
"type": "Microsoft.Network/privateEndpoints",
"location": "[resourceGroup().Location]",
"properties": {
"privateLinkServiceConnections": [
{
"name": "[parameters('privateEndpointName')]",
"properties": {
"privateLinkServiceId": "[resourceId('Microsoft.Storage/storageAccounts', 'teststorage05')]",
"groupIds": [
"[parameters('groupId')]"
]
}
}
],
"manualPrivateLinkServiceConnections": [],
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('subnetName') )]"
}
}
},
{
"type": "Microsoft.Network/privateDnsZones",
"apiVersion": "2018-09-01",
"name": "[variables('privateDNSZone_name')]",
"dependsOn": [
"[parameters('privateEndpointName')]"
],
"location": "global",
"tags": {},
"properties": {}
},
{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2018-09-01",
"name": "[concat(variables('privateDNSZone_name'), '/', parameters('vnetName'), 'link' )]",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/privateDnsZones', variables('privateDNSZone_name'))]"
],
"properties": {
"virtualNetwork": {
"id": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
},
"registrationEnabled": false
}
},
{
"type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups",
"apiVersion": "2020-03-01",
"name": "[concat(parameters('privateEndpointName'), '/', 'default')]",
"dependsOn": [
"[parameters('privateEndpointName')]",
"[variables('privateDNSZone_name')]"
],
"location": "[resourceGroup().Location]",
"properties": {
"privateDnsZoneConfigs": [
{
"name": "privatelink-queue-core-windows-net",
"properties": {
"privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones',variables('privateDNSZone_name'))]"
}
}
]
}
}
],
"outputs": {
}
}
For more details, please refer to here and here

Appservice and slots deployment issues with ARM template

I have a ARM template code to deploy the webapp and slot creating along with app with respective the environment based on the condition. When i try to deploy the resource using the template it only deploys the web app and the slot is not created using the settings on the App. I am new to the ARM stuff could any one please help me out on what i have done wrong with my template.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroup": {
"type": "string"
},
"displayNameTag": {
"type": "string"
},
"appInsightName": {
"type": "string"
},
"environment": {
"type": "string"
},
"appType": {
"type": "string"
},
"appServicePlanName": {
"type": "string"
},
"alwaysOn": {
"type": "bool"
},
"currentStack": {
"type": "string"
},
"netFrameworkVersion": {
"type": "string",
"defaultValue": "v4.0"
},
"secondaryApp":{
"type":"string"
}
},
"variables": {
"AustraliaEast": {
"countryCode": "au",
"regionShortCode": "aue",
"regionShortCodePair": "aue",
"omsLocation": "AustraliaEast",
"omsLocationShortCode": "aue",
"PrimaryRegion": true,
"SecondaryRegion": "AustraliaSoutheast",
"regionLocation":"AustraliaEast"
},
"AustraliaSoutheast": {
"countryCode": "au",
"regionShortCode": "aus",
"regionShortCodePair": "aue",
"PrimaryRegion": false,
"regionLocation":"AustraliaSoutheast"
},
"regionSpec": "[variables(resourceGroup().location)]",
"applicationRegion" : "[if(equals(parameters('secondaryApp'),'Yes'),variables('AustraliaSoutheast'),variables('regionspec'))]",
"appName": "[concat('myapp-',parameters('environment'),'-',parameters('appType'),'-',variables('applicationRegion').regionShortcode,'-',parameters('displayNameTag'))]"
},
"resources": [
{
"apiVersion": "2018-11-01",
"name": "[variables('appName')]",
"type": "Microsoft.Web/sites",
"location": "[variables('applicationRegion').regionLocation]",
"tags": {
"displayName": "[parameters('displayNameTag')]",
"environment": "[parameters('environment')]"
},
"dependsOn": [],
"properties": {
"name": "[variables('appName')]",
"mode": "incremental",
"siteConfig": {
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
"value": "[concat('InstrumentationKey=',reference(resourceId('Microsoft.Insights/components', parameters('appInsightName')), '2015-05-01').InstrumentationKey)]"
}
],
"metadata": [
{
"name": "CURRENT_STACK",
"value": "[parameters('currentStack')]"
}
],
"netFrameworkVersion": "[parameters('netFrameworkVersion')]",
"alwaysOn": "[parameters('alwaysOn')]"
},
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]",
"clientAffinityEnabled": true
}
},
{
"condition":"[equals(parameters('secondaryApp'),'Yes')]",
"apiVersion": "2018-11-01",
"type": "Microsoft.Web/sites/slots",
"name": "[concat(variables('appName'), '/', 'Slot-Staging')]",
"location": "[variables('applicationRegion').regionLocation]",
"comments": "This specifies the web app slots.",
"tags": {
"displayName": "WebAppSlots"
},
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]"
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('appName'))]"
]
}
],
"outputs": {
"webAppName": {
"type": "string",
"value": "[variables('appName')]"
}
}
}'
Please have a try to add the json code snipped in the ARM template.
"resources": [
{
"apiVersion": "2015-08-01",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites/Slots', variables('webSiteName'), 'Staging')]"
],
"properties": {
"AppSettingKey1": "Some staging value",
"AppSettingKey2": "My second staging setting",
"AppSettingKey3": "My third staging setting"
}
}
]
Follow this SO for complete reference.

Problem deploying multiple resources using ARM Subscription Level Deployment

I'm rewriting an ARM template because we no longer use Linked Templates. The Linked templates give us versioning headaches. I'm using a subscription level deployment to deploy a resource group, with nested a deletion lock, storage account, keyvault, 2 functionapps, user assigned managed identity and a keyvault access policy.
ARM Template I use:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"deplocation": {
"type": "string",
"allowedValues": [
"West Europe",
"North Europe"
],
"defaultValue": "West Europe",
"metadata": {
"description": "Location for all resources."
}
},
"tags": {
"type": "object"
},
"rgName": {
"type": "string"
},
"saName": {
"type": "string",
"metadata": {
"description": "The name of the resource."
}
},
"saType": {
"type": "string",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"defaultValue": "Standard_LRS",
"metadata": {
"description": "Gets or sets the SKU name. Required for account creation; optional for update. Note that in older versions, SKU name was called accountType. - Standard_LRS, Standard_GRS, Standard_RAGRS, Standard_ZRS, Premium_LRS, Premium_ZRS, Standard_GZRS, Standard_RAGZRS"
}
},
"saKind": {
"type": "string",
"allowedValues": [
"StorageV2",
"BlobStorage",
"FileStorage",
"BlockBlobStorage"
],
"defaultValue": "StorageV2",
"metadata": {
"description": "Indicates the type of storage account. - Storage, StorageV2, BlobStorage, FileStorage, BlockBlobStorage"
}
},
"saAccessTier": {
"type": "string"
},
"saSupportsHttpsTrafficOnly": {
"type": "bool"
},
"kvName": {
"type": "string"
},
"kvSkuName": {
"type": "string"
},
"kvSkuFamily": {
"type": "string"
},
"kvSecretsPermissions": {
"type": "array"
},
"uamiName": {
"type": "string"
},
"fa1Name": {
"type": "string"
},
"fa2Name": {
"type": "string"
},
"aspName": {
"type": "string"
},
"aspRg": {
"type": "string"
},
"appInsightsName": {
"type": "string"
},
"appInsightsRg": {
"type": "string"
}
},
"variables": {
"tenantId": "[subscription().tenantId]",
"subscriptionId": "[subscription().subscriptionId]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('depLocation')]",
"name": "[parameters('rgName')]",
"tags": "[parameters('tags')]",
"properties": {
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "resourceDeployment",
"resourceGroup": "[parameters('rgName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('rgName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "DeletionLock",
"type": "Microsoft.Authorization/locks",
"apiVersion": "2017-04-01",
"properties": {
"level": "CanNotDelete",
"notes": "[parameters('rgName')]"
}
},
{
"name": "[parameters('saName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"sku": {
"name": "[parameters('saType')]"
},
"kind": "[parameters('saKind')]",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"properties": {
"accessTier": "[parameters('saAccessTier')]",
"supportsHttpsTrafficOnly": "[parameters('saSupportsHttpsTrafficOnly')]"
}
},
{
"name": "[concat(parameters('saName'), '/default')]",
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-04-01",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('saName'))]"
],
"properties": {
"cors": {
"corsRules": [
]
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"name": "[parameters('kvName')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"properties": {
"tenantId": "[variables('tenantId')]",
"accessPolicies": [
],
"sku": {
"name": "[parameters('kvSkuName')]",
"family": "[parameters('kvSkuFamily')]"
}
}
},
{
"name": "[parameters('uamiName')]",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2018-11-30",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"properties": {
}
},
{
"name": "[parameters('fa1Name')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"kind": "functionapp",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('uamiName'))]",
"[resourceId('Microsoft.Storage/storageAccounts/', parameters('saName'))]"
],
"identity": {
"type": "SystemAssigned, UserAssigned",
"userAssignedIdentities": {
"[concat('/subscriptions/', variables('subscriptionId'), '/resourceGroups/', parameters('rgName'), '/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('uamiName'))]": {
}
}
},
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_TIME_ZONE",
"value": "W. Europe Standard Time"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('saName'),';AccountKey=',listKeys(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value,';')]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "1"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('appInsightsRg'),'/providers/microsoft.insights/components/',parameters('appInsightsName')),providers('microsoft.insights', 'components').apiVersions[0]).InstrumentationKey]"
}
],
"alwaysOn": true
},
"serverFarmId": "[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('aspRg'),'/providers/Microsoft.Web/serverfarms/',parameters('aspName'))]",
"httpsOnly": true
}
},
{
"name": "[parameters('fa2Name')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"kind": "functionapp",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]",
"[resourceId('Microsoft.Storage/storageAccounts/', parameters('saName'))]"
],
"identity": {
"type": "SystemAssigned, UserAssigned",
"userAssignedIdentities": {
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]": {
}
}
},
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_TIME_ZONE",
"value": "W. Europe Standard Time"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('saName'),';AccountKey=',listKeys(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value,';')]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "1"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('appInsightsRg'),'/providers/microsoft.insights/components/',parameters('appInsightsName')),providers('microsoft.insights', 'components').apiVersions[0]).InstrumentationKey]"
}
],
"alwaysOn": true
},
"serverFarmId": "[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('aspRg'),'/providers/Microsoft.Web/serverfarms/',parameters('aspName'))]",
"httpsOnly": true
}
},
{
"name": "[concat(parameters('kvName'), '/add')]",
"type": "Microsoft.KeyVault/vaults/accessPolicies",
"apiVersion": "2018-02-14",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults', parameters('kvName'))]",
"[resourceId('Microsoft.Web/sites', parameters('fa1Name'))]",
"[resourceId('Microsoft.Web/sites', parameters('fa2Name'))]"
],
"properties": {
"accessPolicies": [
{
"tenantId": "[variables('tenantId')]",
"objectId": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Web/sites/', parameters('fa1Name'), '/providers/Microsoft.ManagedIdentity/Identities/default'),providers('Microsoft.ManagedIdentity', 'Identities').apiVersions[0]).principalId]",
"permissions": {
"secrets": "[parameters('kvSecretsPermissions')]"
}
}
,
{
"tenantId": "[variables('tenantId')]",
"objectId": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Web/sites/', parameters('fa2Name'), '/providers/Microsoft.ManagedIdentity/Identities/default'),providers('Microsoft.ManagedIdentity', 'Identities').apiVersions[0]).principalId]",
"permissions": {
"secrets": "[parameters('kvSecretsPermissions')]"
}
}
]
}
}
]
}
}
}
],
"outputs": {
// "uamiPrincipalId": {
// "value": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('uamiName')), providers('Microsoft.ManagedIdentity', 'userAssignedIdentities').apiVersions[0]).principalId]",
// "type": "string"
// }
}
}
Powershell code to deploy the template.
#region variableDeclaration
$ErrorActionPreference = "Stop"
$subscriptionId = "subscription id here"
$location = "West Europe"
#endregion variableDeclaration
Set-location -path $PSScriptRoot
#region connectToSubscription
Connect-AzAccount -ErrorAction Stop
Set-AzContext -Subscription $subscriptionId
#endregion connectToSubscription
#region createAzureResources
$workloadInputResources = #{
depLocation = $location
tags = #{
dienst = "-"
kostenplaats = "-"
omgeving = "-"
contactpersoon = "-"
eigenaar = "-"
referentie = "-"
omschrijving = "-"
}
rgName = "resources-dev-rg"
saName = "resourcesdevsa"
saType = "Standard_LRS"
saKind = "StorageV2"
saAccessTier = "Hot"
saSupportsHttpsTrafficOnly = $true
kvName = "resourcesdevkv"
kvSkuName = "Standard"
kvSkuFamily = "A"
kvSecretsPermissions = #("get", "list" )
uamiName = "resources-dev-uami"
fa1Name = "resources-dev-fa1"
fa2Name = "resources-dev-fa2"
aspName = "resources-dev-asp"
aspRg = "resources-asp-dev-rg"
appInsightsName = "resources-dev-appins"
appInsightsRg = "resources-appins-dev-rg"
}
New-AzDeployment -Name "deployResources" -Location $location -TemplateFile .\deploy.json #workloadInputResources
#endregion createAzureResources
Problems:
When deploying the arm template as-is I get the following error:
Resource Microsoft.Storage/storageAccounts 'resourcesdevsa' failed with message '{
"error": {
"code": "ResourceGroupNotFound",
"message": "Resource group 'resources-dev-rg' could not be found."
}
}'
But the creation of the resource group is successful.
When rerunning the script I get the following error:
Resource Microsoft.Storage/storageAccounts 'resourcesdevsa' failed with message '{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.Storage/storageAccounts/saName' under resource group 'resources-dev-rg' was not found."
}
}'
The second problem disappears when I comment out the deployment fa1, fa2 and the access policy
I was under the impression that using dependsOn solves the dependency issues but apparently I'm either wrong, using it incorrectly or missing a dependsOn somewhere.
Have been staring at this problem for hours now and I can't seem to find the problem.
Any help is appreciated.
Small update because parts of it are solved. Still a couple of issues though.
I have rewritten the ARM Template file as shown below
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"deplocation": {
"type": "string",
"allowedValues": [
"West Europe",
"North Europe"
],
"defaultValue": "West Europe",
"metadata": {
"description": "Location for all resources."
}
},
"tags": {
"type": "object"
},
"rgName": {
"type": "string"
},
"saName": {
"type": "string",
"metadata": {
"description": "The name of the resource."
}
},
"saType": {
"type": "string",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"defaultValue": "Standard_LRS",
"metadata": {
"description": "Gets or sets the SKU name. Required for account creation; optional for update. Note that in older versions, SKU name was called accountType. - Standard_LRS, Standard_GRS, Standard_RAGRS, Standard_ZRS, Premium_LRS, Premium_ZRS, Standard_GZRS, Standard_RAGZRS"
}
},
"saKind": {
"type": "string",
"allowedValues": [
"StorageV2",
"BlobStorage",
"FileStorage",
"BlockBlobStorage"
],
"defaultValue": "StorageV2",
"metadata": {
"description": "Indicates the type of storage account. - Storage, StorageV2, BlobStorage, FileStorage, BlockBlobStorage"
}
},
"saAccessTier": {
"type": "string"
},
"saSupportsHttpsTrafficOnly": {
"type": "bool"
},
"kvName": {
"type": "string"
},
"kvSkuName": {
"type": "string"
},
"kvSkuFamily": {
"type": "string"
},
"kvSecretsPermissions": {
"type": "array"
},
"uamiName": {
"type": "string"
},
"fa1Name": {
"type": "string"
},
"fa2Name": {
"type": "string"
},
"aspName": {
"type": "string"
},
"aspRg": {
"type": "string"
},
"appInsightsName": {
"type": "string"
},
"appInsightsRg": {
"type": "string"
}
},
"variables": {
"tenantId": "[subscription().tenantId]",
"subscriptionId": "[subscription().subscriptionId]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('depLocation')]",
"name": "[parameters('rgName')]",
"tags": "[parameters('tags')]",
"properties": {
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "resourceDeployment",
"resourceGroup": "[parameters('rgName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('rgName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "DeletionLock",
"type": "Microsoft.Authorization/locks",
"apiVersion": "2017-04-01",
"properties": {
"level": "CanNotDelete",
"notes": "[parameters('rgName')]"
}
},
{
"name": "[parameters('saName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"sku": {
"name": "[parameters('saType')]"
},
"kind": "[parameters('saKind')]",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"properties": {
"accessTier": "[parameters('saAccessTier')]",
"supportsHttpsTrafficOnly": "[parameters('saSupportsHttpsTrafficOnly')]"
},
"resources": [
]
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-04-01",
"name": "[concat(parameters('saName'), '/default')]",
"dependsOn": [
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName'))]"
],
"properties": {
"cors": {
"corsRules": [
]
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"name": "[parameters('uamiName')]",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"apiVersion": "2018-11-30",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"properties": {
}
},
{
"name": "[parameters('fa1Name')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"kind": "functionapp",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"dependsOn": [
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]",
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName'))]"
],
"identity": {
"type": "SystemAssigned, UserAssigned",
"userAssignedIdentities": {
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]": {
}
}
},
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_TIME_ZONE",
"value": "W. Europe Standard Time"
},
// {
// "name": "AzureWebJobsStorage",
// "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('saName'),';AccountKey=',listKeys(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value,';')]"
// },
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "0"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('appInsightsRg'),'/providers/microsoft.insights/components/',parameters('appInsightsName')),providers('microsoft.insights', 'components').apiVersions[0]).InstrumentationKey]"
}
],
"alwaysOn": true
},
"serverFarmId": "[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('aspRg'),'/providers/Microsoft.Web/serverfarms/',parameters('aspName'))]",
"httpsOnly": true
}
},
{
"name": "[parameters('fa2Name')]",
"type": "Microsoft.Web/sites",
"apiVersion": "2019-08-01",
"kind": "functionapp",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"dependsOn": [
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]",
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName'))]"
],
"identity": {
"type": "SystemAssigned, UserAssigned",
"userAssignedIdentities": {
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]": {
}
}
},
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "dotnet"
},
{
"name": "WEBSITE_TIME_ZONE",
"value": "W. Europe Standard Time"
},
// {
// "name": "AzureWebJobsStorage",
// "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',parameters('saName'),';AccountKey=',listKeys(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName')),providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value,';')]"
// },
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "0"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('appInsightsRg'),'/providers/microsoft.insights/components/',parameters('appInsightsName')),providers('microsoft.insights', 'components').apiVersions[0]).InstrumentationKey]"
}
],
"alwaysOn": true
},
"serverFarmId": "[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('aspRg'),'/providers/Microsoft.Web/serverfarms/',parameters('aspName'))]",
"httpsOnly": true
}
},
{
"name": "[parameters('kvName')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "[parameters('deplocation')]",
"tags": "[parameters('tags')]",
"dependsOn": [
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Web/sites/',parameters('fa1Name'))]",
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Web/sites/',parameters('fa2Name'))]"
],
"properties": {
"tenantId": "[variables('tenantId')]",
"accessPolicies": [
// {
// "tenantId": "[variables('tenantId')]",
// "objectId": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Web/sites/', parameters('fa1Name'), '/providers/Microsoft.ManagedIdentity/Identities/default'),providers('Microsoft.ManagedIdentity', 'Identities').apiVersions[0]).principalId]",
// "permissions": {
// "secrets": "[parameters('kvSecretsPermissions')]"
// }
// },
// {
// "tenantId": "[variables('tenantId')]",
// "objectId": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Web/sites/', parameters('fa2Name'), '/providers/Microsoft.ManagedIdentity/Identities/default'),providers('Microsoft.ManagedIdentity', 'Identities').apiVersions[0]).principalId]",
// "permissions": {
// "secrets": "[parameters('kvSecretsPermissions')]"
// }
// }
],
"sku": {
"name": "[parameters('kvSkuName')]",
"family": "[parameters('kvSkuFamily')]"
}
}
}
]
}
}
}
],
"outputs": {
// "uamiPrincipalId": {
// "value": "[reference(concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('uamiName')), providers('Microsoft.ManagedIdentity', 'userAssignedIdentities').apiVersions[0]).principalId]",
// "type": "string"
// }
}
}
This work flawlessly very time, but as you can see I have 3 sections commented out. This is the problem area now. They are all dependsOn issues. When I uncomment the AzureWebJobsStorage part in the function app deployments the deployment fails with this message:
12:00:18 - Resource Microsoft.Storage/storageAccounts 'resourcesdevsa' failed with message '{
"error": {
"code": "ResourceGroupNotFound",
"message": "Resource group 'resources-dev-rg' could not be found."
}
}'
I have added the StorageAccount to the dependsOn section
"dependsOn": [
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.ManagedIdentity/userAssignedIdentities/',parameters('uamiName'))]",
"[concat('/subscriptions/',variables('subscriptionId'),'/resourceGroups/',parameters('rgName'),'/providers/Microsoft.Storage/storageAccounts/',parameters('saName'))]"
],
But that doesn't seem to do the trick.
Any ideas?
Update 28/11/2019
Oke. I'm getting slightly frustrated. I now have a fully functional resourcegroup level deployment. I'm creating the resourcegroup and resourcegroup deletionlock in powershell and after that a New-AzResourceGroupDeployment. When I try to rewrite this into a subscription level deployment I keep getting dependency issues. For instance; creating the KeyVault Access Policies results in an error that the function app couldn't be found. And a similar error for setting the AzureWebJobsStorage setting for the function app. But than offcourse a reference to the storageaccount.

Using CopyIndex and listKeys in outputs section

I'm trying to get the primaryConnectionStrings from an aRM template that creates multiple notification hubs
But I get this error
Error: Code=InvalidTemplate; Message=Deployment template validation failed: 'The template output 'connectionStrings' at line '291' and column '30' is not valid: The
template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified. Please see https://aka.ms/arm-copy for usage details.. Please see
https://aka.ms/arm-template-expressions for usage details.'.
I am clearly missing what this actually means as I've tried various incarnations of the template all of which have a copy for the resource.
I've tried this with a nested template (apologies if i've mangled the template, just removed some extraneous items):
"resources": [
{
"type": "Microsoft.NotificationHubs/namespaces",
"apiVersion": "2017-04-01",
"name": "[parameters('notificationHubName')]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hub Namespace"
},
"sku": {
"name": "[parameters('notificationHubSku')]"
},
"kind": "NotificationHub",
"properties": {
"namespaceType": "NotificationHub"
}
},
{
"type": "Microsoft.NotificationHubs/namespaces/AuthorizationRules",
"apiVersion": "2017-04-01",
"name": "[concat(parameters('notificationHubName'), '/RootManageSharedAccessKey')]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hub Namespace Auth Rules"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('notificationHubName'))]"
],
"properties": {
"rights": [
"Listen",
"Manage",
"Send"
]
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "[concat('nestedTemplate', copyIndex('notificationHubEntities'))]",
"copy": {
"name": "notificationHubEntities",
"count": "[length(parameters('notificationHubEntities'))]"
},
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs",
"apiVersion": "2017-04-01",
"name": "[concat(parameters('notificationHubName'), '/', parameters('notificationHubEntities')[copyIndex('notificationHubEntities')])]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hubs"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('notificationHubName'))]"
],
"properties": {
"authorizationRules": []
}
},
{
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs/authorizationRules",
"apiVersion": "2017-04-01",
"name": "[concat(parameters('notificationHubName'), '/',parameters('notificationHubEntities')[copyIndex('notificationHubEntities')],'/DefaultFullSharedAccessSignature')]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hub Auth Rules"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs',parameters('notificationHubName'), parameters('notificationHubEntities')[copyIndex('notificationHubEntities')])]",
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('notificationHubName'))]"
],
"properties": {
"rights": [
"Listen",
"Manage",
"Send"
]
}
},
],
"outputs" : {
"connectionString" : {
"type" : "object",
"value": "[listKeys(resourceId('Microsoft.NotificationHubs/namespaces/NotificationHubs/AuthorizationRules',parameters('notificationHubName'), parameters('notificationHubEntities')[copyIndex('notificationHubEntities')], 'DefaultFullSharedAccessSignature'),'2016-03-01').primaryConnectionString]"
}
}
}
}
}
],
"outputs": {
"connectionStrings" :
{
"type": "array",
"value": "[reference(concat('nestedTemplate', copyIndex('notificationHubEntities'))).outputs.connectionString.value]"
}
}
}
I've also tried with this:
"resources": [
{
"type": "Microsoft.NotificationHubs/namespaces",
"apiVersion": "2017-04-01",
"name": "[parameters('notificationHubName')]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hub Namespace"
},
"sku": {
"name": "[parameters('notificationHubSku')]"
},
"kind": "NotificationHub",
"properties": {
"namespaceType": "NotificationHub"
}
},
{
"type": "Microsoft.NotificationHubs/namespaces/AuthorizationRules",
"apiVersion": "2017-04-01",
"name": "[concat(parameters('notificationHubName'), '/RootManageSharedAccessKey')]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hub Namespace Auth Rules"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('notificationHubName'))]"
],
"properties": {
"rights": [
"Listen",
"Manage",
"Send"
]
}
},
{
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs",
"apiVersion": "2017-04-01",
"name": "[concat(parameters('notificationHubName'), '/', parameters('notificationHubEntities')[copyIndex()])]",
"location": "[resourceGroup().location]",
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hubs"
},
"copy": {
"name": "addNotificationHub",
"count": "[length(parameters('notificationHubEntities'))]"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('notificationHubName'))]"
],
"properties": {
"authorizationRules": []
}
},
{
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs/authorizationRules",
"apiVersion": "2017-04-01",
"name": "[concat(parameters('notificationHubName'), '/',parameters('notificationHubEntities')[copyIndex()],'/DefaultFullSharedAccessSignature')]",
"copy": {
"name": "addNotificationHub",
"count": "[length(parameters('notificationHubEntities'))]"
},
"tags": {
"Environment": "[parameters('environment')]",
"DisplayName": "Notification Hub Auth Rules"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces/notificationHubs',parameters('notificationHubName'), parameters('notificationHubEntities')[copyIndex()])]",
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('notificationHubName'))]"
],
"properties": {
"rights": [
"Listen",
"Manage",
"Send"
]
}
}
],
"outputs": {
"connectionStrings" :
{
"type": "array",
"value": "[listKeys(resourceId('Microsoft.NotificationHubs/namespaces/NotificationHubs/AuthorizationRules',parameters('notificationHubName'), parameters('notificationHubEntities')[copyIndex()], 'DefaultFullSharedAccessSignature'),'2016-03-01').primaryConnectionString]"
}
}
I've tried using object instead of array but to no avail, so I'm a bit confused, any help would be appreciated as the error message seems misleading to me or I'm just not interpreting it correctly.
To accomplish requirement of creating multiple notification hubs and it's authorization rules, you can use below ARM template.
Template Parameter File (notificationhub.parameters.json):
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namespaceName": {
"value": "mm-namespace"
},
"notificationhubNamePrefix": {
"value": "mm-notificationhub"
},
"notificationhubAuthorizationruleNamePrefix": {
"value": "mm-notificationhubAuthorizationrule"
}
}
}
Template File (notificationhub.json):
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"namespaceName": {
"type": "string",
"defaultValue": "mm-namespace",
"metadata": {
"description": "namespaceName sample description"
}
},
"notificationhubNamePrefix": {
"type": "string",
"defaultValue": "mm-notificationhub",
"metadata": {
"description": "notificationhubName sample description"
}
},
"notificationhubAuthorizationruleNamePrefix": {
"type": "string",
"defaultValue": "mm-notificationhubAuthorizationrule",
"metadata": {
"description": "notificationhubAuthorizationruleName sample description"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The location in which the resources should be deployed."
}
},
"notificationhubNameSuffix": {
"type": "array",
"defaultValue": [
"00",
"01",
"02"
]
},
"notificationhubAuthorizationruleNameSuffix": {
"type": "array",
"defaultValue": [
"00",
"01",
"02"
]
}
},
"variables": {},
"resources": [
{
"name": "[parameters('namespaceName')]",
"type": "Microsoft.NotificationHubs/namespaces",
"apiVersion": "2017-04-01",
"location": "[parameters('location')]",
"tags": {},
"sku": {
"name": "Free"
},
"properties": {
"namespaceType": "NotificationHub"
}
},
{
"name": "[concat(parameters('namespaceName'), '/', parameters('notificationhubNamePrefix'), parameters('notificationhubNameSuffix')[copyIndex()])]",
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs",
"apiVersion": "2017-04-01",
"location": "[parameters('location')]",
"sku": {
"name": "Free"
},
"copy": {
"name": "notificationhubscopy",
"count": "[length(parameters('notificationhubNameSuffix'))]"
},
"dependsOn": [
"[resourceId('Microsoft.NotificationHubs/namespaces', parameters('namespaceName'))]"
]
},
{
"name": "[concat(parameters('namespaceName'), '/', parameters('notificationhubNamePrefix'), parameters('notificationhubNameSuffix')[copyIndex()], '/', parameters('notificationhubAuthorizationruleNamePrefix'), parameters('notificationhubAuthorizationruleNameSuffix')[copyIndex()])]",
"type": "Microsoft.NotificationHubs/namespaces/notificationHubs/AuthorizationRules",
"apiVersion": "2017-04-01",
"properties": {
"rights": [
"Listen",
"Manage",
"Send"
]
},
"copy": {
"name": "notificationhubsauthroizationrulescopy",
"count": "[length(parameters('notificationhubAuthorizationruleNameSuffix'))]"
},
"dependsOn": [
"notificationhubscopy"
]
}
]
}
Deployment:
AFAIK, to accomplish requirement of getting output (in this case primaryConnectionStrings of multiple notification hubs' authorization rules) from ARM template is currently an unsupported feature. I already see related feature requests / feedback here and here. I would recommend you to up-vote these feature requests / feedback or create a new feature request / feedback explaining your use case and requirement. Azure feature team would consider and work on the feature request / feedback based on the votes, visibility and priority on it.
Azure document references:
ARM template reference for NotificationHubs
Resolve Invalid Template errors
Create multiple instances of a resource using copy and copyIndex
ARM template functions like list (ListKeys)
ARM template structure
Defining order for deploying resources in ARM templates
Hope this helps!! Cheers!!
You can't use a copy loop in outputs today - listing the keys is fine, but you have to know how many you need at design time and hardcode each output. We're working on a fix for that but not there yet.
You could emulate this by using your second option - deploying in a nested deployment and outputting each key in it's own deployment, but then you have to iterate through all the deployments to get all the outputs.

Resources