Exercise - Add conditional logic to your ARM template

Completed

In the previous exercises, you worked with Linux virtual machines. Here, you switch gears a bit and focus on managing storage accounts.

Let's say that you have three environments that you need to deploy to: Dev, Staging, and Production.

  • The Dev environment is the first place where everything your application needs comes together. This environment might include web servers, a load balancer, and a database.
  • The Staging environment is where final testing happens before new application features are released to your end users.
  • The Production environment is where your end users access your application.

As you move from Dev to Production, you require additional infrastructure. For example, in Production, you require an additional storage account that you don't need in the previous environments.

Here, you use a condition to control when a storage account is provisioned. Doing so enables you to support each of your infrastructure environments from the same ARM template.

Create the ARM template

Here, you create an Azure Resource Manager (ARM) template that defines a storage account resource.

The template also defines two parameters:

  • environment: the name of the current environment.
  • storageAccountName: the name for the storage account.

environment can have one of three values: dev, staging, or production. The condition provisions the storage account only when environment equals production.

  1. In Visual Studio Code, create a file named condition.json in the same directory that contains azuredeploy.json.

  2. Add these contents to condition.json:

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "environment": {
          "type": "string",
          "defaultValue": "dev",
          "allowedValues": [
            "dev",
            "staging",
            "production"
          ],
          "metadata": {
            "description": "a value that represents the current environment"
          }
        },
        "storageAccountName": {
          "type": "string",
          "metadata": {
            "description": "a name for the account"
          }
        }
      },
      "functions": [],
      "variables": {},
      "resources": [
        {
          "condition": "[equals(parameters('environment'),'production')]",
          "name": "[parameters('storageAccountName')]",
          "type": "Microsoft.Storage/storageAccounts",
          "apiVersion": "2019-06-01",
          "tags": {
            "displayName": "[parameters('storageAccountName')]"
          },
          "location": "[resourceGroup().location]",
          "kind": "StorageV2",
          "sku": {
            "name": "Premium_LRS",
            "tier": "Premium"
          }
        }
      ],
      "outputs": {}
    }
    

Here you will deploy an ARM template, with a condition construct, by using PowerShell and the Az module.

Provision the Dev environment

Here, you deploy the ARM template to the Dev environment. You do so by setting the environment template parameter to dev.

Because the condition provisions the storage account only when environment equals production, you expect the template to not provision the storage account. In other words, you expect a deployment that contains zero resources.

  1. Create a PowerShell variable that holds the storage account name.

    $STORAGE_ACCT_NAME="tailwindsa"+ (Get-Random -COUNT 1 -Maximum 9999999 )
    

    Storage account names must be unique. The Get-Random part ensures that the storage account name ends in a random series of numbers.

  2. Run the following New-AzResourceGroupDeployment command to deploy the template to the Dev environment:

    New-AzResourceGroupDeployment `
      -TemplateFile "./condition.json" `
      -storageAccountName $STORAGE_ACCT_NAME `
      -environment dev
    

Verify the deployment to Dev

Remember, you expect the template to have not provisioned the storage account.

To verify this fact, you run the Get-AzStorageAccount command to check whether the storage account name is already in use.

Run the command Get-AzStorageAccount:

Get-AzStorageAccount -Name $STORAGE_ACCT_NAME -ResourceGroupName <rgn>sandbox resource group</rgn>

Your output resembles this:

Get-AzStorageAccount: The Resource 'Microsoft.Storage/storageAccounts/tailwindsa4736629' under resource group '<rgn>name of resource group</rgn>' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix

This tells you that the storage account hasn't yet been provisioned. You expect this because you haven't yet deployed to the Production environment.

Provision the Production environment

Here, you deploy the ARM template to the Production environment, similar to how you did for the Dev environment.

As a refresher, here's what the condition looks like in your template:

"condition": "[equals(parameters('environment'),'production')]"

To trigger this condition, you set the environment template parameter to production.

Run the following New-AzResourceGroupDeployment command to deploy the template to the Production environment:

New-AzResourceGroupDeployment `
  -TemplateFile "./condition.json" `
  -storageAccountName $STORAGE_ACCT_NAME `
  -environment production

Verify the deployment to Production

This time, you expect the template to have provisioned the storage account.

To verify this fact, you run the Get-AzStorageAccount command again to verify that the storage account name is in use.

Run the following Get-AzStorageAccount command:

