What does terraform apply/plan refresh-only do? - terraform

So I'm a bit confused on what terraform plan refresh-only is giving me. Essentially with just terraform plan it was saying it detected changes outside of terraform (that was me) and it was trying to "correct" these changes, sadly correcting these change requires the recreation of the resource. However if I add "refresh-only" after the plan, it removes that recreation and now says it will update the tfstate to match what changes I have done manually.
Is my understanding of this correct or are there things I'm missing?

A "normal" terraform plan includes two main behaviors:
Update the state from the previous run to reflect any changes made outside of Terraform. That's called "refreshing" in Terraform terminology.
Comparing that updated state with the desired state described by the configuration, and in case of any differences generating a proposed set of actions to change the real remote objects to match the desired state.
When you create a "refresh-only" plan, you're disabling the second of those, but still performing the first. Terraform will update the state to match changes made outside of Terraform, and then ask you if you want to commit that result as a new state snapshot to use on future runs. Typically the desired result of a refresh-only plan is for Terraform to report that there were no changes outside of Terraform, although Terraform does allow you to commit the result as a new state snapshot if you wish, for example if the changes cascaded from an updated object used as a data resource and you want to save those new results.
A refresh-only plan prevents Terraform from proposing any actions that would change the real infrastructure for that particular plan, but it does not avoid the need to deal with any differences in future plans. If the changes that Terraform is proposing are not acceptable then to move forward you will either need to change the configuration to match your actual desired state (for example, to match the current state of the object you don't want to replace) or change the real infrastructure (outside of Terraform) so it will match your configuration.

Related

Terraform Refresh after manual change

So here's what I'm trying to do
Given I changed a configuration in the load balancer
And I added that to my terraform declaration
When I run a plan there are zero changes which is expected
Do I need to refresh at this point to match my hardware state before applying?
Or when I run an apply this would just update the state?
If you've changed the settings outside of Terraform and you've updated the Terraform configuration to match then indeed there's no extra step to run here: terraform plan should report that it detected the value changed outside of Terraform (assuming you're using Terraform v1.0.0 or later) but then report that it doesn't need to make any changes to match with the configuration.
Note also that in recent Terraform the terraform refresh command is still available but no longer recommended. Instead, you can use terraform apply -refresh-only to get a similar effect but with the opportunity to review the detected changes before creating a new state snapshot. In the situation you've described, a refresh-only apply like this will also allow you to commit the detected change as a new state snapshot so that future terraform plan won't re-report that it detected a change made outside of Terraform, which might avoid your coworkers being confused by this message when they make a later change.

terraform plan notifies of changes in infrastructure but also saying No changes

