Resource Overview

Resources are the most critical element within the Terraform Configuration. Each resource block in a Terraform configuration is an infrastructure representation, including virtual machine, network, database, or any other cloud service or resource.
By defining resources in your Terraform configuration, you are declaring your desired state of your infrastructure. Terraform will manage the creation, updating or deletion of these resources for you to reach this desired state.

Resource Syntax

The basic syntax of a resource block is:
resource resource_type local_name {
    # arguments 
}
Let's break this syntax apart:

Example

Here is an example of a resource block:
resource aws_instance example_ec2_instance {
    ami = "ami-0123456789
    instance_type = "t2.micro
    tags {
        name = "my-ec2-instance"
    }
}
In this scenario:

Accessing Resource Attributes

Terraform has expressions which allow access to information regarding resources of the same module. In this way, other resources can be configured with the arguments of the existing resources inside a configuration.
In addition to the arguments you specify in your Terraform configuration, many resources have additional read-only arguments. These read-only arguments include information retrieved from the remote API as part of resource creation, such as a resource's unique random ID.

Resource Attribute Syntax

To refer to a resource attribute in an expression, use the following syntax:
<RESOURCE_TYPE>.<LOCAL_NAME>.<ATTRIBUTE>
Here

Example

resource "aws_iam_role" "s3" {
    assume_role_policy = data.aws_iam_policy_document.s3_policy.json
    name = "s2-access-role"
}

resource "aws_iam_role_policy_attachment" "s3policy" {
    role = aws_iam_role.s3.name
    policy_arn = var.policy_arn
}

resource "aws_instance" "example_ec2_instance" {
    ami = "ami-0123456789"
    instance_type = "t2.micro"
}

resource "aws_eip" "my_eip" {
    vpc = true
    instance = aws_instance.my_instance.id
}
In the above example, The aws_iam_role.s3.name attribute would be accessing the name attribute (a direct attribute) of the aws_iam_role resource named "s3". Its value is used to set the role argument of the aws_iam_role_policy_attachment resource.
The read-only id attribute of the aws_instance resource named "example_ec2_instance" will be accessed via the aws_instance.my_instance.id attribute. This value will be set to assign the instance argument of the aws_eip resource.

Resource Dependencies

Terraform automatically builds Resource Graph - a Directed Acyclic Graph (DAG) representing dependencies between the resources. Most resources in the configuration don't have any particular relationship to each other, and Terraform can make changes to several unrelated resources in parallel. However, some resources necessarily have to be processed after other certain resources due to the fact that the resource's configuration requires information generated by another resource.

Types of Dependencies

There are two kinds of dependencies in Terraform:

1. Implicit Dependencies

When creating infrastructure resources with Terraform, it is rather common to be facing a situation in which one resource will depend on another. In other words, you might want to create an AMI before you could then create, say, an EC2 instance using that AMI. These dependencies can be automatically managed by Terraform for you, it doesn't require you to write the logic on the order of creation or updates that each resource depends on. This is called an implicit dependency.
Whenever you use an expression with a resource block that refers to another resource, Terraform considers that reference to be an implicit ordering requirement. In other words, Terraform will automatically create or update that referenced resource before it will create or update the dependent resource.

Example

Let's take a look at the following Terraform configuration:
resource "aws_instance" "instance" {
    ami = aws_ami.ami.id
    instance_type = "t2.micro"
}

resource "aws_ami" "ami" {
    name = "example-ami"
    virtualization_type = "hvm"
}
Here, we have defined two resources: aws_instance and aws_ami. The aws_instance resource contains an ami attribute that references the id attribute of the aws_ami resource. Because this reference exists, Terraform will automatically consider the aws_ami resource as an implicit dependency of the aws_instance resource. So, when we run Terraform, it will create or update the aws_ami resource automatically before creating or updating the aws_instance resource.

2. Explicit Dependencies

Sometimes, Terraform cannot automatically determine the dependencies between resources. Therefore, to be able to create the resources in the right order, or update them in the right order, explicit dependencies have to be specified using depends_on and replace_triggered_by.

1. depends_on Meta-Argument

