I have a scenario where i need to generate the parameters names dynamically. Like certificate1, certificate2, certificate3 .. so on. Currently all these parameters should be defined in Main template. Can we use copy to iterate and define parameter Names dynamically in Main/Parent template? Or is there a way in ARM templates by which this can be accomplished?
you can use copy construct in variables section or in resource definition\resource properties. and then you can use concat() together with copyIndex() function to create names.
example:
[concat('something-', copyIndex())]
this will give you names like something-0, something-1, something-2 etc. (copyIndex starts at 0). you can also choose to offset copyIndex by giving it an offset number:
[concat('something-', copyIndex(10))]
this will give you name like something-10, something-11, something-12 etc.
copy in variables\properties:
"copy": [
{
"name": "nameOfThePropertyOrVariableYouWantToIterateOver",
"count": 3,
"input": {
"name": "[concat('something-', copyIndex('nameOfThePropertyOrVariableYouWantToIterateOver', 1))]"
}
}
]
here you need to specify which loop are you referring to with copyIndex function and you can use offset as well
You can use the copy function in Azure Template to generate the name of the resource, just like certificate1, certificate2, certificate3 .. so on.
Example below:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2016-01-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[concat('storage',copyIndex())]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage",
"properties": {},
"copy": {
"name": "storagecopy",
"count": 3
}
}
],
"outputs": {}
}
And the storage name will like these:
storage0
storage1
storage2
For more details, see Deploy multiple instances of a resource or property in Azure Resource Manager Templates.
Related
I'm working on an ARM template and need to perform conditional deployment. For instance, I've got two network security groups defined in a variable 'subnets'.
"variables": {
"subnets": [
{
"subnetname": "AzureBastionSubnet",
"nsgname": "nsg_bastion1"
},
{
"subnetname": "client-subnet",
"nsgname": "nsg_client1"
}
]
}
The network security group 'nsg_bastion1' needs special treatment with predefined rules since it is a network security group for an Azure Bastion subnet.
'nsg_client1' will get some custom rules assigned, which don't matter at this point.
In order to differentiate between non-Bastion and Bastion-network security groups, I've created two conditional resource blocks:
"resources": [
// NSG (non-Bastion)
{
"condition": "[not(equals(variables('subnets')[copyIndex()].name, 'AzureBastionSubnet'))]",
"name": "[variables('subnets')[copyIndex()].nsg]",
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2019-11-01",
"location": "[parameters('location')]",
"properties": {},
"copy": {
"name": "nsg-c",
"count": "[length(variables('subnets'))]"
}
},
// NSG (Bastion)
{
"condition": "[equals(variables('subnets')[copyIndex()].name, 'AzureBastionSubnet')]",
"name": "[variables('subnets')[copyIndex()].nsg]",
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2019-11-01",
"location": "[parameters('location')]",
"properties": {},
"resources": [
// Bastion Security Rules .....
],
"copy": {
"name": "nsg-bastion-c",
"count": "[length(variables('subnets'))]"
}
},]
The condition property checks whether the subnet is called 'AzureBastionSubnet' or not. I've verified that this works for both resource blocks alone, but it doesn't when they're included both in the code. It always throws the following error message:
Code=InvalidTemplate; Message=Deployment template validation failed:
'The resource 'Microsoft.Network/networkSecurityGroups/AzureBastionSubnet' at line '' and column '' is defined multiple times in a template.
I'd appreciate any help, thanks in advance!
Ok, I thought we had fixed this but not yet...
Even though your conditions are mutually exclusive, you can't have 2 resources with the same resourceId in the same template.
I'm guessing the difference between the two is in the securityRules? If so, simplest option may be to define 2 separate vars and then use an if() statement to swap between them based on your condition.
Failing that if you want to expand on the template can see if there is a better option...
I am creating ARM template which takes in hash table of subnets and creates those. However, it looks that I need to wait for the first subnet to be ready before creating the second etc. But I do not know how I could depend on the previous subnet in copy loop. My template resource looks like this currently:
{
"apiVersion": "2018-06-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(parameters('vnetName') , '/' , parameters('subnets').settings[copyIndex()].name)]",
"location": "[variables('location')]",
"copy": {
"name": "subnetLoop",
"count": "[variables('subnetcount')]"
},
"dependsOn": ["[parameters('vnetName')]",
"[resourceId(variables('rgname'), 'Microsoft.Network/virtualNetworks/subnets', parameters('vNetName'), parameters('subnets').settings[copyIndex()].name)]"
],
"properties": {
"addressPrefix": "[parameters('subnets').settings[copyIndex()].addressPrefix]",
}
Which does not work because the first subnet cannot reference itself.
you can use "mode": "serial" to workaround that.
"copy": {
"name": "subnetLoop",
"count": "[variables('subnetcount')]",
"mode": "serial"
},
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#resource-iteration
but you really need to look at properties loop, check this link:
https://learn.microsoft.com/en-us/azure/architecture/building-blocks/extending-templates/objects-as-parameters#using-a-property-object-in-a-copy-loop
I am trying to get a arm template running and have hit an issue with the virtualnetwork creation.
azuredeploy.json
"virtualNetworkName": {
"type": "string",
"metadata": {
"description": "Name of virtual network to be created"
},
"defaultValue": "autohav2VNET"
},
vnet-net.json
"resources": [
{
"name": "[parameters('virtualNetworkName')]",
"type": "Microsoft.Network/virtualNetworks",
"location": "[parameters('location')]",
"apiVersion": "2015-06-15",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('virtualNetworkAddressRange')]"
]
},
"subnets": "[parameters('subnets')]"
}
}
]
The issue I am getting is that the vnet gets created with an appendix such as this: autohav2VNETl5g
So when this gets used to create a loadblancer, the names doe not match the defined parameter and the creation fails.
..../virtualNetworks/AUTOHAV2VNET referenced by resource .... /Microsoft.Network/loadBalancers/sqlLoadBalancer was not found.
Any suggestions?
with the data given it impossible to be sure why this is happening. you are probably passing in a value to the parameter virtualNetworkName. because if you wouldn't, than the vnet name would be: autohav2VNET.
ARM templates do not append anything anywhere just because they are arm templates. they only do what you designed them to do.
to help with debugging: how you are invoking the template and full template + full parameters file.
Not sure if it is supported in ARM. I could find power-shell references only.
You cannot currently deploy a dacpac with an ARM template. The link above uses PowerShell but not ARM. You can create however create a database from a source database as a copy using an ARM template.
A simple way to find an example template for any Azure action is to perform the action in the portal - in this case, copy a database - and then open the appropriate resource group blade in the portal, list the deployments, locate the deployment just submitted and open it. Then select ViewTemplate from the menu bar and examine both the Template tab and the Parameters tab. These show you the full template and the parameter values actually used. You can then download the template, with accompanying Powershell script.
For database copy, here is the template:
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"databaseName": {
"type": "string"
},
"serverName": {
"type": "string"
},
"location": {
"type": "string"
},
"createMode": {
"type": "string"
},
"sourceDatabaseId": {
"type": "string"
},
"requestedServiceObjectiveName": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2014-04-01-preview",
"location": "[parameters('location')]",
"name": "[concat(parameters('serverName'), '/', parameters('databaseName'))]",
"properties": {
"createMode": "[parameters('createMode')]",
"sourceDatabaseId": "[parameters('sourceDatabaseId')]",
"requestedServiceObjectiveName": "[parameters('requestedServiceObjectiveName')]"
},
"type": "Microsoft.Sql/servers/databases"
}
]
}
For database copy createMode = 'Copy'
And be sure to provide a fully qualified resourceId formatted as follows:
"/subscriptions/<sub-id>/resourceGroups/<resourceGroupName>/providers/Microsoft.Sql/Servers/<server-name>/databases/<database-name>"
Make sure the resource group name capitalization is correct and that the server name is all lower case.
You can use the sourceDatabaseId property to reference another database. Then you can specify various createModes depending on what type of database you would like to create:
{
"properties": {
"createMode": "OnlineSecondary",
"sourceDatabaseId": "[resourceId('Microsoft.Sql/servers/databases', variables('sql01Name'), 'databasename')]"
}
}
http://msdn.microsoft.com/en-us/library/azure/mt163685.aspx
The answer above from #Bill Gibson - MSFT works if you are using a Microsoft.Sql/servers resource, however if you're using a Microsoft.Sql/managedInstances resource you'll need to use the appropriate Microsoft.Sql/managedInstance/databases - ARM Template.
The following works for me to perform a PointInTimeRestore accessing a source database that lives in another resource group (the variables and parameters are left as an exercise to the reader):
{
"type": "Microsoft.Sql/managedInstances/databases",
"name": "[concat(variables('destinationSqlManagedInstanceName'), '/', 'AdventureWorks')]",
"apiVersion": "2021-11-01",
"location": "[parameters('location')]",
"properties": {
"createMode": "PointInTimeRestore",
"restorePointInTime": "2022-12-14T12:00:00Z",
"sourceDatabaseId": "[resourceId(variables('sourceResourceGroupName'), 'Microsoft.Sql/managedInstances/databases', variables('sourceSqlManagedInstanceName'), 'AdventureWorks')]"
}
}
The documentation is broken in a few ways:
When attempting to perform a PointInTimeRestore the properties referenced (SourceDatabaseName, SourceManagedInstanceName, PointInTime) do not exist. Rather the following properties are used: restorePointInTime and sourceDatabaseId which are documented in the documentation.
Additionally, the restorePointInTime indicates that the time should be in ISO8601 format, however this is not the same as what is returned by utcNow(). Testing has shown that you must provide it in this version of the ISO8601 format: yyyy-MM-ddTHH:mm:ssZ which can be done using utcNow('yyyy-MM-ddTHH:mm:ssZ').
I have created an issue to try and get the documentation fixed up here: https://github.com/MicrosoftDocs/azure-docs/issues/102717
Does anyone know how to place Resources in an ARM template into specific, and different Resource Groups? This might be the storage in one RG and the network in another, both created in the same, or different, templates (nested, for example).
Full details are below.
Reading through the best practice guide ARM template best practice and the whitepaper World Class ARM Templates Considerations and Proven Practices there's a recommendation that different elements of a deployment should be situated in separate Resource Groups. For example, in an IaaS solution, your DCs might sit in an Admin RG, your back-end servers in another, and your client desktops in a third.
I'm currently trying to deploy such a solution via nested templates, and I've stumbled upon an issue whereby all items being created are automatically placed inside the Resource Group selected when kicking the process off (i.e. the parent template). I've looked through the various documentation online but can't obviously find a way to force resources being created in a template into a specific Resource Group. Has anyone done this?
For anyone else that finds this in google (like I did):
It is now possible to deploy resources to multiple resource groups in one ARM template. Microsoft has details available here: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-cross-resource-group-deployment for the details.
To do this you include a nested deployment template within the main one, and set the nested deployment to another resource group. here is an example from the MS Site:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storagePrefix": {
"type": "string",
"maxLength": 11
},
"secondResourceGroup": {
"type": "string"
},
"secondSubscriptionID": {
"type": "string",
"defaultValue": ""
},
"secondStorageLocation": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"firstStorageName": "[concat(parameters('storagePrefix'), uniqueString(resourceGroup().id))]",
"secondStorageName": "[concat(parameters('storagePrefix'), uniqueString(parameters('secondSubscriptionID'), parameters('secondResourceGroup')))]"
},
"resources": [
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('secondResourceGroup')]",
"subscriptionId": "[parameters('secondSubscriptionID')]",
"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.Storage/storageAccounts",
"name": "[variables('secondStorageName')]",
"apiVersion": "2017-06-01",
"location": "[parameters('secondStorageLocation')]",
"sku":{
"name": "Standard_LRS"
},
"kind": "Storage",
"properties": {
}
}
]
},
"parameters": {}
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('firstStorageName')]",
"apiVersion": "2017-06-01",
"location": "[resourceGroup().location]",
"sku":{
"name": "Standard_LRS"
},
"kind": "Storage",
"properties": {
}
}
]
}
It is not possible to deploy resources into multiple resource groups from a template. Simply by virtue of the fact that the Azure Resource Manager REST API Reference only has a single place to specify the resource group name.
The concept of ARM templates is that you create a resource group and deploy a template into it, and thus provide a single administrative unit from which to manage those resources. This improves over the Azure Service Management model where you had to manage each resource individually.
Nested resource groups would be quite a nice feature to fulfill your need, but I've never heard of such a thing being planned for Azure.