When I run
terraform plan
it shows a list of changes made out of Terraform and at the end of output, it also informs that "No changes. Your infrastructure matches the configuration.":
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# google_sql_database_instance.db1 has been changed
~ resource "google_sql_database_instance" "db1" {
id = "db1"
name = "db1"
# (12 unchanged attributes hidden)
....
whole list of objects to update
....
....
Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
No changes. Your infrastructure matches the configuration.
Your configuration already matches the changes detected above. If you'd like to update the Terraform state to match, create and apply a refresh-only plan:
terraform apply -refresh-only
Not sure why it first says there are changes in infrastructure but also say that Configuration matches the Infrastructure.
I ran a test "Apply" and Terraform did not change anything but I want to know why is it showing these two different statements and also want to ensure that nothing is changes accidentally.
When Terraform creates a plan, it does two separate operations for each of your resource instances:
Read the latest values associated with the object from the remote system, to make sure that Terraform takes into account any changes you've made outside of Terraform.
Compare the updated objects against the configuration to see if there are any differences, and if so to propose actions Terraform will take in order to make the remote objects match the configuration.
The output you've shared is talking about both of those steps. Terraform first reports that when it read the latest values it detected that some things have already changed outside of Terraform, and explains what it detected. It then compared those updated objects against your configuration and found that your configuration already matches, and so Terraform doesn't need to make any additional changes to your infrastructure.
The final paragraph of the output includes "your configuration already matches the changes detected above", which suggests that you have made some changes to the objects outside of Terraform but you've also updated the configuration to match. Therefore Terraform doesn't need to make any changes to the remote objects to make them match the configuration, because something other than Terraform already updated them.

Resolving broken deleted state in terraform

When terraform tries to deploy something and then times out in a state like pending or deleting the state will eventually update to successful or deleted but this never gets updated in the tf state so when I try to run something again it errors because the state doesn't match.
Error: error waiting for EC2 Transit Gateway VPC Attachment (tgw-attach-xxxxxxxxx) deletion: unexpected state 'failed', wanted target 'deleted'. last error: %!s(<nil>)
What is the correct way to handle this? Can I do something within terraform to get it to recognise the latest state in AWS? Is it a bug on tf's part?
tl; dr
It's probably less of a bug and more of a design choice.
You should investigate and if appropriate (e.g. the resource was created or deleted successfully and the state was not updated appropriately), you could either
run terraform refresh, which will cause Terraform to refresh its state file against what actually exists with the cloud provider
manually reconcile the situation by manipulating the Terraform state with the terraform state command, removing deleted resources or adding created resources
Detail
Unlike CloudFormation, Terraform's approach to 'failures' is to just drop everything and error out, leaving the operator to investigate the issue and attempt to resolve it themselves. As a result, operations which timeout are classed as failures and so the relevant resources are often not updated in Terraform's state.
Terraform does give us some recourse to handle this however. For one, we can manually manipulate Terraform's state file. We can add resources or remove resources from the state file as we like, though this should be done with caution.
We can also ask Terraform to 'refresh' its state, basically comparing the state file to reality. Implicitly this should remove resources which no longer exist, but it will not adopt resources into the state file which were provisioned outside of a successful Terraform run.
As an aside, timeouts relating to the interaction with any service provider, are a feature of the relevant Terraform Provider, in this case the AWS Provider. Only the Providers can expose configurable timeouts. For example, the AzureRM Provider does provide a means to configure timeouts, but it appears the AWS Provider does not.
Efforts are presumably made to incorporate sensible timeout values, but it's not unusual to see trivial operations take an age to complete properly.

What happen when removing resources from terraform configuration file

I am trying to find my way in terraform , i am going through the documentation and got confused about what is exactly will happen if a resource has been deleted manually from the configuration file then we ran the apply command on the modified configuration file please ?
my understanding that the state file will still have the deleted resource as well it will still be actually running on the cloud platform so terraform apply will not perform any action, but i am not sure.
Appreciate if you help to clear my understanding please
Also another relevant point please what if a resource was changed manually from the cloud console for example and we tried to do any action from terraform on that resouces , what will happen ?
Thanks a lot ,
First, some background from the documentation at https://www.terraform.io/intro/index.html
Terraform generates an execution plan describing what it will do to reach the desired state, and then executes it to build the described infrastructure. As the configuration changes, Terraform is able to determine what changed and create incremental execution plans which can be applied.
The state mentioned gets saved when resources are modified. When you add a resource, it will get created and the state will be updated to reflect this. The same is for removing of resources. When you remove a resource in Terraform by deleting the code or template file, the resource will be removed and state updated to to reflect the removed resource (emphasis mine to illustrate the answer).
The second question of changing resources that drift from the state is a little more involved. When you create a plan against a resource that may have change, the provider will usually refresh the resources in state to compare them and show you what the changes to be made will be (ie. trying to change the resource to the declared state in the code).

Is terraform destroy needed before terraform apply?

Is terraform destroy needed before terraform apply? If not, what is a workflow you follow when updating existing infrastructure and how do you decide if destroy is needed?
That would be pretty non-standard, in my opinion. Terraform destroy is only used in cases where you want to completely wipe your infrastructure. One of the biggest features of terraform is that it can do an intelligent delta of your desired infrastructure and your existing infrastructure and only make the changes needed. By performing a refresh, plan and apply you can ensure that terraform:
refresh - Has an up-to-date understanding of your current infrastructure. This is important in case anything was changed manually, outside of your terraform script.
plan - Prepares a list for you to review of what terraform intends to modify, or delete (or leave alone).
apply - Performs the changes laid out in the plan.
By executing these 3 commands in sequence terraform will only perform the changes necessary, in the order required, to bring your environments in line with any changes to your terraform file.
Where I find destroy to be useful is in non-production environments or in cases where you are performing a restructure that's so invasive that starting from scratch would ensure a safer build.
*There are also edge cases where terraform may fail to understand the correct order of operations (do I modify a security group first or a security group rule?), or it will find itself in a dependency cycle and will be unable to perform an operation. In those cases, however, running destroy is a nuclear solution. In general, I would perform the problem change manually (via command line, or AWS Console, if I'm in AWS), to nudge it along and then run a refresh, plan, apply sequence to get back on track.
No terraform destroy is not needed before terraform apply.
Your Terraform configuration (*.tf and *.tfvars files) describes the desired state of your infrastructure. It says "this is how I want my infrastructure to be."
You use the terraform tool to plan and apply changes to get your infrastructure into the desired state you have described. You can make those changes incrementally without destroying anything.
A typical workflow might be:
make changes to .tf and .tfvars files
refresh state
plan changes
review the planned changes
apply those changes
If you wanted to completely destroy that infrastructure you'd use terraform plan -destroy to see what Terraform intends to destroy. If you are happy with that you'd then use terraform destroy to destroy it.
Typically, destroy is rarely used, unless you are provisioning infrastructure for a temporary purpose (e.g., builds) or testing your ability to provision from a clean slate with different parameters. Even then, you could use a count parameter on resources to temporarily provision resources by increasing the count, then decreasing it again when no longer needed.
More comments after #mwielbut's answer.
Instead of option apply + destroy, you need to run terraform with option taint + apply
Normally we don't need run terraform destroy at all. It is a really dangerous option, especially for a production environment.
with option plan and apply, it is good enough to update the infrastructure with code.
But if you do need to destroy some resources and re-build something which is already created, you can use the option of taint, which is the right answer for your question, it is so important and missed in #mwielbut's answer.
The terraform taint command manually marks a Terraform-managed resource as tainted, forcing it to be destroyed and recreated on the next apply.
This command will not modify infrastructure but does modify the state file in order to mark a resource as tainted. Once a resource is marked as tainted, the next plan will show that the resource will be destroyed and recreated and the next apply will implement this change.
Refer:
command taint:
https://www.terraform.io/docs/commands/taint.html
a sample of option taint:
https://www.terraform.io/docs/modules/usage.html
Terraform destroy destroys all the resources and it is not required if you want to apply incremental changes. Destroy should be only used if you want to destroy the whole infrastructure.
No need to use the destroy command before apply. as long as you are in testing period you can use destroy command or destroy the complete infra you can use destroy command
You can use below flow
terraform init
terraform plan
terraform apply
if you made any manual changes that needs to update in your state file, use below command to update the state file.
Terrafrom refresh
You don't need to run to terraform destroy . If you have made any changes to you infrastructure, [added/ removed a resource], on next terraform plan & terraform apply, the changes will be reflected automatically
Terraform apply always refreshes the Terraform state, so if you change anything, it auto recognizes the changes, lets say you've updated your NSG rules, added new VM, deleted old VM, so when you run terraform apply again, your old state gets updated with the new state where you've Added/Updated/Deleted.
If you use terraform destroy, it just kills the entire state and you'll be back to the new state if you are running terraform apply.
You need to use terraform destroy only if you think you just want to bring down your infrastructure and you don't really need it.
For minor - major changes like Adding Components, Updating Rules, Deleting other things, you can use plan and apply without any problem.
Simply NO.
You don't need to run terraform apply before terraform destroyو Your terraform (.tf) files describe the state of your infrastructure.
terraform apply always refresh your infrastructure. And it identifies the state of infrastructure and updates it.
terraform destroy only use is to bring down and completely wipe down your infrastructure. (You have to think twice before using it) you can use terraform plan and terraform refresh to ensure the state of the infrastructure.
You could always manually destroy your instances, after only running your terraform apply. Then when you run terraform apply it will create brand new instances without the terraform destroy.
No! you don't need to run terraform destroy when you need a modification of resources! This is the beauty of Infra-as-Code.
Here are some more details on Terraform init, plan, apply and destroy -
terraform init command is used to initialize a working directory containing Terraform configuration files. This is the first command that should be run after writing a new Terraform configuration or cloning an existing one from version control. It is safe to run this command multiple times.
terraform plan command creates an execution plan. By default, creating a plan consists of:
a) Reading the current state of any already-existing remote objects to make sure that the Terraform state is up-to-date.
b) Comparing the current configuration to the prior state and noting any differences.
c) Proposing a set of change actions that should, if applied, make the remote objects match the configuration.
terraform apply command executes the actions proposed in a Terraform plan. (you can do an apply without plan however it's not a best practice)
terraform destroy command is a convenient way to destroy all remote objects managed by a particular Terraform configuration.
Core Terraform workflows:
The core Terraform workflow has five steps:
Write - Author infrastructure as code.
Terraform init - it’ll automatically download and install partner and community provider directly to the local disk so that it can be used by other commands Plugin_Installation, Backend_Initialization, ChildModule_Installation and Community and third party plugin
Terraform plan - Preview changes before applying.
Terraform Apply - Provision reproducible infrastructure.
Terraform destroy - It will destroy your infrastructure.
No need for terraform destroy, as it will just destroy all the resources created.
You just need to provide the backend configuration in your tf file.
Backend configuration is the configuration in order to retrieve terraform state files.
Terraform apply first time will create your cloud infrastructure, this will update your state file also.
And next apply terraform will compare what new/update resources are to be done with what is already there using state file and will deploy accordingly.

Resources