Part 4 — HumanGov Application — Terraform-2: Working with Input Variables and Output Values in Terraform

Cansu Tekin
9 min readMay 22, 2023

--

HumanGov is a software-as-a-service (SaaS) cloud company that will create a Human Resources Management SaaS application for the Department of Education across all 50 states in the US and host the application files and databases in the cloud. Whenever a new employee is hired, a new registry will be created for this employee inside this application.

In this following project series, we are going to transition the architecture from a traditional virtual machine architecture to a modern container-based architecture using Docker containers and Kubernetes running on AWS. In addition, we will also be responsible for automating the complete software delivery process using Pipelines CI/CD using AWS services such as AWS CodeCommit, AWS CodePipeline, AWS CodeBuild, and AWS CodeDeploy. Finally, we will learn how to monitor and observe the cloud environment in real-time using tools such as Prometheus, Grafana, and automate one-off cloud tasks using Python and the AWS SDK.

In this section, we are going to introduce working with input variables and output values in Terraform and practice Terraform with cloud provider AWS before using it in the implementation of the HumanGov application. This is the 4rd part of a project series. Check Part 1, Part 2 and Part 3 to follow up.

Input Variables

Terraform variables allow you to write flexible configurations for easy reuse. Using variables make code more dynamic. You can call that variable instead of writing codes again.

Example of Input Variable:

variable "<name>" {
default = "<value>"
type = string
description = "Explain the use of the varibale"
}

name: It can be any name except Terraform reserved names.

default: It will be the variable's default value if nothing is assigned to it later.

type: It can be string, number, bool, etc.

description: It is an explanation for the usage of the variable.

Let's create a web server in AWS using Terraform.

resource "aws_instance" "vm-webserver"{
ami = "ami-12345678910"
instance_type = "t2.micro"
}

We have 2 arguments to configure this instance: ami(Amazon Machine Image) and instance_type.

When we are creating only one instance this configuration is OK. However, it is cumbersome to create lots of different instances with the exact same configuration like same AMI and instance type. We need to repeat the source block for each instance. Instead, to make code more dynamic and reusable we can use variables. We can assign the variables to an argument instead of assigning their value directly.

Let's create a Terraform variable file with variables: variable.tf

variable "ami" {
default = "ami-12345678910"
}

variable "instance_type" {
default = "t2.micro"
}

Replace static variables inside the resource block with the dynamic variables we created above:

resource "aws_instance" "vm-webserver"{
ami = var.ami
instance_type = var.instance_type
}

Now it will be easier to create more resources and make changes in the configuration of these resources by updating variables inside variables.tf file.

How to set a value to the variables

  • After declaring the variable inside the block as we did above we need to set a value to the variable. If we do not specify a value it will be assigned to the default value we determined while declaring.
  • In addition to defining the variable's value inside the block, we can define an environment variable, TF_VAR, to the variable inside the configuration code block. Whenever the Terraform configuration code runs, Terraform will look for the environment variable that starts with TF_VAR and associate this value with the code.
  • Instead of setting values as an environment variable, we can set values inside files: terraform.tfvars, terraform.tfvars.json, *.auto.tfvars, or *.auto.tfvars.json
  • We can also specify the values of variables using the command line by passing values using -var and -var-file flags.

Variable Definition Precedence: Terraform loads variables in the following order;

-var and -var-file flags > *.auto.tfvars, or *.auto.tfvars.json > terraform.tfvars.json file > terraform.tfvars file > environment variable

The earlier sources take precedence over later ones.

Output Values

The output value is like return values in a programming language. It returns and stores the results of the resources created, especially for displaying messages regarding resource provisioning, using the output value in another block, feeding other IaC tools variables, accessing remote state “data source” and handling with modules.

Consider creating a new instance. We want to get the public IP address of the instance after Terraform provisions the EC2 instance to test if the webserver inside this instance is up and running.

resource "aws_instance" "webserver"{
ami = "ami-12345678910"
instance_type = "t2.micro"
}

We can create a Terraform output file, outputs.tf, and call public IP inside an output block.

output "instance_public_ip" {
value = aws_instance.webserver.public_ip
}

It displays the public IP address of the EC2 instance once previsioning over.

Hands-on: Input Variables

We are going to create 3 different S3 buckets on AWS using Terraform.

Step 1: Go to the Terraform AWS documentation

Anytime you want to create resources in AWS go and check Terraform documentation. Search for the S3 bucket under Resources. Find the example that shows how to create a S3 bucket with a tag.

Step 2: Open the humangov Cloud9 environment

Open the humangov-terraform folder we created in the previous part. Open the terraform.tf and resources.tf files. We are going to change this file based on the purpose of this section.