Get-AzStorageAccount -Name $STORAGE_ACCT_NAME -ResourceGroupName <rgn>sandbox resource group</rgn>

This time around you'll get a different output. Instead of an error message, it shows this table output that shows information about your storage account resource:

Your output resembles this:

Location Name              Type                              Kind
-------- ----              ----                              ----
westus   tailwindsa4736629 Microsoft.Storage/storageAccounts StorageV2

These values tell you that the storage account has been provisioned as you expect.

Although this is a basic example, you see how to deploy based on a condition.

In practice, your Dev, Staging, and Production environments would contain additional Azure resources to support your compute, networking, and storage needs. Each environment would likely be managed through its own resource group so that it can be provisioned and treated as a single unit.

Create the ARM template

Here, you create an Azure Resource Manager (ARM) template that defines a storage account resource.

The template also defines two parameters:

  • environment: the name of the current environment.
  • storageAccountName: the name for the storage account.

environment can have one of three values: dev, staging, or production. The condition provisions the storage account only when environment equals production.

  1. In Visual Studio Code, create a file named condition.json in the same directory that contains azuredeploy.json.

  2. Add these contents to condition.json:

    {
      "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "environment": {
          "type": "string",
          "defaultValue": "dev",
          "allowedValues": [
            "dev",
            "staging",
            "production"
          ],
          "metadata": {
            "description": "a value that represents the current environment"
          }
        },
        "storageAccountName": {
          "type": "string",
          "metadata": {
            "description": "a name for the account"
          }
        }
      },
      "functions": [],
      "variables": {},
      "resources": [
        {
          "condition": "[equals(parameters('environment'),'production')]",
          "name": "[parameters('storageAccountName')]",
          "type": "Microsoft.Storage/storageAccounts",
          "apiVersion": "2019-06-01",
          "tags": {
            "displayName": "[parameters('storageAccountName')]"
          },
          "location": "[resourceGroup().location]",
          "kind": "StorageV2",
          "sku": {
            "name": "Premium_LRS",
            "tier": "Premium"
          }
        }
      ],
      "outputs": {}
    }
    

Provision the Dev environment

Here, you deploy the ARM template to the Dev environment. You do so by setting the environment template parameter to dev.

Because the condition provisions the storage account only when environment equals production, you expect the template to not provision the storage account. In other words, you expect a deployment that contains zero resources.

  1. Create a Bash variable that holds the storage account name.

    STORAGE_ACCT_NAME=tailwindsa$RANDOM
    

    Storage account names must be unique. The $RANDOM part ensures that the storage account name ends in a random series of numbers.

  2. Run the following az deployment group create command to deploy the template to the Dev environment:

    az deployment group create \
      --template-file condition.json \
      --parameters storageAccountName=$STORAGE_ACCT_NAME environment=dev
    

Verify the deployment to Dev

Remember, you expect the template to have not provisioned the storage account.

To verify this fact, you run the az storage account check-name command to check whether the storage account name is already in use.

Run the following az storage account check-name command:

az storage account check-name --name $STORAGE_ACCT_NAME

You see this:

{
  "message": null,
  "nameAvailable": true,
  "reason": null
}

The value for nameAvailable is true, which means that the storage account name is still available and hasn't yet been provisioned. You expect this because you haven't yet deployed to the Production environment.

Provision the Production environment

Here, you deploy the ARM template to the Production environment, similar to how you did for the Dev environment.

As a refresher, here's what the condition looks like in your template:

"condition": "[equals(parameters('environment'),'production')]"

To trigger this condition, you set the environment template parameter to production.

Run the following az deployment group create command to deploy the template to the Production environment:

az deployment group create \
  --template-file condition.json \
  --parameters storageAccountName=$STORAGE_ACCT_NAME environment=production

Verify the deployment to Production

This time, you expect the template to have provisioned the storage account.

To verify this fact, you run the az storage account check-name command again to verify that the storage account name is in use.

Run the following az storage account check-name command:

az storage account check-name --name $STORAGE_ACCT_NAME

Your output resembles this:

{
  "message": "The storage account named tailwindsa32100 is already taken.",
  "nameAvailable": false,
  "reason": "AlreadyExists"
}

These values tell you that the storage account has been provisioned as you expect.

Although this is a basic example, you see how to deploy based on a condition.

In practice, your Dev, Staging, and Production environments would contain additional Azure resources to support your compute, networking, and storage needs. Each environment would likely be managed through its own resource group so that it can be provisioned and treated as a single unit.