Azure Template Specs - Part 3 - Template Links

2023, Apr 04

There are different ways to use and deploy Template Specs. However, if you refer to them as Template Links, you won't need nested ARM templates anymore. This is great news because it simplifies things and makes it easier to reuse code (IaC).

Template Links are especially handy when it comes to Deployment templates. They bring many benefits, especially when used with Azure Blueprints. If you're working with Azure Blueprints, it's a great idea to give Template Links a try to make your work easier and more efficient.

The JSON template

In this example, we are making use of the traditional ARM template, as a deployment template. This is a much simpler implementation, direct to the point. Let's consider the same Template Spec created in Part 2, which was provisioned to Azure:

File c:\templates\deployment.json

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "tsResourceGroup":{
      "type": "string",
      "metadata": {
        "Description": "Specifies the resource group name of the template spec."
      }
    },
    "tsName": {
      "type": "string",
      "metadata": {
        "Description": "Specifies the name of the template spec."
      }
    },
    "tsVersion": {
      "type": "string",
      "defaultValue": "1.0.0",
      "metadata": {
        "Description": "Specifies the version the template spec."
      }
    },
    "storageAccountType": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "metadata": {
        "Description": "Specifies the storage account type required by the template spec."
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-10-01",
      "name": "createStorage",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "id": "[resourceId(parameters('tsResourceGroup'), 'Microsoft.Resources/templateSpecs/versions', parameters('tsName'), parameters('tsVersion'))]"
        },
        "parameters": {
          "location": {
            "value": "[parameters('location')]"
          },
          "storageAccountType": {
            "value": "[parameters('storageAccountType')]"
          }
        }
      }
    }
  ],
  "outputs": {
    "templateSpecId": {
      "type": "string",
      "value": "[resourceId(parameters('tsResourceGroup'), 'Microsoft.Resources/templateSpecs/versions', parameters('tsName'), parameters('tsVersion'))]"
    }
  }
}

Note the different parameters: location, tsResourceGroup, tsName, tsVersion, storageAccountType. They are used within the deployment of the resources, used to deploy the storage template spec, which is referenced via templateLink and its id retrieved from resourceId.

Create a resource via scripting

Assuming that the Template Spec is already deployed to the Resource Group template-specs, available in Part 1, then we can run the following PowerShell2 or Azure CLI3:

New-AzResourceGroupDeployment -ResourceGroupName anyResourceGroup -TemplateFile "c:\templates\deployment.json" -tsResourceGroup template-specs -tsName Storage -tsVersion 1.0.0
az deployment group create -f .\deployment.json -g anyResourceGroup -p tsResourceGroup=template-specs tsName=Storage

Provisioning is straightforward. The resource is created on Resource Group anyResourceGroup.

Don't nest ARM templates anymore, have another look at your IaC implementation and make sure you leverage Template Links1.

Full Series

Azure Template Specs - Part 1 - Introduction

Azure Template Specs - Part 2 - Scripting

Azure Template Specs - Part 3 - Template Links

Azure Template Specs - Part 4 - Bicep Modules