Step 3: Change terraform.tf and resources.tf files

Delete the azure provider part inside terraform.tf and everything inside resources.tf file because we are going to create new resources.

We are going to create three S3 buckets whose names need to be unique across the whole AWS. We are going to specify with tags with the name and ID of the project to identify the resources which are related to the HumanGov application. Here we are going to use repetitive codes for Terraform but as we continue the project we will learn the best practice to do the same thing.

Once we set up files we can run Terraform to create resources inside AWS.

terraform init
# -out option saves Terraform plan to a file.
# Whenever we need to apply this configuration Terraform does not need to
# go through exacution plan to create resources again
# It is going to be way faste rto create resources using this file
terraform plan -out=tcb-plan
terraform apply tcb-plan

Check S3 Buckets inside AWS.

Step 4: Make the Application and ProjectId values dynamic using Variables

  • 1) Using default value: The Application and ProjectId inside tags have the same information and are repetitive. We can use variables here. First, create a variables.tf file inside the same folder with terraform.tf and resources.tf. Then, create variables to hold values for the Application and ProjectId.
variable "application" {
default = "HumanGov"
}

variable "projectid" {
default = "HGV20392"
}

Update resources.tf file passing variables.

When we run terraform apply again, no changes will be made because we did not change the configuration.

Let's test variables without a default value. Remove the default line from the variable application and run terraform apply again.

So we do not have any default value, it is going to ask to enter a value for the variables. Once we assign values to the variables, Terraform shows what changes are made.

  • 2) Using TF_VAR environment variable: Set the TF_VAR environment variable before running the terraform plan command. Whatever name comes after TF_VAR_……. is going to be understood as a variable name and its value will be passed to the related variables inside variables.tf file by Terraform.

As you can see, it is only asking a value for the projectid variable for now because we already assigned a value to the application using environment variable TF_VAR_application.

  • 3) Using -var flag/option:
terraform plan -var="application=HumanGovSaaS" -out=tcb-plan
terraform plan -var="application=HumanGovCloud" -var="projectid=HGV000001" -out="tcb-plan"
  • 4) Using file .tfvars: First, create a new file terraform.tfvars in the same directory. Fill the file with the variable and their values.
application = "HumanGovAWS"
projectid = "HGVAWS0001"
  • 5) Using -var-file flag/option: Update the values inside the terraform.tfvars file.
application = "HumanGovCloudTesting"
projectid = "HGVTESTING"
# run on the command line
terraform plan -var-file="terraform.tfvars" -out=tcb-plan

Lets run terraform apply to save changes in AWS.

terraform apply tcb-plan

Lets check changes inside AWS. Go inside one of the three buckets and check Tags section under Properties tab.

Well done!

You can destroy resources we created for this section.

terraform destroy

Hands-on: Output Values

Step 1: Generate a dynamic bucket name

Lets create a resource random_string to generate a dynamic unique bucket name with the length 5. Update resources.tf file. Remove two S3 buckets block and leave only one S3 bucket resources. Add resource random_string.

resource "random_string" "bucket_name_suffix" {
length = 5
special = false
upper = false
}


resource "aws_s3_bucket" "HG1_suffix" {
bucket = "humangov-tf-test-bucket1-${random_string.bucket_name_suffix.result}"

tags = {
Application = var.application
ProjectId = var.projectid
}
}

We are doing an interpolation here. We are joining the name of the bucket (string: humangov-tf-test-bucket1) with the result of the random_string resource.

Run Terraform commands to configure changes.

terraform plan
terraform apply

It is created [id=vkjhr]. Go and check S3 buckets in AWS. You should see this as a suffix in the bucket name.

This is going to be really useful when we need to create many resources.

Step 2: Display bucket name on the terminal screen

Create the outputs.tf file under same directory with the following input:

output "bucket_name" {
# Concatenate a string with the bucket name using interpolation
value = "The bucket name is: ${aws_s3_bucket.HG1_suffix.bucket}"
}
terraform plan
terrform apply
# It is going to show all resources created and detail of these resources.
terraform show

The bucket name is displayed as we described.

The output result stored in the terraform output as well. Run terraform output command to see.

Well done!

Do not forget to destroy resources after completed project with terraform destroy command.

terraform destroy

CONGRULATIOTIONS!!

Follow me on LinkedIn:

https://www.linkedin.com/in/cansu-tekin-a5617557/

--

--

Cansu Tekin

AWS Community Builder | Full Stack Java Developer | DevOps | AWS | Microsoft Azure | Google Cloud | Docker | Kubernetes | Ansible | Terraform