terraform variables and locals
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
}
- 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
- 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"
- 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
- 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
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."
}
}
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.
variable "datastore_clusters" {
description = "Names of VMware datastore clusters"
type = list(string)
}
datastore_clusters = ["cluster1", "cluster2", "cluster3"]
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
variable "vm_config" {
description = "Configuration details of VMware virtual
machines"
type = 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
}
}
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 = [
{ 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
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 = [
{ 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
resource "azurerm_network_security_rule" "any_clientnetwork_any_mgmtnsg" { ... var.clientnetworks[*].value }
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