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:
resource
: This is the reserved keyword used to define a resource block in Terraform.
resource_type
: This defines what type of resource is to be created and what provider to use in creation. The naming convention on resource type is<provider_resource>
, where theprovider
is the name of the provider that Terraform will employ to create and manage this resource. For example, when you use AWS to create a virtual machine, aws is the provider, andresource
is the particular type of resource that you would want to create. For example, if you are carrying out an EC2 virtual machine, then say vpc for a VPC network or s3_bucket for an S3 storage bucket. So, in short, if you are creating an EC2 instance in AWS, then the resource_type would be aws_instance. That is, Terraform uses the aws provider or in other words, a plugin-to create an instance in the AWS Cloud platform.
local_name
: This is the unique name given for this resource in your Terraform configuration. The name here is used to refer to this resource throughout your code and has no significance outside of your Terraform module.
{
: This opening curly brace starts the resource block, which contains specific configuration arguments for this resource.
arguments
: Within the curly braces, you include one or more lines of configuration arguments that define what you want the state of the resource to be. The set of arguments is resource-specific.
}
: The ending curly brace completes the resource block.
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:
- aws_instance is the resource_type that determines that Terraform should use the AWS provider (or plugin) for provisioning an instance in the infrastructure of the AWS Cloud.
- example_ec2_instance is the unique name which we will use to identify this particular EC2 instance within the configuration file of Terraform.
- The key-value pairs within the curly braces are arguments that are specific to the type of resource, aws_instance.
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
RESOURCE_TYPE
: The type of resource - eg: aws_instance, azure_virtual_machine
LOCAL_NAME
: The name to be given to the resource (e.g., my_ec2_instance, my_vm)
ATTRIBUTE
: The specific attribute you want to access (e.g. id, public_ip, private_dns_name)
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:
- Implicit Dependencies
- Explicit Dependencies
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
}
}
- The
from
argument identifies the address of the resource you would like to remove, an instance key is not required.
- The
lifecycle
block is required, and its destroy argument specifies whether Terraform will attempt to destroy the object managed by the resource, or not. A value of false will mean it only removes the resource from the statefile without destroying it.
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
- Meta-Arguments - depends_on and replace_triggered_by
Feedback
Was this page helpful?