DEV Community

Revathi Joshi for AWS Community Builders

Posted on

Using refresh-only mode to sync Terraform state File

The -refresh-only option for terraform plan and terraform apply was introduced in Terraform v0.15.4. For prior versions you must use terraform refresh. It reads the current settings from all managed remote objects and updates the Terraform state to match. Automatically applying the effect of a refresh is risky. If you have misconfigured credentials for one or more providers, Terraform may be misled into thinking that all of the managed objects have been deleted, causing it to remove all of the tracked objects without any confirmation prompt.

The -refresh-only command presents an interactive prompt for you to review the changes that Terraform has detected before committing them to the state.

Please visit my GitHub Repository for Terraform articles on various topics being updated on constant basis.

Let’s get started!

Objectives:

1. Login to AWS Management Console

2. Create infrastructure for resources block

3. Under terraform_files resources directory - Create subfolder - S3.

  • Under S3 sub-folder - Create dynamodb.tf and s3-bucket.tf.

4. Deploy Your Backend Resources

5. Under terraform_files resources directory - Create sub-folder - Terraform.

  • Under Terraform sub-folder, Create 5 files - backend.tf, main.tf, variables.tf, outputs.tf and terrafprm.tfvars.

6. Create Your Resources

  • Under Terraform sub-folder, Create 5 files - backend.tf, main.tf, variables.tf, outputs.tf and terraform.tfvars.

7. Troubleshoot Error

Pre-requisites:

  • AWS user account with admin access, not a root account.
  • Cloud9 IDE with AWS CLI.

Resources Used:

Terraform documentation.
Terraform documentation for AMI.
What is Amazon S3?.
What is Amazon DynamoDB?
Use refresh-only mode to sync Terraform state

Steps for implementation to this project:

1. Login to AWS Management Console

  • Make sure you're in the N. Virginia (us-east-1) region

2. Create infrastructure for resources block

  • Let’s create the following organizational structure as shown below. Image description

3. Under terraform_files resources directory - Create subfolder - S3.

  • Under S3 sub-folder - Create dynamodb.tf and s3-bucket.tf.

dynamodb.tf

resource "aws_dynamodb_table" "dynamodb-terraform-state-lock" {
  name = "backend-state-lock-dynamo"
  hash_key = "LockID"
  read_capacity = 20
  write_capacity = 20

  attribute {
    name = "LockID"
    type = "S"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Dynamo DB Name - backend-state-lock-dynamo

s3.tf

provider "aws" {
  region     = "us-east-1"
}

resource "aws_s3_bucket" "revmybucket" {
    bucket = "revbucket123456"
}

Enter fullscreen mode Exit fullscreen mode
  • bucket name - revbucket123456

4. Deploy Your Backend Resources

Now run these Terraform commands in the following order:

  • Run terraform version displays the current version of Terraform and all installed plugins.
  • Run terraform fmt to format the code.

Image description

  • Run terraform init to initialize Terraform.

Image description

  • Run terraform validate to check for any syntax errors.

Image description

  • Run terraform plan to see what resources will be created.

Image description

  • Run terraform apply executes the actions proposed in a terraform plan and type yes when prompted.
  • Run terraform apply --auto-approve flag will prevent Terraform from prompting you to enter yes explicitly before it deploys the code.

Image description

  • s3 bucket - revbucket123456

Image description

  • dynamodb table - backend-state-lock-dynamo, no backend state file created

Image description

  • terraform.tfstate file

Image description

5. Under terraform_files resources directory - Create sub-folder - Terraform.

  • Under Terraform sub-folder, Create 5 files - backend.tf, main.tf, variables.tf, outputs.tf and terraform.tfvars.

  • 1. backend.tf

  • substitute your bucket name and dynamodb table name

terraform {
  backend "s3" {
    encrypt = true
    bucket = "revbucket123456"
    dynamodb_table = "backend-state-lock-dynamo"
    key    = "backend.tfstate"
    region = "us-east-1"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • 2. main.tf
terraform {

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.23"
    }
  }

  required_version = ">= 0.14.9"
}

provider "aws" {
  profile = "default"
  region  = var.region
}

data "aws_ami" "linux" {
   most_recent = true
   owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_instance" "app_server" {
  ami           = data.aws_ami.linux.id
  instance_type = var.instance_type
  availability_zone = var.az_1a

  tags = {
    Name = var.instance_name
  }
}
Enter fullscreen mode Exit fullscreen mode
  • 3. variables.tf
variable "region" {
  description = "region"
  type        = string
  default     = "us-east-1"
}

variable "az_1a" {
  description = "availability zone 1"
  type        = string
  default     = "us-east-1a"
}

variable "instance_type" {
  description = "Value of the Name tag for the EC2 instance type"
  type        = string
  default     = "t2.micro"
}

variable "instance_name" {
  description = "Value of the Name tag for the EC2 instance"
  type        = string
  default     = "MyInstance"
}
Enter fullscreen mode Exit fullscreen mode
  • 4. outputs.tf
output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.app_server.id
}

output "instance_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_instance.app_server.public_ip
}

