Skip to content

terraform variables and locals

ghdrako edited this page Dec 30, 2023 · 13 revisions

Using variables

In Terraform 0.12, you use this syntax: var.ip_range. Old syntax: ${var.ip_range}

resource "google_project" "my_project" {
  name       = var.myproject_name
  project_id = var.project_id
  org_id     = var.org_id
}

Four ways of having Terraform variable values

  1. Defining variable values in the Terraform environment variables. Terraform will look for the values in the environment variable, starting with TF_VAR_, followed by the name of the declared variable

$ export TF_VAR_rgname=example-rg

  1. Store variable values in either a default supported file named terraform.tfvars or terraform.tfvars.json or in a file name ending with .auto.tfvars or .auto.tfvars.json.
terraform.tfvars:
rgname                  = "Terraform-rg"
rglocation              = "West Europe"
idle_timeout_in_minutes = 10
tags = {
  environment = "Preprod"
  Owner       = "Azure-Terraform"
}
allocation_method = "Dynamic"
public_ip_name    = "azure-example-pip"
variables.tf:
# variables for Resource Group
variable "ami" {
  description = "Name of the AMI"
  type        = string
}
variable "instance_type" {
  description = "Name of the instance type"
  type        = string
}

variable "var1" {}

terraform.tfvars:
ami           = "ami-a1b2c5d6" 
instance_type = "t1.micro"

To define input variable values in any other file you will be required to explicitly mention the filename:

terraform apply -var-file="testing.tfvars"
  1. Having Terraform variable values is during runtime. If you defined the variable in main.tf or variables.tf and its input values are missing, then it will prompt you to provide respective variable values during the runtime itself
$ terraform plan

var.rglocation
  Resource Group location like West Europe etc.
  Enter a value:
terraform plan -var "nb_webapp=5"   # assign variable value overreade that defined in terraform files  

  1. define a variable value directly as a default value while declaring the variables
variable "rgname" {
  description = "(Required)Name of the Resource Group"
  type        = string
  default     = "example-rg"
}

Precedende sequence: Environment variable values | values during runtime | terraform.tfvars | default values

Validation rules

variable "location" {
  description ="The name of the Azure location"
  default ="West Europe"
  validation { # TF 0.13
    condition = can(index(["westeurope","westus"], var.location) >= 0)
    error_message = "The location must be westeurope or westus."
  }
}

Collection Types

A collection type allows multiple values of one other type to be grouped together as a single value. The type of value within a collection is called its element type.

  • Lists Lists in Terraform allow you to define ordered collections of values. list(...): a sequence of values identified by consecutive whole numbers starting with zero. Every element of the list must be the same type.
Defining a List
variable "datastore_clusters" {
  description = "Names of VMware datastore clusters"
  type = list(string)
}
Assigning Values to the List
datastore_clusters = ["cluster1", "cluster2", "cluster3"]
Accessing List Values
resource "vsphere_virtual_machine" "example_vm" {
  name = "web-server"
  datastore_cluster = var.datastore_clusters[1]
  # ... other configuration options
}
["a", "b", "c"]

["a", 1, "b"] # convert to ["a", "1", "b"]

["a", [], "b"] # wrong [] can not convert to string

  • Maps
Defining a Map
variable "vm_config" {
  description = "Configuration details of VMware virtual
  machines"
  type = map
}
Assigning Values to the Map
vm_config = {
  "web-server" = {
    cpu_count = 2
    memory_size = 4096
    disk_size = 20
  }
  "database-server" = {
    cpu_count = 4
    memory_size = 8192
    disk_size = 100
  }
}
Accessing Map Values
resource "vsphere_virtual_machine" "example_vm" {
  name = "web-server"
  cpu_number = var.vm_config["web-server"]["cpu_count"]
  memory = var.vm_config["web-server"]["memory_size"]
  disk_size = var.vm_config["web-server"]["disk_size"]
  # ... other configuration options
}

