The Terraform Resource Lifecycle
In this post
I recently started working on Terraform Provider plugins, but there doesn’t seem to be much information about plugin-development out there on the internet. So I decided to collect some of my experience in a couple of posts.
When applying a Terraform configuration,
-
Terraform starts with a refresh of its state-file, reading the information about its resources from the infrastructure, and updating its state-file.
-
It will look for differences between its state-file and its configuration-files, to make a plan.
-
It will apply the plan by creating, updating or deleting resources,
-
Finally, it will refresh its state-file with the information from the updated infrastructure.
The resource lifecycle is based on the CRUD methods: Create, Read, Update and Delete. The minimum set of methods a provider needs to implement for a resource is: Create
, Read
and Delete
. The Update
method is optional. And for resources where a Read
is expensive, one can also add an Exists
method.
The data-source lifecycle only requires the Read
-method, since the infrastructure isn’t updated. I didn’t explicitly check if it can also use the Exists
-method, but I assume so.
The Create
, Read
& Delete
Methods Create, Read
& Delete
Methods'"> 🔗
These are the basic provider-methods used by Terraform. Which methods Terraform executes to refresh its state and to apply the user’s configuration depends on the state of the infrastructure, the state stored in the Terraform state-file ( typically terraform.tfstate
) and the Terraform configuration-files (*.tf
).
resource | terraform refresh | terraform apply | |
---|---|---|---|
- not in infrastructure | |||
– not in terraform state | |||
— not in terraform config | - | — | — |
— in terraform config | 1 | — | Create, Read |
– in terraform state | |||
— not in terraform config | 2 | Read (clear state) | |
— in terraform config | 3 | Read (clear state) | Create, Read |
- in infrastructure | |||
– not in terraform state | |||
— not in terraform config | - | — | — |
— in terraform config | 4 | — | Create (error) |
– in terraform state | |||
— not in terraform config | 5 | Read (refresh state) | Delete |
— in terraform config | |||
> config same as state | 6 | Read (refresh state) | — |
» changed computed attributes | 7 | Read (refresh state) | — |
> config different from state | |||
» changed force-new attributes | 8 | Read (refresh state) | Delete, Create, Read |
» changed common attributes | - | n.a. | n.a. |
For instance, take line 3 in the previous table
A resource X does not exist in the infrastructure. However, it does exist in the Terraform state - it was previously created using Terraform but was later manually deleted from the infrastructure. It does exist in the Terraform configuration - so we do want to re-create it.
Terraform will first refresh its state-file, so it uses the provider’s Read
-method to try to get the latest information about this resource from the infrastructure. Since the resource doesn’t exist in the infrastructure, Terraform will clear the resource from its state-file.
Terraform will then apply the terraform configuration, and will use the provider’s Create
-method to create the resource. The Create
-method is typically implemented to return the output of the provider’s Read
-method, and the Read
-method updates the new Terraform state-file. This will get infrastructure, Terraform state and Terraform configuration in-line with each other.
Terraform will not use theRead
-method after aCreate
-method by itself. Instead, theCreate
-method has to call theRead
-method (or implement its own read-function) before returning.
For instance, take line 4 in the previous table
A resource Y does exist in the infrastructure. However, it does not exist in the Terraform state - it was manually created in the infrastructure. It does exist in the Terraform configuration - so we do want to create it.
Terraform will not refresh its state-file because the resource is not known to Terraform.
Terraform then try to apply the terraform configuration, and will use the provider’s Create
-method to create the resource. The Create
-method is typically implemented to throw an error when a resource already exists, so Terraform will not create anything in the infrastructure and will not update its state-file.
For instance, take line 8 in the previous table
A resource Z does exist in the infrastructure. It does exist in the Terraform state - it was previously created using Terraform but some of its attributes may have been changed since. It does exist in the Terraform configuration - so we do want to get update its attributes in-line with the Terraform configuration.
Terraform will first refresh its state-file, so it uses the provider’s Read
-method to get the latest information about this resource from the infrastructure, and will update the resource’s attributes in its state-file.
Terraform will then apply the terraform configuration, and finds there are some attributes that are different from the Terraform configuration. Since the provider doesn’t implement an Update
-method, Terraform will Delete
, Create
and Read
the resource to get infrastructure, Terraform state and Terraform configuration in-line with each other.
Because there is noUpdate
-method, one must setForceNew: true
for all attributes in the schema, except for theComputed
attributes. This forces Terraform to useDelete
+Create
instead ofUpdate
.
Adding The Update
Method Update Method'"> 🔗
Forcing all resources to be deleted and re-created every time one of its attributes needs to be changed is not the most efficient way of working. Hence let’s add the Update
-method to the Terraform Provider. This means we don’t need to add ForceNew: true
to all non-Computed
attributes anymore, we can now do this selectively, only for attributes that cannot be changed without re-creating the resource.
resource | terraform refresh | terraform apply | |
---|---|---|---|
- not in infrastructure | |||
– not in terraform state | |||
— not in terraform config | - | — | — |
— in terraform config | 1 | — | Create, Read |
– in terraform state | |||
— not in terraform config | 2 | Read (clear state) | |
— in terraform config | 3 | Read (clear state) | Create, Read |
- in infrastructure | |||
– not in terraform state | |||
— not in terraform config | - | — | — |
— in terraform config | 4 | — | Create (error) |
– in terraform state | |||
— not in terraform config | 5 | Read (refresh state) | Delete |
— in terraform config | |||
> config same as state | 6 | Read (refresh state) | — |
» changed computed attributes | 7 | Read (refresh state) | — |
> config different from state | |||
» changed force-new attributes | 8 | Read (refresh state) | Delete, Create, Read |
» changed common attributes | 9 | Read (refresh state) | Update, Read |
Let’s have a look at what changed - take line 9 in the previous table
A resource Z* does exist in the infrastructure. It does exist in the Terraform state - it was previously created using Terraform but some of its attributes may have been changed since. It does exist in the Terraform configuration - so we do want to get update its attributes in-line with the Terraform configuration.
Terraform will first refresh its state-file, so it uses the provider’s Read
-method to get the latest information about this resource from the infrastructure, and will update the resource’s attributes in its state-file.
Terraform will then apply the terraform configuration, and finds there are some attributes that are different from the Terraform configuration. Terraform will use the provider’s Update
-method to update the resource. The Update
-method is typically implemented to return the output of the provider’s Read
-method, and the Read
-method updates the new Terraform state-file. This will get infrastructure, Terraform state and Terraform configuration in-line with each other.
Terraform will not use theRead
-method after anUpdate
-method by itself. Instead, theUpdate
-method has to call theRead
-method (or implement its own read-function) before returning.
Adding The Exists
Method Exists Method'"> 🔗
The Read
-method can be a very expensive method. A Terraform Provider may implement an Exists
-method to avoid this in some use-cases.
resource | terraform refresh | terraform apply | |
---|---|---|---|
- not in infrastructure | |||
– not in terraform state | |||
— not in terraform config | - | — | — |
— in terraform config | 1 | — | Create, Read |
– in terraform state | |||
— not in terraform config | 2 | Exists (clear state) | |
— in terraform config | 3 | Exists (clear state) | Create, Read |
- in infrastructure | |||
– not in terraform state | |||
— not in terraform config | - | — | — |
— in terraform config | 4 | — | Create (error) |
– in terraform state | |||
— not in terraform config | 5 | Exists, Read (refresh state) | Delete |
— in terraform config | |||
> config same as state | 6 | Exists, Read (refresh state) | — |
» changed computed attributes | 7 | Exists, Read (refresh state) | — |
> config different from state | |||
» changed force-new attributes | 8 | Exists, Read (refresh state) | Delete, Create, Read |
» changed common attributes | 9 | Exists, Read (refresh state) | Update, Read |
For instance, take line 3 in the previous table
A resource X* does not exist in the infrastructure. However, it does exist in the Terraform state - it was previously created using Terraform but was later manually deleted from the infrastructure. It does exist in the Terraform configuration - so we do want to re-create it.
Terraform will first refresh its state-file, so it uses the provider’s Exists
-method to find out if this resource exists in the infrastructure. Since the resource doesn’t exist in the infrastructure, Terraform will clear the resource from its state-file.
Terraform will then apply the terraform configuration, and will use the provider’s Create
-method to create the resource. The Create
-method is typically implemented to return the output of the provider’s Read
-method, and the Read
-method updates the new Terraform state-file. This will get infrastructure, Terraform state and Terraform configuration in-line with each other.
Leave a comment