output "instance_name" {
  description = "Name of the EC2 instance"
  value       = aws_instance.app_server.tags.Name
}
Enter fullscreen mode Exit fullscreen mode
  • 5. terraform.tfvars
name = "rev"
#region = "us-west-1"
Enter fullscreen mode Exit fullscreen mode

6. Create Your Resources

cd terraform
Enter fullscreen mode Exit fullscreen mode

Now run these Terraform commands in the following order:

  • Run terraform version displays the current version of Terraform and all installed plugins.
  • Run terraform fmt to format the code.

Image description

  • Run terraform init to initialize Terraform.

Image description

  • Run terraform validate to check for any syntax errors.

Image description

  • Run terraform plan to see what resources will be created.

Image description

  • Run terraform apply executes the actions proposed in a terraform plan and type yes when prompted.
  • Run terraform apply --auto-approve flag will prevent Terraform from prompting you to enter yes explicitly before it deploys the code.

Image description

  • s3 bucket - revbucket123456, file - backend.tfstate

Image description

  • dynamodb table - backend-state-lock-dynamo, backend state file created

Image description

Image description

Image description

7. Troubleshoot Error

  • "In Terraform, refreshing your state file updates Terraform's knowledge of your infrastructure, as represented in your state file, with the actual state of your infrastructure. Terraform plan and apply operations run an implicit in-memory refresh as part of their functionality, reconciling any drift from your state file before suggesting infrastructure changes."

  • You can update your state file without making modifications to your infrastructure using the -refresh-only flag for plan and apply operations.

  • This allows you to review any updates to your state file.

  • Uncomment the region value by removing the hashtag in terraform.tfvars

#region = "us-west-1"
Enter fullscreen mode Exit fullscreen mode
region = "us-west-1"
Enter fullscreen mode Exit fullscreen mode
  • run
terraform plan -refresh-only
Enter fullscreen mode Exit fullscreen mode

Image description

  • Because you updated your provider for the us-west-1 region, Terraform tries to locate the EC2 instance with the instance ID tracked in your state file but fails to locate it since it's in a different region. Terraform assumes that you destroyed the instance and wants to remove it from your state file.

  • If the modifications to your state file proposed by a -refresh-only plan were acceptable, you could run a terraform apply -refresh-only and approve the operation to overwrite your state file without modifying your infrastructure.

  • However, in this tutorial, refreshing your state file would drop your resources, so do not run the apply operation.

  • Comment the region value by removing the hashtag in terraform.tfvars

region = "us-west-1"
Enter fullscreen mode Exit fullscreen mode
#region = "us-west-1"
Enter fullscreen mode Exit fullscreen mode
  • run
terraform plan -refresh-only
Enter fullscreen mode Exit fullscreen mode
  • You should now see the following message, "No changes. Your infrastructure still matches the configuration."

Image description

Cleanup

  • delete the file - backend.tfstate from bucket
terraform destroy
Enter fullscreen mode Exit fullscreen mode

Image description

What we have done so far

We have successfuly deployed backend and AWS resources. We reviewed the changes that Terraform has detected before committing them to the state using Terraform refresh-only command, thus demonstated the advantages of when to use that command.

Top comments (0)