Terraform: About Variables
As a supplemental article to Terraforming the Oracle Cloud Infrastructure – Part 1, I want to say a few words about Terraform variables.
In order to avoid hardcoding resources, Terraform provides variables. In this post, I’ll explain some of the basics around variables. At the time of this writing, the current version of Terraform is 0.11.8. The syntax in the next major version will change.
Declaration
Variables need to be formally declared in Terraform. This can be done in either the main Terraform file or in a separate variables file. Typically, when your Terraform scripts become large, it is recommended to keep the variable declarations in a separate file named variables.tf.
There are three types of variables: Strings, Lists, and Maps. The string type is the default.
As you begin using and playing with variables, you may want to see what values they hold. To do this, you can use output variables. They will print a variable’s value to the screen. Variables are referenced rather verbosely inside a quoted string: “${var.myVariable}”
All these examples can be tested by pasting them into a main.tf file, and then performing a terraform init (once), and a terraform apply.
Strings
variable "myStringVar" {} # defines a string variale with no default value
Optional Attributes:
variable "myStringVar" { type = "string" description = "This is a variable" default = "Hello" } output "myStringVar-value" { value = "${var.myStringVar}" } # returns "Hello"
Lists
Lists are simple arrays enclosed in square brackets. The element values can be numbers (without quotes) or quoted strings. When list are referenced, their (zero-based) index is specified in square brackets.
variable "myNumberList" { type = "list" description = "A list of integers" default = [1,2,3] } output "myNumberList-value" { value = "${var.myNumberList[1]}" } # returns 2 variable "myStringList" { type = "list" description = "A list of strings" default = ["apple","banana","cherry"] } output "myStringList-value-1" { value = "${var.myStringList[1]}" } # returns "banana"
There are a number of functions available around variables, as specified in the Terraform Interpolation Syntax. One function of note is the element() function, which returns a list element based on the given index. However, if the index exceeds the number of elements in the list, it wraps around and returns elements from the front of the list. In the example above, myStringList contains three elements (indexes 0,1,2). If trying to return element 3, you would get an out of range error. However, when using element(), you would simply get element 0 back:
output "myStringList-value-2" { value = "${element(var.myStringList,3)}" } # returns "apple"
This is useful when provisioning resources across a limited list of subnets for example. If you provision six and only have three subnets, this technique will allow you to spread the servers across these subnets in a round-robin fashion
Maps
Maps are key-value pairs defined inside curly brackets and can be referenced by their keys. They keys are quoted strings inside square brackets.
Note that Terraform is smart enough to recognize enclosed quotes!
variable "myMap" { type = "map" description = "A server" default = { name = "WebServer" ip = "1.2.3.4" os = "Linux" } } output "myMap-value" { value = "${var.myMap["ip"]}" } # returns "1.2.3.4"
Similar to the element() function above, the lookup() function works with maps. This function allows you to specify a default value, in case a non-existent key is given:
output "myMap-value-2" { value = "${lookup(var.myMap,"i-do-not-exist","something")}" } # returns "something"
You can easily test this code by creating a main.tf file, then executing terraform init, and a terraform apply.
Setting Variables
While a default value may be of good use, you more than likely want to set values more dynamically. Other ways of setting variable values include environment variables, tfvars file, and command line.
Environment Variables
Any environment variable preceded with TF_VAR_ and followed by the declared variable name will set the given variable. For example, TF_VAR_myStringVar will get picked up by terraform and set its value, overriding the default value from the declaration.
This methodology is especially useful for credentials. You can set variables such as user ID’s and passwords in the environment, and have Terraform pick them up.
In the command prompt:
$ export TF_VAR_password="secret"
In the main.tf file:
variable "password" {} output "password-value" { value = "${var.password}" } # returns "secret"
tfvars file
A special file named terraform.tfvars can be created to set variable values. These values override the defaults.
myStringVar = "foo" password = "bar"
Terraform will automatically pick up the terraform. tfvars file and apply the values. You can also specify other file names and specify them in the command line.
$ terraform apply -var-file=my-variables.tfvars
Command line
You can specify variable values in the command line, and they would override defaults, environment variables, and tfvars specified ones:
$ terraform apply -var password=superSecret -var myStringVar=World
Further details can be found in Hashicorp’s documentation.