Terraform Tutorial - variables, user input, and terraform fmt
In our tf file, we use "ami" and "instance_type". But now we want to parameterize those variables so that our tf can adapt to any changes in variables.
provider "aws" { region = "us-east-1" } variable "ami" { default = "ami-04169656fea786776" } variable "instance_type" { default = "t2.nano" } resource "aws_key_pair" "terraform-demo" { key_name = "terraform-demo" public_key = "${file("terraform-demo.pub")}" } resource "aws_instance" "my-instance" { ami = "${var.ami}" instance_type = "${var.instance_type}" key_name = "${aws_key_pair.terraform-demo.key_name}" user_data = "${file("install_apache.sh")}" tags = { Name = "Terraform" Batch = "5AM" } }
As project grows, we'll have more variables, and we may want to put the variables in a separate file (vars.tf):
variable "ami" { default = "ami-04169656fea786776" } variable "instance_type" { default = "t2.nano" }
And our tf file now looks like this:
provider "aws" { region = "us-east-1" } resource "aws_key_pair" "terraform-demo" { key_name = "terraform-demo" public_key = "${file("terraform-demo.pub")}" } resource "aws_instance" "my-instance" { ami = "${var.ami}" instance_type = "${var.instance_type}" key_name = "${aws_key_pair.terraform-demo.key_name}" user_data = "${file("install_apache.sh")}" tags = { Name = "Terraform" Batch = "5AM" } }
Since we've just replaced the variables, if we run terraform plan
, we should see there are no changes:
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. aws_key_pair.terraform-demo: Refreshing state... (ID: terraform-demo) aws_instance.my-instance: Refreshing state... (ID: i-0256275af92b28d7b) ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
Note that when we run terraform apply
, Terraform looks for all *.tf files in the directory. In our case, they are ec2-instance.tf and vars.tf.
We've replaced our sensitive strings with variables, but we still are hard-coding AMIs. Unfortunately, AMIs are specific to the region that is in use.
Maps are a way to create variables that are lookup tables. Let's extract our AMIs into a map and add support for the us-west-1 region as well. Here is our updated tf file:
provider "aws" { region = "${var.aws_region}" } resource "aws_key_pair" "terraform-demo" { key_name = "terraform-demo" public_key = "${file("terraform-demo.pub")}" } resource "aws_instance" "my-instance" { ami = "${lookup(var.ami,var.aws_region)}" instance_type = "${var.instance_type}" key_name = "${aws_key_pair.terraform-demo.key_name}" user_data = "${file("install_apache.sh")}" tags = { Name = "Terraform" Batch = "5AM" } }
Out vars.tf:
variable "ami" { type = "map" default = { "us-east-1" = "ami-04169656fea786776" "us-west-1" = "ami-006fce2a9625b177f" } } variable "instance_type" { default = "t2.nano" } variable "aws_region" { default = "us-east-1" }
To see what ami the lookup() returns:
$ terraform console > "${lookup(var.ami,var.aws_region)}" ami-04169656fea786776 >
As expected, it returns the ami for "us-east-1" region!
If we do not set a value in the variables, Terraform asks for an input from the user. For example, if the region is not defined as shown in the following tf file:
... variable "aws_region" { #default = "us-east-1" }
When we run terraform apply
:
$ terraform apply var.aws_region Enter a value:
$ terraform fmt ec2-instance.tf provider.tf vars.tf
The terraform fmt
makes our tf files looking good, well aligned. Our vars.tf:
variable "ami" { type = "map" default = { "us-east-1" = "ami-04169656fea786776" "us-west-1" = "ami-006fce2a9625b177f" } } variable "instance_type" { default = "t2.nano" } variable "aws_region" { default = "us-east-1" }
ec2-instance.tf:
resource "aws_key_pair" "terraform-demo" { key_name = "terraform-demo" public_key = "${file("terraform-demo.pub")}" } resource "aws_instance" "my-instance" { count = 1 ami = "${lookup(var.ami,var.aws_region)}" instance_type = "${var.instance_type}" key_name = "${aws_key_pair.terraform-demo.key_name}" user_data = "${file("install_apache.sh")}" tags = { Name = "Terraform" Batch = "5AM" } }
provider.tf:
provider "aws" { region = "${var.aws_region}" }
Terraform
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization