Hashicorp Terraform - Providers, Variables & Attributes
Providers
Terraform offers a large quantity of providers that you can use in your configuration file - e.g. the Random Provider that you can use to generate random:
- random_id
- random_integer
- random_password
- random_pet
- random_shuffle
- random_string
- random_uuid
Resource Attributes
Let's add this to our configuration:
sudo nano /etc/terraform.d/main.tf
resource "random_uuid" "uuid" {
}
resource "local_file" "resource_name" {
filename = "/opt/uuid"
content = "${random_uuid.uuid.result}-rg"
directory_permission = "0777"
file_permission = "0700"
}
Here I am using the result of the random_uuid
as an attribute in the local_file
resource:
sudo terraform init
sudo terraform plan
sudo terraform apply
And check the result - the file now contains the generated UUID:
sudo cat /opt/uuid
833732a2-438a-76dd-828f-a7fe2a64f5bb-rg
Dependency
The example above works because the random_uuid
provider is run before the local_file
provider. But it is also possible to declare an explicit dependency:
resource "local_file" "resource_name" {
filename = "/opt/uuid"
content = "${random_uuid.uuid.result}-rg"
directory_permission = "0777"
file_permission = "0700"
depends_on = [
random_uuid.uuid
]
}
resource "random_uuid" "uuid" {
}
Input Variables
To make configuration files re-useable we can variables instead of hardcoding values:
resource "random_uuid" "uuid" {
}
resource "local_file" "resource_name" {
filename = var.filename
content = "${random_uuid.uuid.result}-rg"
directory_permission = var.directory_permission
file_permission = var.file_permission
}
If no variables are provided the Terraform CLI will ask you for values when you try to run this configuration file. But they can also be provided with CLI flags:
terraform apply -var "filename=/opt/uuid" -var "directory_permission=0777" -var "file_permission=0700"
Or use environment variables:
export TF_VAR_filename="/opt/uuid"
export TF_VAR_directory_permission="0777"
export TF_VAR_file_permission="0700"
Or create variable definition file terraform.auto.tfvars
filename = "/opt/uuid"
directory_permission = "0777"
file_permission = "0700"
Default Variables
You can also define default variable in a file variables.tf
next to our main configuration:
variable "filename" {
default = "/opt/uuid"
type = string
description = "ID file location"
}
variable "directory_permission" {
default = "0777"
}
variable "file_permission" {
default = "0700"
}
sudo terraform plan
sudo terraform apply
sudo cat /opt/uuid
4c148730-9cd1-bc23-04eb-ae3f5e5000d7-rg
Precedence
These defaults will be overridden by the following in this order:
- Default
variables.tf
- Environment Variables
- terraform.tfvars
- *.auto.tfvars
- CLI flags
Variable Types
types
can be any, string, numbers, bool, list, set, map, object, tuple:
List
variable "prefix" {
default = ["Mr.", "Mrs."]
type = list(string)
}
resource "random_pet" "pet" {
prefix = var.prefix[0]
}
Map
variable "file-content" {
type = map(string)
default = {
"key1" = "value1"
"key2" = "value2"
}
}
variable "file-content" {
type = map(number)
default = {
"key1" = "1"
"key2" = "2"
}
}
resource local_file "test" {
filename = "/opt/test"
content = var.file-content["key2"]
}
Set
A set is a list without duplicated elements:
variable "prefix" {
default = ["Mr.", "Mrs.", "Dr."]
type = set(string)
}
variable "prefix" {
default = ["123", "456", "789]
type = set(number)
}
Object
variable "product" {
type = object({
model = string
color = string
article = number
compatibility = set(string)
sale = bool
})
default = {
model = "IN-9408 WQHD"
color = "purple"
article = 479831
compatibility = ["Windows", "macOS", "LINUX"]
sale = false
}
}
Tuples
Just like lists but with mixed types:
variable "not_a_list" {
default = ["Artemis", true, 666]
type = tuple([string, bool, number])
}
Output Variables
Output values are like the return values of a Terraform module, and have several uses:
- A child module can use outputs to expose a subset of its resource attributes to a parent module.
- A root module can use outputs to print certain values in the CLI output after running terraform apply.
- When using remote state, root module outputs can be accessed by other configurations via a terraform_remote_state data source.
Resource instances managed by Terraform each export attributes whose values can be used elsewhere in configuration. Output values are a way to expose some of that information to the user of your module.
resource "random_uuid" "uuid" {
}
resource "local_file" "resource_name" {
filename = var.filename
content = "${random_uuid.uuid.result}-rg"
directory_permission = var.directory_permission
file_permission = var.file_permission
}
output uuid {
value = random_uuid.uuid.result
description = "Output the randomly generated UUID"
}
The UUID will now be output the the terminal when you run the job:
sudo terraform apply
random_uuid.uuid: Refreshing state... [id=4c148730-9cd1-bc23-04eb-ae3f5e5000d7]
local_file.resource_name: Refreshing state... [id=59c2ee47c7e515c04607c0cfa3d0028dd32e2f13]
Changes to Outputs:
+ uuid = "4c148730-9cd1-bc23-04eb-ae3f5e5000d7"
You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
uuid = "4c148730-9cd1-bc23-04eb-ae3f5e5000d7"
And it can also be directly queried to make it available for other applications:
terraform output
uuid = "4c148730-9cd1-bc23-04eb-ae3f5e5000d7"
terraform output uuid
"4c148730-9cd1-bc23-04eb-ae3f5e5000d7"
State
The state of the result
is stored inside a file terraform.tfstate
next to the main configuration file and can also be read from there:
{
"mode": "managed",
"type": "random_uuid",
"name": "uuid",
"provider": "provider[\"registry.terraform.io/hashicorp/random\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"id": "4c148730-9cd1-bc23-04eb-ae3f5e5000d7",
"keepers": null,
"result": "4c148730-9cd1-bc23-04eb-ae3f5e5000d7"
},
"sensitive_attributes": [],
"private": "bnVsbA=="
}
]
}
To update the Terraform State without applying changes to your infrastructure run:
terraform refresh
To apply changes to your infrastructure from the existing state (instead of updating it):
terraform plan --refresh=false