##### Dynamically Populating Maps
Maps can be dynamically populated using interpolation and other
Terraform features. For instance, you can use a loop to iterate over a list
and generate a map with dynamic values based on specific criteria or
conditions.
Maps can be made with braces ({}) and colons (:) or equals signs (=): 

{ "foo": "bar", "bar": "baz" }

 OR 

{ foo = "bar", bar = "baz" }

Quotes may be omitted on keys, unless the key starts with a number, in which case quotes are required. Commas are required between key/value pairs for single line maps.

variables.tf: variable "tags" { type = map(string) description = "Tags" default = {} }

terraform.tfvars: variable "app_settings" { type = map(string) description = "App settings of the App Service" default = {} }

main.tf: resource { ... tags = var.tags app_settings = var.app_settings }

It is not possible to put a variable inside map.

It's possible to merge maps; that is, to merge two maps, we can use the **merge function**, which is native to Terraform.

merge({a="b", c="d"}, {e="f", c="z"}) { "a" = "b" "c" = "z" "e" = "f" }

merge({a="b"}, {a=[1,2], c="z"}, {d=3}) { "a" = [ 1, 2, ] "c" = "z" "d" = 3 }

variable.tf: variable "custom_app_settings" { description = "Custom app settings" type = map(string) default = {} }

terraform.tfvars: custom_app_settings = { CUSTOM_KEY1 = "CUSTOM_VAL1" }

main.tf: locals { default_app_settings = { "DEFAULT_KEY1" = "DEFAULT_VAL1" } } resource ....{ ... app_settings = merge(local.default_app_settings,var.custom_app_settings) }


main.tf app_settings = {"KEY1" = "VAL1", "KEY2" = "VAL2"} # create map on the fly


* **Set**
set(...): a collection of unique values that do not have any secondary identifiers or ordering.

* List of maps

variable "clientnetworks" { type = list(map(string)) default = [] }

clientnetworks = [

Values must follow CIDR notation, so /32 or /27 or /24 or something

{ name = "Clientsubnet1" # Name will be the route name, no spaces value = "10.1.1.0/24" } , { name = "Clientsubnet2" value = "10.1.2.0/24" } ]

resource "azurerm_route_table" "test-routetable" { name = "testroutes" location = var.location resource_group_name = var.resourcegroupname disable_bgp_route_propagation = false

For each item in the list of this variable map, we create a route

dynamic "route" { for_each = var.clientnetworks content { name = route.value["name"] address_prefix = route.value["value"] next_hop_type = "VirtualAppliance" next_hop_in_ip_address = local.nva-ge3_ip # a local that populates the ip of my network virtual appliance } } }

clientnetworks = [

Values must follow CIDR notation, so /32 or /27 or /24 or something

{ name = "Clientsubnet1" # Name will be the route name, no spaces value = "10.1.1.0/24" } , { name = "Clientsubnet2" value = "10.1.2.0/24" } ]

Using a “splat” expression creating a list containing each “value” from each map in my variable list

[10.1.1.0/24,10.1.2.0/24]

resource "azurerm_network_security_rule" "any_clientnetwork_any_mgmtnsg" { ... var.clientnetworks[*].value }


Locals

resource "random_string" "password" {
  length      = 16
  special     = true
  min_upper   = 2
  min_lower   = 2
  min_numeric = 2
  min_special = 2
}

locals {
  vmpassword = random_string.password.result
}

locals is just a local variable, having a map data type that contains a key and a value. It is used within the code by referencing local.key. In our example, we are storing a value of "random_string" "password" in vmpassword. So, wherever we want to reference or use this local variable in the Terraform configuration code, we can define local.vmpassword and it will automatically take the content of it.

resource "azurerm_key_vault_secret" "key_vault_secret" {
  name         = var.keyvault_secret_name
  value        = local.vmpassword
  key_vault_id = azurerm_key_vault.key_vault.id
  tags         = var.custom_tags
}
locals {
  subnets = {
    for x in var.subnets :
    "${x.subnet_region}/${x.subnet_name}" => x
  }
}

Test

Clone this wiki locally