Terraform Meta-Arguments
Count
The 'count' attribute can be added to any resource and the value of this attribute determines the number of resource instances to be deployed. The 'count' attribute provides an 'index' property which can be use with variable interpolation to assign unique names to each resource created. The index begins at 0.
resource "azurerm_virtual_machine" "user_vm" {
count = 3
name = "${var.vm_name}-0${count.index}"
...
...
}
output vm_ids {
value = azurerm_virtual_machine.user_vm[*].id
}
Terraform stores the list of resources created as an array in the terraform state and the splatting operator (an asterisk) can be used to refer to this array as a whole.
The 'count' meta-element can also be used with a list variable, allowing more tailored names to be given to the resources created:
variable "vm_names" {
type = list(string)
default = ["vm_harry", "vm_larry", "vm_barry"]
}
resource "azurerm_virtual_machine" "user_vm" {
count = length(var.vm_names)
name = "${var.vm_names[count.index]}"
...
...
}
output vm_ids {
value = azurerm_virtual_machine.user_vm[*].id
}
For Each
The 'for_each' meta element can be used to iterate a map or set to provision multiple resources from a single resource block. 'for_each' provides a 'each.key' and an 'each.value' attribute to further tailor the properties of the resources created:
variable "user_machines" = {
type = map(string)
default = {
"vm_harry" : "rg-env-dev",
"vm_larry" : "rg-env-live",
"vm_barry" : "rg-env-test"
}
}
resource azurerm_virtual_machine "user_vm" {
for_each = var.user_machines
name = each.key
resource_group_name = each.value
...
...
}
The 'for_each' meta-element can also be used to iterate at the property level: instead of using for_each to define multiple instance of the same resource type, for_each can be used to define multiple instances of a property on a singe resource:
resource "azurerm_app_service" "app_service" {
name = var.app_service_name
location = azurerm_resource_group.resource_group.location
resource_group_name = azurerm_resource_group.resource_group.name
app_service_plan_id = azurerm_app_service_plan.app_service_plan.id
dynamic "connection_string" {
for_each = var.connection_strings
content {
name = connection_string.name
type = connection_string.type
value = connection_string.value
}
}
https_only = true
}
Property iterations use the keyword 'dynamic' along with the name of the property being iterated
Depends On
Terraform can identify resource dependancies automatically, and will create resources with no dependancies in parallel, whilst resources with dependancies are created sequentially. But where a resource depends on another resources behaviour rather than it's data, we have to explicitly declare the dependancy. A data dependancy is clear to see: where the value for an attribute is declared by reference to the value of an attribute of another resource. For example:
resource azurerm_virtual_machine "my_database_server" {
...
resource_group_name = azurerm_resource_group.resource_group.name
...
}
Implicit dependancies must be declared as a list of references to other
resources, using a depends_on
block:
resource_azurerm_virtual_machine "my_app_server" {
...
depends_on = [
azurerm_virtual_machine.db_server.id,
azurerm_virtual_machine.controller.id
]
}
A depends_on
block can be included in any resource or module block.
Terraform creates a dependancy graph from the dependancy information to ensure that resources are created in the correct order.
Provider
Where multiple providers are being used in Terraform scripts, you can add a provider attribute to a resource to tell it to use the non-default provider
Lifecycle
The 'lifecycle' meta-argument can be used to change terraform's default behaviour when creating, updating or destroying resources
Template File
The template_file()
function allows you to interpolate values into a script
file at resource creation time. A simple template file might contain
references to variables such as ${group}
and ${user}
. The template_file()
function allows you to specify the values for the variables:
user_data = template_file("user_data.tftpl", { group = var.user_group, user = var.user_name })
The file()
function does not interpolate values into the files contents, but allows you
to read a file into your configuration without modification:
resource "aws_key_pair" "ssh_key" {
key_name = "ssh_key"
public_key = file("ssh_key.pub")
}