Showing the effect of a null_resource with Your Terraform Configuration
Tags: terraform, ec2, vpc, availabilityzone
Published: 2023-10-03 12:07:41

# What is null_resource? 

- As in the name you see a prefix ***`null`*** which means this resource will not exist on your Cloud Infrastructure(AWS, Google Cloud, Azure). 
- The reason is there is no terraform state associated with it, due to you can update the ***`null_resource`***  inside your Terraform file as many times as you can.

- Terraform null_resource can be used in the following scenario -

   - Run shell command.
   - You can use it along with local provisioner and remote provisioner.
   - It can also be used with Terraform Module, Terraform count, Terraform Data source, Local variables.
   - It can even be used for output block.

resource block using a null_resource that can be used to call your script and deploy your infrastructure to complete this lab.

I am going show you how to create a ***`null_resource`*** that can be used to call a script ***`health.sh`*** to deploy your infrastructure.

This will allow you to add some functionality and flexibility to your Terraform configuration and perform useful tasks. 

For example, we can see the status of the instance, along with the instance ID, the Availability Zone it is running in, and what state the health check is in while your instance is being deployed.

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 a subfolder - ***`scripts`*** for ***`health.sh`***, and 3 files - ***`main.tf`***, ***`variables.tf`***, ***`outputs.tf`***.

**4.** Configure Your null_resource

**5.** Initialize Terraform

**6.** To generate the action plans

**7.** Create all the resources declared in main.tf configuration file

**8.** Validate all resources created
 


# 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).***
***[null_resource](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource).***


# 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/pz1gkf41nmae0kmcnmnl.png)

## 3. Under ***`terraform_files`*** resources directory - Create a subfolder - ***`scripts`*** for ***`health.sh`***, and files - ***`main.tf`***, ***`variables.tf`***, and ***`outputs.tf`***.


- Create a directory - ***`terraform-files`***

    - Create a sub-folder - ***`scripts`***

        - Create a file - ***`health.sh`***

```
#!/bin/bash
echo "  -------------------------------------------"
echo "  --> Fetching Instance status."
sleep 25
instance_id=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=TheFastestManAlive" "Name=instance-state-name,Values=running" --query'Reservations[*].Instances[*].InstanceId' --output text)
size=${#instance_id}
echo "   -------------------------------- "
echo "  --> Instance ID: $instance_id"
sleep 2
instance_state=$(aws ec2 describe-instance-status --instance-ids $instance_id --query 'InstanceStatuses[*].InstanceState.Name' --output text)
size=${#instance_state}
echo "   -------------------------------- "
echo "  --> Instance Status: $instance_state"
sleep 2
instance_zone=$(aws ec2 describe-instance-status --instance-ids $instance_id --query 'InstanceStatuses[*].AvailabilityZone' --output text)
size=${#instance_zone}
echo "   -------------------------------- "
echo "  --> Availability Zone: $instance_zone"
sleep 2
fetch_instance_health=$(aws ec2 describe-instance-status --instance-ids $instance_id --query 'InstanceStatuses[*].InstanceStatus.Status' --output text)
echo "   -------------------------------- "
echo "  --> Instance health check : $fetch_instance_health"
echo "  -------------------------------------------"
```
- add executable permissions

```
chmod 755 health.sh
```

- Create 3 files - ***`main.tf`***, ***`variables.tf`***, and ***`outputs.tf`***. 

- 1. ***`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 = "My_Instance"
  }
}
```

- 2. ***`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"
}
```

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

## 4. Configure Your null_resource

- Open main.tf again in an editor:

- Add the following resource block to the end of the file:

```
resource "null_resource" "ec2_status" {
  provisioner "local-exec" {
    command = "./scripts/health.sh"
  }
}
```

- main.tf after you have added the resource ***`null_resource`*** block

```
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 = "My_Instance"
  }
}

resource "null_resource" "ec2_status" {
  provisioner "local-exec" {
    command = "./scripts/health.sh"
  }
}
```

- When you apply your Terraform configuration, this null_resource should launch your health.sh script.


## 5. Initialize Terraform
***`cd terraform-files`***

- ***`terraform status`*** 
```
terraform version
```
Since the Terraform version is returned, you have validated that the Terraform binary is installed and functioning properly.

#### Note:
If you receive a notification that there is a newer version of Terraform available, you can ignore it — it will run safely with the version installed on the VM.

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

- ***`terraform fmt`*** 

to format all of your resources

```
terraform fmt
```

- ***`terraform init`*** will check for all the plugin dependencies and download them if required, this will be used for creating a deployment plan.

```
terraform init
```

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

- Validate your Terraform syntax

```
terraform validate
```


## 6. To generate the action plans

```
terraform plan
```

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


## 7. Create all the resources declared in main.tf configuration file

#### Note: 
The --auto-approve flag will prevent Terraform from prompting you to enter yes explicitly before it deploys the code.

```
terraform apply --auto-approve
```

- 1.

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

- 2. 

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

- 3.

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

- 4.

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


```
terraform state list
```

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


## 8. Validate all resources created


- 1. instance_name, instance_id, and instance_ip


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

- 2. availability zone


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

# Cleanup

- terraform destroy

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


# What we have done so far

We have successfully created a ***`null_resource`*** that can be used to call a script ***`health.sh`*** to deploy all the resources in your infrastructure along with its status.