Using refresh-only mode to sync Terraform state File
Tags: terraform, s3, dynamodb
Published: 2023-10-09 22:37:01

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](https://github.com/awsmine/Terraform_projects)** 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](https://registry.terraform.io/providers/hashicorp/aws/latest/docs).***
***[Terraform documentation for AMI](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami).***
***[What is Amazon S3?](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html).***
***[What is Amazon DynamoDB?](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html)***
***[Use refresh-only mode to sync Terraform state](https://developer.hashicorp.com/terraform/tutorials/state/refresh)***

# 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/roinszhhz6f70sa4wwc4.png)



## 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"
  }
}
```
- Dynamo DB Name - backend-state-lock-dynamo

**s3.tf**

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

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

```

- 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q2q4ac3vsmuyij3mv3vc.png)


- Run **terraform init** to initialize Terraform.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwue2jtb1g4rog79rk21.png)


- Run **terraform validate** to check for any syntax errors.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gzdalvotrfc028n0ujo.png)


- Run **terraform plan** to see what resources will be created.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rlma0sbxbbcjf309bvhy.png)


- 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vtb6k3g8k1103w0f54m.png)

- s3 bucket - revbucket123456

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mw2104qyucw6bongdbj3.png)

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


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6oqrj9rwxbocfeix75t.png)

- terraform.tfstate file

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jmigcxzepa7hws4bmnth.png)


## 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"
  }
}
```



- **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
  }
}
```

- **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"
}
```
- **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
}
```
- **5. terraform.tfvars**

```
name = "rev"
#region = "us-west-1"
```
## 6. Create Your Resources

```
cd terraform
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v0h7ygz3m09humqsjs2i.png)


- Run **terraform init** to initialize Terraform.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1yxdcr2h9nmwmjw42s4m.png)


- Run **terraform validate** to check for any syntax errors.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frnu3kfvs1hk7m2cete7.png)


- Run **terraform plan** to see what resources will be created.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sul7q7l5m7m52gpgnmbn.png)





- 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ymukidgxp4b2ykmtdzh1.png)




- s3 bucket - revbucket123456, file - backend.tfstate


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7w4rmscg9oz6cyocj3im.png)



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


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u1kosz3zvwr6awyep2a2.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1t5nf0s2uba2ih6fsmji.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rcbmedhtdnkjt1gi1tb3.png)

## 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"
```

```
region = "us-west-1"
```

- run
```
terraform plan -refresh-only
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmcqnhonrn0c2kahiqkb.png)

- 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"
```

```
#region = "us-west-1"
```

- run
```
terraform plan -refresh-only
```
- You should now see the following message, "No changes. Your infrastructure still matches the configuration."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/480fwjwgada2w4frfnfl.png)

# Cleanup
- delete the file - backend.tfstate from bucket

```
terraform destroy
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d74keictfmfm6yvp1qd2.png)

# 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.