Azure Resource Manager (ARM) templates are starting to become the privileged method for the deployment of resources in the Microsoft Azure Cloud. This results in a stronger community and therefor it’s continuously being improved by our friends from Redmond.
Before going into the technical details I’ll try to explain what brought me to blog about the topic of governance and naming Azure resources.
About a month ago I started working in a Microsoft Azure project team for one of the biggest banks in the Netherlands. The team exists of a couple of folks from Microsoft and some contractors like myself.
One of the coding principles that is being followed is “code as documentation” which means that all code delivered should be clean and self explainable as much as possible.
Because we’re deploying resources in a large environment a good governance plan is a must, which also accounts for the naming standards used for the resources. This can be challenging especially when deploying multi instances of a resource like virtual machines.
Deploying multiple VM’s
When deploying multi VM’s from an ARM template the complexity begins. Because all resources of the same type within a resource group need to have a unique name, a concatenation of various properties has to be used for the name.
In this example the value of the parameter virtualMachineName will be concatenated with the number of the copy index resulting in a name like web-server1, web-server2, etc.
When you’re deploying only a couple of VM’s this won’t be an issue although it doesn’t look very nice. An alternative to this can be to add an extra ‘0’ in front of the index value. This can either be done by adding the ‘0’ in the virtual machine parameter which is a bit clumsy, or add it to the concat. But this will only work when rolling out less that 10 machines.
As a result the name will look something like web-server01, ….web-server010
An alternative is to create a more complex concat with some if statements that will validate the length of the copyindex value to add an extra ‘0’ To do this we also have to add some more magic by using if statements and integer options like ‘less’ and ‘if’
What the hack are you doing here, you might ask to yourself. Well let me break that down.
- First of all we take the name from the parameter virtualMachineName.
- than the If statement checks if the value of the copyindex is less than 10.
- When true an extra ‘0’ is added to the concat
When false no extra character is added
p.s. All supported template expressions and functions can be found (here)
The padLeft can be used to add extra characters to a sting value up to a specified length.
padLeft(valueToPad, totalLength, paddingCharacter)
If we have a string value like “1234” we can use padLeft to add characters to the left side of the string resulting in “xxxx1234”
The following example shows how we can use the padLeft to overcome our challange for naming our virtual machines.
The above sample will result in an output value of web-server001 Pretty nice ay!
Now that we have solved the long expressions, we are still looking at another challenge although it is a minor one. Because a virtual machine exists out of multiple components like an os-disk, data disk(s), network interface(s), and the VM itself we need to do the concatenation for every resource that is related to the same VM. Although this is not a technical requirement, it helps you to keep an overview of all the resources that belong together.
As I mention before I don’t like to do the same thing more than once, so how can we solve this?
Since the start of may 2018 it is possible to to create your own functions within the ARM templates. This is great because you can now move the complicated expressions, that you don’t want to repeat for every resource to a separate section called functions. You can use all expressions and functions that are supported in template to create your own. user-defined functions
Because these user-defined functions are pretty new, there’s currently not a lot of documentation available. The current schema doesn’t recognize the parameters defined in the functions although they happily work as expected. This will probably be fixed soon by the good folks at Microsoft.
To add the functions to your template a separate section has to be declared as shown in the following example:
Now that we have functions section available we can start building our user-defined function for naming our resources.
What happens here is that when calling the function myFunctions.vmName two parameters needs to be passed to the user-defined function. In this case we are using “virtualMachineName” and “copyindex(1)” as an input value for our function. these two input parameters will be used in the concat at the output section of our user-defined function to generate a new name.
The output of the above example will be something like: “web-server001”
In this example we have kept it pretty easy, but you can build awesome expressions to generate a new function that fits your needs.
A full version of the json template for a virtual machine can be found on my (GitHub)
The result of this deployment is shown below.
Some improvements in my opinion would be a to create nested functions. Right now if we want to create a separate function for the naming of our network interfaces we still have to redo the same concatenation as before, which results in doing the same multiple times again, something I’m trying to prevent.
What you can do is create a concat with a function in the name property of a resource, but still this is not ideal to my opinion.
Another great feature would be an option to call functions from other nested templates. Especially when creating very complex expressions. This could help to create one template with only functions that could be used by other templates.
Again you don’t want to copy/paste the same code over-and-over again into new templates that your creating.
User-defined functions are a great way to handle complex scenario’s in your ARM templates although some functionality is still missing. I do recommend using this new capability to make your templates more readable and keep all the complexity in a separate section of your template, instead of in every name property of the resource that you’re deploying.
Have fun coding!