Skip to main content

Using the Terraform CLI

·1253 words·6 mins
Jack Warner
Author
Jack Warner
A little blog by me

Terraform Commands

terraform validate

resource "local_file" "pet" {
filename = "/root/pets.txt"
content = "We love pets!"
file_permissions = "0700"
}

$ terraform validate
Error: Unsupported argument
on main.tf line 4, in resource "local_file" "pet":
4: file_permissions = "0777"
An argument named "file_permissions" is not expected
here. Did you mean "file_permission"?

terraform fmt

resource "local_file" "pet" {
filename = "/root/pets.txt"
content = "We love pets!"
}
file_permission = "0700"
terraform fmt
main.tf

terraform show

$ terraform show
# local_file.pet:
resource "local_file" "pet" {
content = "We love pets!"
directory_permission = "0777"
file_permission = "0777"
filename = "/root/pets.txt"
id =
"cba595b7d9f94ba1107a46f3f731912d95fb3d2c"
}
terraform show -json
{"format_version":"0.1","terraform_version":"0.13.0
","values":{"root_module":{"resources":[{"address":
"local_file.pet","mode":"managed","type":"local_fil
e","name":"pet","provider_name":"registry.terraform
.io/hashicorp/local","schema_version":0,"values":{"
content":"We love
pets!","content_base64":null,"directory_permission"
:"0777","file_permission":"0777","filename":"/root/
pets.txt","id":"cba595b7d9f94ba1107a46f3f731912d95f
b3d2c","sensitive_content":null}}]}}}

terraform providers


resource "aws_instance" "db" {
ami = var.ami
instance_type = var.instance_type
}
```bash
$ terraform providers

roviders required by configuration:
.
└── provider[registry.terraform.io/hashicorp/aws]
Providers required by state:
provider[registry.terraform.io/hashicorp/aws]

terraform output

resource "local_file" "pet" {
filename = "/root/pets.txt"
content = "We love pets!"
file_permission = "0777"
}
resource "random_pet" "cat" {
length = "2"
separator = "-"
}
output content {
value = local_file.pet.content
sensitive = false
description = "Print the content of the file"
}
output pet-name {
value = random_pet.cat.id
sensitive = false
description = "Print the name of the pet"
}
$ terraform output
content = We love pets!
pet-name = huge-owl

$ terraform output pet-name 
pet-name = huge-owl

terraform refresh

main.tf
resource "local_file" "pet" {
filename = "/root/pets.txt"
content = "We love pets!"
file_permission = "0777"
}
resource "random_pet" "cat" {
length = "2"
separator = "-"
$ 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.
random_pet.cat: Refreshing state... [id=huge-owl]
local_file.pet: Refreshing state...
[id=cba595b7d9f94ba1107a46f3f731912d95fb3d2c]
------------------------------------------------------
No changes. Infrastructure is up-to-date.

$ terrform apply -refresh-only 

random_pet.cat: Refreshing state... [id=huge-owl]
local_file.pet: Refreshing state...
[id=cba595b7d9f94ba1107a46f3f731912d95fb3d2c]

terraform graph

this command generates a visual representation of the resources and their dependencies in the Terraform configuration. It can be used to understand the relationships between resources and how they are connected.

managing terraform state

$ vi terraform.tfstate
$ terraform state show aws_s3_bucket.finance 
$ terraform state list 
aws_dynamodb_table.cars
aws_s3_bucket.finance-2020922

$ terraform state list aws_s3_bucket.cerberus-finance 

aws_s3_bucket.cerberus-finance
$ terraform state show aws_s3_bucket.cerberus-finance
resource "aws_s3_bucket" "terraform-state" {
acl = "private"
arn = "arn:aws:s3:::cerberus-finance"
bucket = "cerberus-finance"
bucket_domain_name = "cerberus-finance.s3.amazonaws.com"
bucket_regional_domain_name = "cerberus-finance.s3.us-west-1.amazonaws.com"
force_destroy = false
hosted_zone_id = "Z2F5ABCDE1ACD"
id = "cerberus-finance"
region = "us-west-1"
request_payer = "BucketOwner"
tags = {
"Description" = "Bucket to store Finance and Payroll Information"
}
versioning {
enabled = false
mfa_delete = false
}
}

terraform state mv SOURCE DESTINATION

$ terraform state mv aws_dynamodb_table.state-locking aws_dynamodb_table.state-locking-db
Move "aws_dynamodb_table.state-locking" to "aws_dynamodb_table.state-locking-db"
Successfully moved 1 object(s).
"state-locking-db"
aws_dynamodb_table.state-locking-db: Refreshing state... [id=state-locking]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
# terraform state mv [options] SOURCE DESTINATION
$ terraform apply
main.tf
resource "aws_dynamodb_table" "state-locking" {
name = "state-locking"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
terraform.tfstate
"resources": [
{
"mode": "managed",
"type": "aws_dynamodb_table",
"name": "state-locking",
"provider":
"provider[\"registry.terraform.io/hashicorp/aws\"
]",

terraform state pull SOURNCE DESTINATION

$ terraform state pull
Local
Remote State Backend
Terraform State
# terraform state pull [options] SOURCE DESTINATION
{
"version": 4,
"terraform_version": "0.13.0",
"serial": 0,
"lineage": "b6e2cf0e-ef8d-3c59-1e11-c6520dcd745c",
"resources": [
{
"mode": "managed",
"type": "aws_dynamodb_table",
"name": "state-locking-db",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
...
$ terraform state pull | jq '.resources[] | select(.name == "state-locking-
db")|.instances[].attributes.hash_key'
"LockID

terraform state rm ADDRESS

$ terraform state rm aws_s3_bucket.finance-2020922
Acquiring state lock. This may take a few moments...
Removed aws_s3_bucket.finance-2020922
Successfully removed 1 resource instance(s).
Releasing state lock. This may take a few moments...

terraform state push ./terraform.tfstate

$ terraform state push ./terraform.tfstate

$ terraform state push ./randomstate/terraform.tfstate
Failed to write state: cannot import state with lineage "1dc19ee8-2b7f-
d87a-4786-4be724b24988" over unrelated state with lineage "6d167ba6-5171-
a624-6bad-2e6bfec62c28

Lifcycle rules
#

For example when you try to do a new ami. Terraform will need ot destroy the ami first then create the new ami.

To make sure it is created first:

main.tf
resource "aws_instance" "cerberus" {
ami = "ami-06178cf087598769c"
instance_type = "m5.large
tags = {
Name = "Cerberus-Webserver"
}
lifecycle {
create_before_destroy = true
```bash 
$ terraform apply
aws_instance.cerberus: Refreshing state... [id=i-a6e22ec5303190252
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+/- create replacement and then destroy
Terraform will perform the following actions:
# aws_instance.cerberus must be replaced
+/- resource "aws_instance" "cerberus" {
~ ami = "ami-
06178cf087598769c" -> "ami-2158cf087598787a" # forces replacement
Plan: 1 to add, 0 to change, 1 to destroy.
...
aws_instance.cerberus: Creating...
aws_instance.cerberus: Still creating... [10s elapsed]
aws_instance.cerberus: Creation complete after 10s [id=i-
477150603640c96f4]
aws_instance.cerberus: Destroying... [id=i-a6e22ec5303190252]
aws_instance.cerberus: Still destroying... [id=i-a6e22ec5303190252
10s elapsed]
aws_instance.cerberus: Destruction complete after 10s
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

if you dont want a resource to be destroyed. you can used prevent_destory

main.tf
resource "aws_instance" "cerberus" {
ami = "ami-06178cf087598769c"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver"
lifecycle {
prevent_destroy = true
}
$ terraform apply
aws_instance.cerberus: Refreshing state... [id=i-
477150603640c96f4]
Error: Instance cannot be destroyed
on main.tf line 6:
6: resource "aws_instance" "cerberus" {
Resource aws_instance.cerberus has
lifecycle.prevent_destroy set, but the plan
calls for this resource to be destroyed. To avoid this
error and continue with
the plan, either disable lifecycle.prevent_destroy or
reduce the scope of the
plan using the -target flag

This does not make it immune to destroy command.

ignore_chages will prevent from making changes to a resource.

main.tf
resource "aws_instance" "cerberus" {
ami = "ami-06178cf087598769c"
instance_type = "m5.large"
tags = {
Name = "Cerberus-Webserver"
}
lifecycle {
ignore_changes = [
tags
]
}
ami = "ami-2158cf087598787a"
Name = Cerberus-Webserver
"Cerberus-Webserver-1"
lifecycle {
ignore_changes = all
}
$ terraform apply
aws_instance.webserver: Refreshing state... [id=i-
05cd83b221911acd5]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Terraform Taint
#

Taint

main.tf

resource "aws_instance" "webserver-3" {
ami = "ami-0edab43b6fa892279"
instance_type = "t2.micro"
key_name = "ws"
provisioner "local-exec" {
    command = "echo ${aws_instance.webserver-3.public_ip} > /temp/pub_ip.txt"
}
terraform apply 
Plan: 1 to add, 0 to change, 0 to destroy.
aws_instance.webserver: Creating...
aws_instance.webserver: Still creating... [10s elapsed]
aws_instance.webserver: Still creating... [20s elapsed]
aws_instance.webserver: Still creating... [30s elapsed]
aws_instance.webserver: Provisioning with 'local-exec'...
aws_instance.webserver (local-exec): Executing: ["cmd" "/C" "echo 35.183.14.192 > /temp/pub_ip.txt"]
aws_instance.webserver (local-exec): The system cannot find the path specified.
Error: Error running command 'echo 35.183.14.192 > /temp/pub_ip.txt': exit status 1. Output: The system
cannot find the path specified.

This resource failed. Terraform marked this as tainted because it was not able to complete the provisioning.

$ 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_instance.webserver: Refreshing state... [id=i-0dba2d5dc22a9a904]
-----------------------------------------------------------------------
-
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_instance.webserver is tainted, so must be replaced
-/+ resource "aws_instance" "webserver-3" {
$ terraform taint aws_instance.webserver

Resource instance aws_instance.webserver has been marked as tainted.

$ 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_instance.webserver: Refreshing state... [id=i-0fd3946f5b3ab8af8]
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_instance.webserver is tainted, so must be replaced
-/+ resource "aws_instance" "webserver" {

Logging
#

Related