The depends_on meta-argument enables explicit specification of dependency between two resources. We can make use of this to specify a list of resources that needs to be created or updated prior to this resource is allowed to create/update.

Example

There are two resources in this example: aws_instance and aws_security_group. Here, we want the aws_security_group resource to be created or updated prior to the creation or update of the aws_instance resource.
resource "aws_instance" "instance" {
    ami = "ami-12345678"
    instance_type = "t2.micro"
    depends_on = [aws_security_group.example]
}

resource "aws_security_group" "example" {
    name = "example-sg"
    description = "Allow inbound traffic on port 80"
}
With depends_on, we are telling Terraform to establish/update the aws_security_group resource before creating/updating the aws_instance resource.

2. replace_triggered_by Meta-Argument

Another meta-argument available in Terraform is the replace_triggered_by. This argument allows us to add dependencies between independent resources. It will enable Terraform to automatically replace a resource if another resource it depends on changes.

Example

Here, we are describing two resources: aws_instance, aws_eip. We want to be guaranteed that if something changed in the aws_instance resource, Terraform will replace the aws_eip resource.
resource "aws_instance" "instance" {
    ami = "ami-12345678"
    instance_type = "t2.micro"
    depends_on = [aws_security_group.example]
}

resource "aws_eip" "example_eip" {
    domain = "vpc"
    replace_triggered_by = [aws_instance.instance]
}
The replace_triggered_by forces Terraform to change out the aws_eip resource if there is any changes to the aws_instance resource.

Removing a Resource from Terraform Configuration

To delete a resource in Terraform, you simply need to delete the resource block from your Terraform configuration. By default, Terraform will plan to destroy that corresponding infrastructure object managed by the resource.

Removing a Resource without Destroying the Infrastructure

Sometimes you want to remove a resource from your Terraform configuration without destroying the actual underlying infrastructure object. You can do this by having a removed block in your Terraform configuration.
The removed block instructs the Terraform to remove the resource from the Terraform state but should not destroy the object.
removed {
    from = aws_instance.example
    lifecycle {
        destroy = false
    }
}

Local-only Resources

In Terraform, most resources are configured to create infrastructure objects, for example virtual machines or databases, and exist outside of the Terraform. However, a few special resource types work entirely within Terraform and will interact with no infrastructure outside of it. These types of resources are known as "local-only resources".
The local-only resources can perform various types of calculations or generate data to be used by any other resource. Examples:
These resources don't manage any "real" infrastructure objects, but are usually helpful to connect other resources. They work exactly like regular resources, except their output data is stored only in the Terraform statefile, not in an external infrastructure.
When you destroy a local-only resource, that only means its data is removed from Terraform's statefile and it becomes no longer available for use, nothing will change outside of Terraform itself.

Example

For example, let's take a look at one local-only resource, such as random_id, which can generate a random ID. We can create a random ID resource and make use of this ID to tag an AWS instance:.
resource "random_id" "local_resource" {
    byte_length = 4
    instance_type = "t2.micro"
    keepers {
        ami_id = var.ami_id
    }
}

resource "aws_instance" "ec2" {
    tags = {
        Name = "web-server ${random_id.local_resource.hex}"
    }
}
The argument byte_length specifies the length in bytes for the generated random ID, and keepers is used to specify when the random ID should be regenerated. Here we are specifying that the random ID is to be regenerated on changes to the ami_id variable.
We have taken this configuration and run it. Here, the random_id resource generates a random ID when var.ami_id changed and stores it in Terraform's state. Move ahead, the same random ID is used by the aws_instance resource to tag the instance. See the below state file snippet for the random_id resource along with its attributes.
{ 
    "mode" : "managed"
    "type" : "random_id"
    "name" : "local_resource"
    "provider" : "provider[\"registry.terraform.io/hashicorp/random\"]"
    "instances" : [
      {
          "deposed" : "d1d6d1c0",
          "schema_version" : 0,
          "attributes" : {
              "b64_std" : "dvzwmQ==",
              "b64_url" : "dvzwmQ",
              "byte_length" : 4,
              "dec" : "1996288153",
              "hex" : "76fcf099",
              "id" : "dvzwmQ",
          }
      }
   ]
}

Related Pages

Feedback

Was this page helpful?