5 min read

Writing ARM Templates in YAML

Justin Yoo

In my previous post, ARM Template Lifecycle Management: DOs and DON'Ts, I recommend to consider YAML for ARM template authoring. In the post, I also suggest using yarm to convert YAML to JSON and/or vice-versa. However, yarm is not that easy to use because it has to be deployed to Azure or, at least, it has to be run on your local machine. What if there is a command-line tool for easy conversion between YAML and JSON? If this is the case, integrating it with a CI/CD pipeline will be much easier. In this post, I am going to write an ARM template in YAML, build it to JSON, test it against Pester, and finally deploy it to Azure.

Why YAML?

As I mentioned in my previous post, YAML is a superset of JSON and much more human-readable while authoring complex objects like ARM templates. Have a look at the picture below.

The left-hand side of the picture is the original ARM template for Azure Virtual Machine. Can you easily find out where the square brackets are, amongst all curly braces? I know. It is very hard to spot them. On the other hand, at the right-hand side, the same ARM template is written in YAML format. Does it look easier to read? Of course it does.

Therefore, it will be fantastic, if I write the ARM template in YAML and can easily convert it to JSON which Azure PowerShell or Azure CLI understands.

YARM CLI

Instead of using an Azure Function instance of yarm, there is a command-line tool, called yarm cli. It is a very simple cross-platform tool, which is written in C# with .NET Core. It's even better because it doesn't require you to install any .NET Core runtime on your machine. If you want to know more about yarm cli, read this post, Introducing YARM CLI

Let's create a simple Azure Logic App placeholder in YAML.

$schema: 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#'
contentVersion: 1.0.0.0
parameters:
logicAppName1:
type: string
metadata:
description: Name of the Logic App.
logicAppName2:
type: string
metadata:
description: Name of the Logic App.
variables:
logicApp:
name: "[concat(parameters('logicAppName1'), '-', parameters('logicAppName2'))]"
apiVersion: "[providers('Microsoft.Logic', 'workflows').apiVersions[0]]"
location: '[resourceGroup().location]'
tags:
author: Justin Yoo
profile: 'https://twitter.com/justinchronicle'
projectUrl: 'https://github.com/devkimchi/ARM-Templates-in-YAML'
repositoryUrl: 'https://github.com/devkimchi/ARM-Templates-in-YAML'
license: 'https://raw.githubusercontent.com/devkimchi/ARM-Templates-in-YAML/master/LICENSE'
resources:
- apiVersion: "[variables('logicApp').apiVersion]"
type: Microsoft.Logic/workflows
name: "[variables('logicApp').name]"
location: "[variables('logicApp').location]"
tags: "[variables('tags')]"
properties:
state: Enabled
parameters: {}
definition:
$schema: 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#'
contentVersion: 1.0.0.0
parameters: {}
triggers: {}
actions: {}
outputs: {}
outputs:
subscriptionId:
type: string
value: '[subscription().subscriptionId]'
resourceGroup:
type: string
value: '[resourceGroup().name]'

This YAML file itself can't be used for testing nor deploying. Therefore, it needs to be converted into JSON, using yarm cli.

yarm -i azuredeploy.yaml -o azuredeploy.json

That's it, actually. Now, we need to do this conversion task on our preferred CI/CD pipeline. Let's move on.

YARM CLI on VSTS

In this post, I'm going to use VSTS. Let's have a look at the build tasks. The build pipeline consists of several tasks including the yarm cli installation and YAML to JSON conversion.

Installing yarm cli is easy. Run the following PowerShell script and it will install the latest release of yarm cli onto VSTS. As I mentioned above, it doesn't install the .NET Core runtime at all. Therefore, if you are running yarm cli on your machine, even if you don't have any .NET Core runtime installed, it shouldn't really matter.

$script = Invoke-WebRequest https://raw.githubusercontent.com/TeamYARM/YARM-CLI/master/Download-Latest.ps1
$argList = "win-x64", "$(System.DefaultWorkingDirectory)\yarm-cli"
Invoke-Command -ScriptBlock ([scriptblock]::Create($script.Content)) -ArgumentList $argList

Conversion is also easy. Simply loop through all YAML files and convert them one-by-one.

$directory = "$(Build.SourcesDirectory)"
$yarmpath = "$(System.DefaultWorkingDirectory)\yarm-cli\yarm.cmd"
$targetdir = "$(Build.SourcesDirectory)"
Get-ChildItem -Path $directory -Recurse -Include *.yaml | `
ForEach { & $yarmpath -i $_.FullName -o "$targetdir\$($_.Name)".Replace(".yaml", ".json") }

Now, we have the converted ARM template that can be understood by Azure PowerShell and Azure CLI. Let's move onto the test part.

Test ARM Template

As I have already dealt with this topic in my previous post, Testing ARM Templates with Pester #2 – Azure CLI, I'm not going walk through this part here. But, I'm going to show the steps for this – install Pester, install Azure CLI, run Pester for test and publish the test results.

Build and Publish Artifacts

Once all tests are passed, the ARM template needs to be packaged for deployment.

When this build pipeline is run, we can see the result like this:

The fact that we reach this part means that all steps – build, test and creating artifacts – in the CI pipeline is done. Now, let's move onto the release pipeline.

Deploy ARM Template

ARM template deployment is not that special. Just use the release task, Azure Resource Group Deployment.

Once the release pipeline is successfully run, you can see the screen like:


So far, I have shown the full lifecycle of the ARM template, from authoring it in YAML to deploying it to Azure. The only caveat of this approach is no intelli-sense support because YAML for ARM template authoring is not officially supported out-of-the-box. However, other than this, it will bring much better productivity increase due to its better readability.

This was originally posted at Mexia Blog.