0
votes

I am attempting to deploy a resource with Terraform using an ARM template. I will give some simple sample code below that demonstrates the issue. I realize the code below is deploying a storage account and can be done in Terraform without an ARM template, but I am just providing a piece of simple code to demonstrate the problem. My real code is deploying a SQL Managed Instance which is much more complicated and likely just confuses the question.

Here is the main.tf:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "2.41.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "resourcegroup" {
  location = "North Central US"
  name     = "test"
}

resource "azurerm_resource_group_template_deployment" "deployment" {
  name                = "test-${formatdate("YYYYMMDDhhmmss", timestamp())}"
  resource_group_name = azurerm_resource_group.resourcegroup.name
  deployment_mode     = "Incremental"
  template_content    = file("template.json")
  parameters_content = templatefile("parameters.json",
    {
      name = "vwtuvnpplzgelqey"
      supportsHttpsTrafficOnly = true
    }
  )
}

Here is the ARM template.json file:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "name": {
            "type": "string"
        },
        "supportsHttpsTrafficOnly": {
            "type": "bool"
        }
    },
    "variables": {},
    "resources": [
        {
          "type": "Microsoft.Storage/storageAccounts",
          "apiVersion": "2019-04-01",
          "name": "[parameters('name')]",
          "location": "northcentralus",
          "sku": {
            "name": "Standard_LRS"
          },
          "kind": "StorageV2",
          "properties": {
            "supportsHttpsTrafficOnly": "[parameters('supportsHttpsTrafficOnly')]"
          }
        }
    ]
}

Here is the ARM parameters.json file:

{
    "name": {
        "value": "${name}"
    },
    "supportsHttpsTrafficOnly": {
        "value": "${supportsHttpsTrafficOnly}"
    }
}

If I run terraform apply on this with just the name as a parameter and hard-code supportsHttpsTrafficOnly to a true value (e.g. "supportsHttpsTrafficOnly": true), it works perfectly and the storage account is successfully deployed. As soon as I change it to use the parameter for supportsHttpsTrafficOnly, it fails with the following error:

: Code="InvalidTemplate" Message="Deployment template validation failed: 'Template parameter JToken type is not valid. Expected 'Boolean'. Actual 'String'. Please see https://aka.ms/resource-manager-parameter-files for usage details.'." AdditionalInfo=[{"info":{"lineNumber":1,"linePosition":213,"path":"properties.template.parameters.supportsHttpsTrafficOnly"},"type":"TemplateViolation"}]

This error indicates that the value for supportsHttpsTrafficOnly is a string when it should be a boolean. I don't understand this error as I am clearly defining the type as bool in the template.json file.

What am I missing so that the value is interpreted as a bool value instead of a string?

2

2 Answers

0
votes

Per documentation: https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-syntax#data-types

When specifying boolean and integer values in your template, don't surround the value with quotation marks. Start and end string values with double quotation marks.

What you have in your code is "value": "${supportsHttpsTrafficOnly}". This probably interpreted as "value": "true" when you pass a var into it.

Switching to "value": ${supportsHttpsTrafficOnly} should fix your issue.

But if I were you, I would go for the heredoc way, which is also the one used in the example of in the provider docs: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group_template_deployment

So use:

...
template_content = <<TEMPLATE
{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
...
TEMPLATE
}

instead of using a different .json file.

0
votes

It turns out this is actually an easy fix, if not an obvious one.

Apparently all parameters need to be defined as string and then use the ARM template conversion functions to convert to the correct type.

In the template.json, we would have this in the parameters section:

“supportsHttpsTrafficOnly”: {
  “type”: “string”
}

And then in the resources section, convert the string to a boolean using a template conversion:

"properties": {
  "supportsHttpsTrafficOnly": "[bool(parameters('supportsHttpsTrafficOnly'))]"
}

Then finally in main.tf, pass the value as a string:

  parameters_content = templatefile("parameters.json",
    {
      name = "vwtuvnpplzgelqey"
      supportsHttpsTrafficOnly = "true"
    }