Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform - Passing type Object as a parameter to Azure Template Deployment

I am tying to to provision Azure AD Domain Service using Terraform by giving Terraform the Azure ARM template, this is because Terrafrom does not support provisioning Azure AD Domain Service natively.

I have exported the ARM Template and it's parameters, one of the parameters is called "notificationSettings" which is a type Object and looks like below :

    "notificationSettings": {
        "value": {
            "notifyGlobalAdmins": "Enabled",
            "notifyDcAdmins": "Enabled",
            "additionalRecipients": []
        }
    }

Other parameters are all strings and I can pass them without any issue, for example:

"apiVersion" = "2017-06-01"

I have tried passing this object to parameters like below :

"notificationSettings" = [{
                "notifyGlobalAdmins" = "Enabled"
            "notifyDcAdmins" ="Enabled"
            "additionalRecipients" = []
}]

However, when I execute terrafrom apply, terrafrom complains and say:

Inappropriate value for attribute "parameters": element "notificationSettings": string required.

How do I pass parameters type of Object to template body?

I have also tried giving the entire ARM json parameter as a file to terrafrom by using parameters_body option like below :

parameters_body = "${file("${path.module}/temp/params.json")}"

however, I am getting the followig error when executing the terrafrom script:

The request content was invalid and could not be deserialized: 'Error converting value "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#" to type 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Data.Definitions.DeploymentParameterDefinition'. Path 'properties.parameters.$schema', line 1, position 2952.'.

Below is the params.json file:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "apiVersion": {
            "value": "2017-06-01"
        },
        "sku": {
            "value": "Standard"
        "location": {
            "value": "westus"
        },
        "notificationSettings": {
            "value": {
                "notifyGlobalAdmins": "Enabled",
                "notifyDcAdmins": "Enabled",
                "additionalRecipients": []
            }
        },
        "subnetName": {
            "value": "xxxx"
        },
        "vnetName": {
            "value": "xxxx"
        },
        "vnetAddressPrefixes": {
            "value": [
                "10.0.1.0/24"
            ]
        },
        "subnetAddressPrefix": {
            "value": "10.0.1.0/24"
        },
        "nsgName": {
            "value": "xxxxx"
        }
    }
}
like image 248
Benjamin Avatar asked Jan 26 '20 16:01

Benjamin


1 Answers

There is a way to pass arbitrary data structures from Terraform to ARM.

There are two ways to pass data to the ARM template within the azure_template_deployment provider

  • use the parameters block, which is limited to string parameters only
  • use the parameters_body block, which is pretty much arbitrary JSON.

I find the easiest way to use the parameters block is to create a local variable with the structure I require, then call jsonencode on it. I also like to keep the ARM template in a separate file and pull it in via a file() call, reducing the complexity of the terraform.

locals {
  location = "string"
  members = [
    "array",
    "of",
    "members"
  ]
  enabled = true
  tags = {
    "key" = "value",
    "simple" = "store"
  }

  # this is the format required by ARM templates
  parameters_body = {
    location = {
      value = "${local.location}"
    },
    properties = {
      value = {
        users = {
          members = "${local.members}"
        }
        boolparameter = "${local.enabled}"
      }
    }
    tags = {
      value = "${module.global.tags}"
    }
  }
}

resource "azurerm_template_deployment" "sample" {
  name = "sample"
  resource_group_name = "rg"
  deployment_mode = "Incremental"
  template_body = "${file("${path.module}/arm/sample_arm.json")}"
  parameter_body = "${jsonencode(local.parameters_body)}"
}

The only caveat I've found is that the bool parameters pass as a string, so declare them as a string in the ARM parameters section, then use a ARM function to convert to bool

"parameters: {
  "boolParameter": {
     "type": "string"
  }
},
"variables": {
  "boolVariable": "[bool(parameters('boolParameter'))]"
},
"resources": [
  ...
  "boolArm": "[variables('boolVariable')]",
  ...
]
like image 179
Leif Avatar answered Oct 09 '22 12:10

Leif