Using Azure Resource Manager functions to save time building ARM templates

Using Azure Resource Manager with templates helps the organization build Azure resources and solutions in a predictable and consistent way. In this article, we are going to be building ARM templates and explore the process to name resources, define a location, and ensure that API is dynamic instead of being entered manually.vi

Naming your resources

When deploying resources, the cloud administrator has several options: decide the name on the fly, use a naming convention, or a mix where part of the name is entered when running the ARM template and then some random characters are added to it.

When building ARM templates, we can start simply by asking the resource prefix (in our case we will create a parameter called StorageAccount. My favorite method is to use defaultvalue, which means if the user doesn’t enter anything we use that predefined as a standard value.


“parameters”: {
“StorageAccountPrefix”: {
“type”: “string”,
“defaultValue”: “ap6sa6”
}
},


At this point we have the prefix defined, but Storage Accounts, like some other resources in Microsoft Azure, must have a unique name. The best way to accomplish that is by using the function uniqueString(), which will create a hash of the value that we enter between parenthesis. Because we want to be as dynamic as possible, we can combine with the function resourcegroup().id, which will return the Resource ID of the current resource group. Both functions combined will generate a hash of 13 characters that we will add to the prefix that we defined in the parameters section.

One more piece to the puzzle — we have the prefix that we will use for the Storage Account and we know how to create a unique and consistent string to be added, but we need to combine both these pieces of information. We can do that using the concat() function, which aggregates all information that we added to it.

At the end of the day, we want to keep it simple and save as much real estate as possible. That being said, we can use a variable that will apply the three functions that we have just seen in a single line. Here is the variables section of our initial ARM template.


“variables”: {
“vStorageAccountName”: “[concat(parameters(‘StorageAccountPrefix’), uniqueString(resourceGroup().id))]”
},


Specifying your location

One attribute that must be defined is the location of the new resource that we are trying to deploy. If we are using Visual Studio, we can take advantage of IntelliSense capabilities, which will provide all available options. This works well for a location attribute as depicted in the image below. Note: If you are not getting that information, type Ctrl + Space and the list will be displayed.

building arm templates

Defining a location is acceptable, however, if we have to deploy in different environments — we may have to go back to the code and type in the new location, which is not good, right? We can take advantage of the function ResourceGroup().location and the location of the Resource Group will be used instead, thus saving time and keeping the ARM template clean and avoid unnecessary manual changes.

Instead of typing the location name, just add the code and your location will always use the same location of the Resource Group, which makes sense — usually, you want to deploy your resources at the same location where your Resource Group is located.
“location”: “[resourceGroup().location]”,

Defining your API version

What dictates which features are available in an ARM template is the API that we are using, and when using the latest API we have access to all the cool resources. In some cases, we may have to force a specific API, although that should be the exception and not the rule. We will use latest API available as standard.

We can use the function Providers() where we provide the provider and resource type and retrieve the first position (latest API available) of the array containing all available API versions.
"apiVersion": "[providers(‘Microsoft.Storage’,’storageAccounts’).apiVersions[0]]"
In order to check the API available for any given Resource Provider, we can use the following cmdlet (the items in bold must be replaced based on your requirements — in this example, we are checking Microsoft.Storage/storageAccounts). Keep in mind that we can take advantage of IntelliSense for that as well when using Visual Studio.

If you want to check using PowerShell, make sure that you are connected to Microsoft Azure and run the following cmdlet.

((Get-AzureRmResourceProvider -ProviderNamespace Microsoft.Storage).ResourceTypes | where { $_.ResourceTypeName -eq 'storageAccounts' } ).ApiVersions

building arm templates

Creating a Storage Account

Time to add the functions that we covered in the previous sections in a simple resource deployment. We will start with a simple Storage Account. We will use Visual Studio to add a resource to a brand-new ARM template and we will incorporate the changes that we introduced in this article.

The final script would be similar to this code below, in theory. If the user does not add anything, a storage account using our naming convention (prefix ap6sa6<randon> will be used).

The beauty of this code is that we are not specifying the location (using the Resource Group location). API and name are being added automatically and without manual intervention.


{
“$schema”: “https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#”,
“contentVersion”: “1.0.0.0”,
“parameters”: {
“StorageAccountPrefix”: {
“type”: “string”,
“defaultValue”: “ap6sa6”
},
“StorageAccountType”: {
“type”: “string”,
“defaultValue”: “Standard_LRS”,
“allowedValues”: [
“Standard_LRS”,
“Standard_ZRS”,
“Standard_GRS”,
“Standard_RAGRS”,
“Premium_LRS”
]
}
},
“variables”: {
“vStorageAccountName”: “[concat(parameters(‘StorageAccountPrefix’), uniqueString(resourceGroup().id))]”
},
“resources”: [
{
“name”: “[variables(‘vStorageAccountName’)]”,
“type”: “Microsoft.Storage/storageAccounts”,
“location”: “[resourceGroup().location]”,
“apiVersion”: “[providers(‘Microsoft.Storage’,’storageAccounts’).apiVersions[0]]”,
“sku”: {
“name”: “[parameters(‘StorageAccountType’)]”
},
“dependsOn”: [],
“kind”: “Storage”
}
],
“outputs”: {}
}


There are several ways to test the deployment. The easiest one is to check the Azure Portal. We should have the resource deployed, as depicted in the image below.

building arm templates

At the Resource Group level, we can check the Deployments and validate the input, output, and the template itself that was used to deploy the resources in the Resource Group, including our Storage Account creation using ARM templates.

building arm templates

Checking your code using the output section

Using the code above and some of the methods to check if the resource was deployed properly is definitely useful. However, we can take advantage of the output section in the ARM template to send some information back, and that helps during troubleshooting purposes.

For example, adding the code below to give the Storage Account name, the API version that is being used, its location, and so forth can be helpful.


“outputs”: {
“Storage Account name”: {
“type”: “string”,
“value”: “[variables(‘vStorageAccountName’)]”
},
“Storage Account API version”: {
“type”: “string”,
“value”: “[providers(‘Microsoft.Storage’,’storageAccounts’).apiVersions[0]]”
},
“StorageAccountResourceID”: {
“type”: “string”,
“value”: “[resourceId(‘Microsoft.Storage/storageAccounts’,variables(‘vStorageAccountName’))]”
},
“Storage Account location”: {
“type”: “string”,
“value”: “[resourceGroup().location]”
}
}
}


When deploying using Visual Studio, we can see the output on the output window and we can check the results as depicted in the image below.

building arm templates

As you can see, using ARM functions in building ARM templates is relatively painless and will bring a lot of rewards.

Featured image: Shutterstock

Leave a Comment

Your email address will not be published.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top