How to manage and manipulate resources in Terraform state file - 1
Tags: terraform, ec2, cloud9, datasource
Published: 2023-01-14 02:34:46

In this article, we are going to create an AWS EC2 Linux instance and security group, examine a state file, and replace a resource using CLI to show how you manipulate the resources.

In the next article - ***[How to manage and manipulate resources in Terraform state file - 2](https://dev.to/aws-builders/how-to-manage-and-manipulate-resources-in-terraform-state-file-2-2hle)***, we will manipulate resources using these commands - **`move, remove and refresh`** to observe how important **state** is to your Terraform operations.

***Terraform state file - terraform.tfstate***

Terraform stores information about your infrastructure in a **`state file`**. This state file keeps track of resources created by your configuration and maps them to real-world resources, and keep track of metadata.

This state is stored by default in a local file named **`"terraform.tfstate"`**, but it can also be stored remotely.

Terraform  compares your configuration with the state file and your existing infrastructure to create **`plans`** and make changes to your infrastructure. When you run **`terraform apply`** or **`terraform destroy`** against your initialized configuration, Terraform writes metadata about your configuration to the state file and updates your infrastructure resources accordingly. Prior to any operation, Terraform does a **`refresh`** to update the state with the real infrastructure.

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.** Create infrastructure and a state file

**2.** Examine the state file with CLI

**3.** Replace a resource with CLI




# Pre-requisites:

- AWS user account with admin access, not a root account.

- Cloud9 IDE with AWS CLI, and Terraform installed.

# Resources Used:

For building this EC2 module, I have used a data source for pulling in an AMI ID instead of a hard-coded value. I have spent so much time to make this work, and after many, many attempts, I succeeded! I have also used Terraform documentation for this purpose.

***[Terraform documentation for AMI](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami).***

***[data source for pulling in an AMI ID](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance).***


# Steps for implementation to this project:

## 1. Create infrastructure and a state file

- Let’s create the following organizational structure as shown below.


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



- Create a **`main.tf`** file. This will deploy a Linux EC2 instance **`"ec2_orig"`**, with the security group**`"ec2_sg"`**. 

```

# PROVIDER BLOCK

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

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


# EC2 BLOCK

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" "ec2_orig" {
  ami                = data.aws_ami.linux.id
  instance_type      = "t2.micro"
  vpc_security_group_ids = [aws_security_group.ec2_sg.id]

  tags = {
    Name = "ec2_orig"
  }
}



# security group 
resource "aws_security_group" "ec2_sg" {
   name        = "ec2_sg"
   description = "allow inbound HTTP traffic"

   # HTTP from vpc
   ingress {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]     
   }


  # outbound rules
  # internet access to anywhere
  egress {
     from_port   = 0
     to_port     = 0
     protocol    = "-1"
     cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
     name = "ec2_sg"
  }
}



# OUTPUTS BLOCK

output "instance_id" {
  value = aws_instance.ec2_orig.id
}

output "public_ip" {
  value       = aws_instance.ec2_orig.public_ip
  description = "The public IP of the ec2 server"
}

output "security_group" {
  value = aws_security_group.ec2_sg.id
}


```

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


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


- Run **`terraform apply`** to apply the configuration and type **`yes`** when prompted.


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

- Wait for 4-5 minutes for the EC2 instance to be created.

## 2. Examine the state file with CLI

- Review the resources in the state file with the Terraform CLI without interacting with the **`.tfstate`** file. This is how you should interact with your state.

- Run **`terraform show`** to get a human-friendly output of the resources contained in your state.

***instance_id, public_ip***

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

***security_group***

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


***data "aws_ami" "linux"***

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


***outputs***

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




- Run **`terraform state list`** to get the list of resource names and local identifiers in your state file. 


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





## 3. Replace a resource with CLI

- Terraform updates your infrastructure if it does not match your configuration. 

- Hence, you can use the **`-replace`** command for **`terraform plan`** and **`terraform apply`** operations to safely recreate resources in your environment even if you have not edited the configuration.

- Replacing a resource is also useful in cases where a user manually changes a setting on a resource or when you need to update a script. 

- This allows you to rebuild specific resources and avoid a full **`terraform destroy`** operation on your configuration. 

- Run **`terraform plan -replace="aws_instance.ec2_orig"`** to see the resources that Terraform would create..



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




- Run **`terraform apply -replace="aws_instance.ec2_orig"`** to force Terraform to destroy and recreate the resource and type **`yes`** when prompted.

- Wait 4-5 minutes for the new EC2 instance to be re-created.



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


- Run **`terraform state list`** to get the list of **`new resource names and local identifiers`** in your state file. 

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



# What we have done so far

you created an EC2 Linux instance and corresponding security group. Then, you examined your local state file and replaced a resource using CLI to show how you manipulated the resources.