Related
I am trying to create multiple storage accounts with arm templates, However i am unable to find syntax for creating with name as parameters. below is the my template.json file
Template.json:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-
01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageName": {
"type": "array",
"metadata": {
"description": "storageaccountname"
}
}
},
"functions": [],
"variables": {},
"resources": [{
"name": "[concat('storage', uniqueString(resourceGroup().id),
parameters('storageName')[copyIndex('copystorage')])]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-04-01",
"tags": {
"displayName": "storageaccount1"
},
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"copy": {
"name": "copystorage",
"count": "[length(parameters('storageName'))]"
}
}],
"outputs": {}
}
Parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-
01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageName": {
"value": [
"storarm1",
"storearm2",
"storearm3"
]
}
}
}
so what should be the "name" property inorder to create storage accounts with
storearm1,storearm2 and storearm3
after modifying from
"name": "[concat('storage', uniqueString(resourceGroup().id), parameters('storageName')[copyIndex('copystorage')])]", to
"name": "[ parameters('storageName')[copyIndex('copystorage')]]",
i able to create with the names
Basically, I am trying to use ARM to deploy an event grid subscription to collect specific events within a subscription (Topic Types = Azure Subscriptions). I already have a function app with an event grid trigger function created, just need to tie the function with the event grid subscription as a webhook.
I am using a release pipeline in Azure DevOps to automate this whole workflow.
Here is one example that I used:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"egstopic": {
"type": "string",
"defaultValue": "egstopic1",
"metadata": {
"description": "Event grid system topic"
}
},
"eventSubName": {
"type": "string",
"defaultValue": "esub1",
"metadata": {
"description": "Event grid system topic"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"eventGridFunc":{
"type": "string",
"defaultValue": "VmAddedListener",
"metadata": {
"description" : "Function Name"
}
}
},
"variables": {
"functionUrl" : "[concat('https://', variables('FunctionAppName'),'.azurewebsites.net/runtime/webhooks/eventgrid?functionName=', parameters('eventGridFunc'),'&code=')]",
"functionAppName": "event-driven-func2"
},
"resources": [
{
"type": "Microsoft.EventGrid/Topics",
"apiVersion": "2018-01-01",
"name": "[parameters('egstopic')]",
"location": "[parameters('location')]",
"properties":{}
},
{
"type": "Microsoft.EventGrid/Topics/providers/eventSubscriptions",
"name": "[concat(parameters('egstopic'), '/Microsoft.EventGrid/', parameters('eventSubName'))]",
"location": "[parameters('location')]",
"apiVersion": "2018-01-01",
"dependsOn": [
"[parameters('egstopic')]"
],
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": "[concat(variables('functionUrl'), listKeys(resourceId('Microsoft.Web/sites/host/', variables('functionAppName'), 'default'),'2016-08-01').masterKey)]"
}
},
"filter": {
"includedEventTypes": [
"Microsoft.Resources.ResourceWriteSuccess"
],
"advancedFilters": [
{
"key": "data.operationName",
"operatorType": "StringContains",
"values": [
"Microsoft.Compute/virtualMachines/write"
]
}
]
}
}
}
]
}
This ended up deploying an event grid topic instead of an event grid subscription.
Then I was suggested to attempt the following:
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"parameters": {
"egstopic": {
"type": "string",
"defaultValue": "egstopic1",
"metadata": {
"description": "Event grid system topic"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"eventGridFunc":{
"type": "string",
"defaultValue": "VmAddedListener",
"metadata": {
"description" : "Function Name"
}
}
},
"variables": {
"functionUrl" : "[concat('https://', variables('FunctionAppName'),'.azurewebsites.net/runtime/webhooks/eventgrid?functionName=', parameters('eventGridFunc'),'&code=')]",
"functionAppName": "event-driven-func2",
"eventSubName": "[concat('esub',uniquestring(resourceGroup().id))]",
"eventSubTopic": "[concat('/subscriptions/',subscription().subscriptionid)]"
},
"resources": [
{
"type": "Microsoft.EventGrid/systemTopics/eventSubscriptions",
"name": "eventSubEG1",
"location": "[parameters('location')]",
"apiVersion": "2020-04-01-preview",
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": "[concat(variables('functionUrl'), listKeys(resourceId('Microsoft.Web/sites/host/', variables('functionAppName'), 'default'),'2016-08-01').masterKey)]"
}
},
"filter": {
"includedEventTypes": [
"Microsoft.Resources.ResourceWriteSuccess"
],
"advancedFilters": [
{
"key": "data.operationName",
"operatorType": "StringContains",
"values": [
"Microsoft.Compute/virtualMachines/write"
]
}
]
}
}
}
]
}
But this ended up failing with this error: A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name
Just need to find a way to use ARM or Azure DevOps to automate this process.
I have a updated template based on your templates and tested this template and it is working fine. It creates a Event Grid Topic and Subscription and ties the Event Grid Trigger function to it.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"eventGridTopicName": {
"type": "String",
"metadata": {
"description": "The name of the Event Grid custom topic."
}
},
"eventGridSubscriptionName": {
"type": "String",
"metadata": {
"description": "The name of the Event Grid custom topic's subscription."
}
},
"eventGridSubscriptionURL": {
"type": "String",
"metadata": {
"description": "Event grid subscription URL."
}
},
"location": {
"defaultValue": "[resourceGroup().location]",
"type": "String",
"metadata": {
"description": "The location in which the Event Grid resources should be deployed."
}
}
},
"resources": [
{
"type": "Microsoft.EventGrid/topics",
"apiVersion": "2018-01-01",
"name": "[parameters('eventGridTopicName')]",
"location": "[parameters('location')]"
},
{
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"apiVersion": "2018-01-01",
"name": "[concat(parameters('eventGridTopicName'), '/Microsoft.EventGrid/', parameters('eventGridSubscriptionName'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[parameters('eventGridTopicName')]"
],
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": "[parameters('eventGridSubscriptionURL')]"
}
},
"filter": {
"includedEventTypes": [
"All"
]
}
}
}
]
}
You can copy Event Grid Subscription URL by going to Function App -> Functions -> Event Grid Trigger Function -> Integrate tab. On this tab you will find the Event Grid Subscription URL copy that and provide as input to template.
Hope this helps!
I'm currently facing an issue with nested template.
When I'm applying my template (detail below), I get this answer from Azure:
Azure Error: InvalidTemplate
Message: Deployment template validation failed: 'The template reference 'sandbox.test.portal' is not valid: could not find template resource or resource copy with this name. Please see https://aka.ms/arm-template-expressions/#reference for usage details.'.
However, I don't really understand why I get this issue, because for the content inside the nested template, I used what they provide in the documentation here: https://github.com/Azure/azure-quickstart-templates/blob/master/101-azure-dns-new-zone/azuredeploy.json
My ARM template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"newZoneName": {
"type": "string",
"defaultValue": "sandbox.test.portal",
"metadata": {
"description": "The name of the DNS zone to be created. Must have at least 2 segements, e.g. hostname.org"
}
},
"newRecordName": {
"type": "string",
"defaultValue": "www",
"metadata": {
"description": "The name of the DNS record to be created. The name is relative to the zone, not the FQDN."
}
}
},
"variables": {
"publicIPAddressName": "[concat(resourceGroup().name, '-pip')]",
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "my-rg",
"subscriptionId": "[subscription().subscriptionId]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Network/dnszones",
"name": "[parameters('newZoneName')]",
"apiVersion": "2016-04-01",
"location": "global",
"properties": {
}
},
{
"type": "Microsoft.Network/dnszones/a",
"name": "[concat(parameters('newZoneName'), '/', parameters('newRecordName'))]",
"apiVersion": "2016-04-01",
"location": "global",
"dependsOn": [
"[parameters('newZoneName')]"
],
"properties": {
"TTL": 3600,
"ARecords": [
{
"ipv4Address": "1.2.3.4"
},
{
"ipv4Address": "1.2.3.5"
}
]
}
}
],
"outputs": {
"nameServers": {
"type": "array",
"value": "[reference(parameters('newZoneName')).nameServers]"
}
}
}
}
}
]
}
basically, you need to remove the outputs from the nested inline template, so remove this bit:
"outputs": {
"nameServers": {
"type": "array",
"value": "[reference(parameters('newZoneName')).nameServers]"
}
}
long story short, nested inline deployments are bad. dont use them.
alternatively move those to the parent template and do a real lookup:
reference(resourceId('Microsoft.Network/dnszones', parameters('newZoneName')))
You have several minor mistakes in your template:
Comma in variables '-pip')]",
Undefined parameter dnsLabelPrefix
The general mistake in nested outputs. When you use nested templates azure don't find it in your main template. Therefore you must use a reference function with identifier and API: "[reference(resourceId('Microsoft.Network/dnszones', parameters('newZoneName')), '2016-04-01').nameServers]".
I modified your template and validate in my subscription.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"newZoneName": {
"type": "string",
"defaultValue": "sandbox.test.portal",
"metadata": {
"description": "The name of the DNS zone to be created. Must have at least 2 segements, e.g. hostname.org"
}
},
"newRecordName": {
"type": "string",
"defaultValue": "www",
"metadata": {
"description": "The name of the DNS record to be created. The name is relative to the zone, not the FQDN."
}
},
"dnsLabelPrefix": {
"type": "string",
"defaultValue": "[concat('dns',uniqueString(resourceGroup().name))]"
},
"nestedResourceGroup": {
"type": "string",
"defaultValue": "my-rg",
"metadata": {
"description": "my-rg"
}
}
},
"variables": {
"publicIPAddressName": "[concat(resourceGroup().name, '-pip')]"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('nestedResourceGroup')]",
"subscriptionId": "[subscription().subscriptionId]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Network/dnszones",
"name": "[parameters('newZoneName')]",
"apiVersion": "2016-04-01",
"location": "global",
"properties": {
}
},
{
"type": "Microsoft.Network/dnszones/a",
"name": "[concat(parameters('newZoneName'), '/', parameters('newRecordName'))]",
"apiVersion": "2016-04-01",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/dnszones', parameters('newZoneName'))]"
],
"properties": {
"TTL": 3600,
"ARecords": [
{
"ipv4Address": "1.2.3.4"
},
{
"ipv4Address": "1.2.3.5"
}
]
}
}
],
"outputs": {
"nameServers": {
"type": "array",
"value": "[reference(resourceId('Microsoft.Network/dnszones', parameters('newZoneName')), '2016-04-01').nameServers]"
}
}
}
}
}
]
}
Have a nice day!
via portal, I can define an Event Subscription in the Storage Account, at the End I have such a view in the portal:
Now I would like to do the same with ARM-Template, I have the following Code:
{
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"name": "[concat(variables('StorageAccountName'),'/Microsoft.EventGrid/',variables('EventGridName'))]",
"location": "[parameters('region')]",
"apiVersion": "2018-01-01",
"dependsOn": [ "[resourceId('Microsoft.Web/sites', variables('AzureFunction'))]" ],
"properties": {
"topic": "[concat('Microsoft.EventGrid/topics/',variables('StorageAccountName'))]",
"destination": {
"endpointType": "WebHook",
"properties": {
"topics": "[variables('StorageAccountName')]",
"endpointUrl": "[concat('https://', variables('AzureFunction'),'.azurewebsites.net/admin/extensions/EventGridExtensionConfig')]"
}
}
}
}
after running this code, I get the following error:
Resource Microsoft.EventGrid/topics/providers/eventSubscriptions 'xxxx0prod0sac0xx0we/Microsoft.EventGrid/xxxx-prod-eg-dz-we' failed with message '{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.EventGrid/topics/xxxx0prod0sac0xx0we' under resource group 'xxxx' was not found."
}
}'
Do you have any idea, what should I do to solve this problem?
#Kaja, Please use the below ARM template to create an Event Subscription in the Storage Account:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageName": {
"type": "string",
"defaultValue": "[concat('storage', uniqueString(resourceGroup().id))]",
"metadata": {
"description": "Provide a unique name for the Blob Storage account."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Provide a location for the Blob Storage account that supports Event Grid."
}
},
"eventSubName": {
"type": "string",
"defaultValue": "subToStorage",
"metadata": {
"description": "Provide a name for the Event Grid subscription."
}
},
"endpoint": {
"type": "string",
"metadata": {
"description": "Provide the URL for the WebHook to receive events. Create your own endpoint for events."
}
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts/providers/eventSubscriptions",
"name": "[concat(parameters('storageName'), '/Microsoft.EventGrid/', parameters('eventSubName'))]",
"apiVersion": "2018-01-01",
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": "[parameters('endpoint')]"
}
},
"filter": {
"subjectBeginsWith": "",
"subjectEndsWith": "",
"isSubjectCaseSensitive": false,
"includedEventTypes": [
"All"
]
}
}
}
]
}
Reference: https://github.com/Azure/azure-quickstart-templates/blob/master/101-event-grid-subscription-and-storage/azuredeploy.json
With the following ARM template, I deploy an Azure Databricks with a custom managed Resource Group Name and add the workers to a custom VNET. In the portal this works fine. But When I try to do this inside an ARM template the managed resource groups keep deploying a workers vnet for the workers. I am thinking that I am on the right track but missing one setting. But can't figure it out. Is there anyone who can see what I am missing ?
Source ARM: https://github.com/Azure/azure-quickstart-templates/tree/master/101-databricks-workspace-with-vnet-injection
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"databricksName": {
"type": "string",
"metadata": {
"description": "The name of the databricks workspace"
}
},
"pricingTier": {
"type": "string",
"allowedValues": [
"trial",
"standard",
"premium"
],
"metadata": {
"description": "The pricing tier of workspace."
}
},
"managedResourceGroupName": {
"type": "string",
"metadata": {
"description": "The name of the managed resource group that databricks will create"
}
},
"Location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The Location of the deployment"
}
},
"vnetName": {
"type": "string",
"metadata": {
"description": "The Name of the virtual network where the Workers would be connected to"
}
},
"privateSubnetName": {
"defaultValue": "public-subnet",
"type": "string",
"metadata": {
"description": "The name of the private subnet to create."
}
},
"publicSubnetName": {
"defaultValue": "private-subnet",
"type": "string",
"metadata": {
"description": "The name of the public subnet to create."
}
}
},
"variables": {
"ManagedResourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('managedResourceGroupName'))]",
"vnetId": "[resourceId('Microsoft.Network/virtualNetworks', parameters('vnetName'))]"
},
"resources": [
{
"name": "[parameters('databricksName')]",
"type": "Microsoft.Databricks/workspaces",
"apiVersion": "2018-04-01",
"tags": {
"description": "MIG6 databricks workspace",
"costCenter": "WPIPM12SG552"
},
"location": "[parameters('Location')]",
"properties": {
"managedResourceGroupId": "[variables('managedResourceGroupId')]",
"parameters": {
"customVirtualNetworkId": {
"value": "[variables('vnetId')]"
},
"customPublicSubnetName": {
"value": "[parameters('publicSubnetName')]"
},
"customPrivateSubnetName": {
"value": "[parameters('privateSubnetName')]"
}
}
},
"sku": {
"name": "[parameters('pricingTier')]"
}
}
]
}
You need to nest the vnet in the template, this works for me:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vnetName": {
"type": "string"
},
"vnetRG": {
"type": "string"
},
"publicSubnetName": {
"type": "string"
},
"publicSubnetCIDR": {
"type": "string"
},
"privateSubnetName": {
"type": "string"
},
"privateSubnetCIDR": {
"type": "string"
},
"workspaceName": {
"type": "string"
},
"tier": {
"type": "string"
},
"location": {
"type": "string"
},
"nsgName": {
"defaultValue": "databricks-nsg",
"type": "string"
},
"environment": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('vnetRG')]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(parameters('vnetName'), '/', parameters('publicSubnetName'))]",
"location": "[parameters('location')]",
"properties": {
"addressPrefix": "[parameters('publicSubnetCIDR')]",
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(parameters('vnetName'), '/', parameters('privateSubnetName'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Network/virtualNetworks/', parameters('vnetName'), '/subnets/', parameters('publicSubnetName'))]"
],
"properties": {
"addressPrefix": "[parameters('privateSubnetCIDR')]",
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
}
]
},
"parameters": {}
}
},
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Databricks/workspaces",
"location": "[parameters('location')]",
"name": "[parameters('workspaceName')]",
"dependsOn": [
"['Microsoft.Resources/deployments/nestedTemplate']"
],
"sku": {
"name": "[parameters('tier')]"
},
"comments": "Please do not use an existing resource group for ManagedResourceGroupId.",
"properties": {
"ManagedResourceGroupId": "[variables('managedResourceGroupId')]",
"parameters": {
"customVirtualNetworkId": {
"value": "[variables('vnetId')]"
},
"customPublicSubnetName": {
"value": "[parameters('publicSubnetName')]"
},
"customPrivateSubnetName": {
"value": "[parameters('privateSubnetName')]"
}
}
}
}
],
"variables": {
"managedResourceGroupId": "[concat(subscription().id, '/resourceGroups/', variables('managedResourceGroupName'))]",
"managedResourceGroupName": "[concat(resourceGroup().name,'-DATABRICKS-MANAGED')]",
"vnetId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('vnetRG'), '/providers/Microsoft.Network/virtualNetworks/', parameters('vnetName'))]",
"nsgId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('vnetRG'), '/providers/Microsoft.Network/networkSecurityGroups/', parameters('nsgName'))]"
},
"outputs": {}
}