Can `terraform destroy` delete the S3 state file when destroying? - terraform

When I run terraform destroy to destroy everything in a folder I leaves behind the state file in S3 (which I'm using as my backend).
The state file it leaves behind looks like this:
{
"version": 4,
"terraform_version": "0.12.12",
"serial": 7,
"lineage": "9eb5ca6d-20a9-d5f5-053a-eefe274bf669",
"outputs": {},
"resources": []
}
Can Terraform delete the S3 file on destroying?

Probably not.
Terraform requires state to function, and a state file with zero resources represents an infrastructure state that's different than having no state file at all. Namely that you've created resources before, and if one were to compare backups of the state file, one could clearly see and restore the state history.
We further confirm this by looking at the terraform state and terraform destroy commands and notice none of their sub-commands or options remove the state file.
Having said that, what may work and I've never tried this, is if terraform manages the bucket containing the state file, and you destroy that bucket (using a local backup as the state file during the bucket destroy operation), we're effectively tricking terraform into erasing its state.

If you are using terraform workspaces to represent different environments then it is possible to remove the state file for a particular workspace by calling:
terraform workspace select default && terraform workspace delete workspace_for_deletion
This will only work with an empty state so should be called after you call terraform destroy.
Note that the default workspace can't be deleted. This means this isn't a perfect solution, but it should help keep minimise the clutter in your backend.

There is no straight forward option to delete a state file we can manipulate it with
terraform state rm command.
But One of the way is to use workspace for each environment but default workspace wont be deleted in that case.
Another way would be in aws cli something like aws s3 rm s3://mybucket/foo.tfstate.
https://docs.aws.amazon.com/cli/latest/reference/s3/rm.html might help.

Related

Completely stop Terraform generate local state file

After switch the backend to GCS, I still notice that the state file is generated every time I run apply locally.
According to document: " When using remote state, state is only ever held in memory when used by Terraform. It may be encrypted at rest, but this depends on the specific remote state backend."
is there a way to completely stop generating a local copy of state file and make local apply really that “state is only ever held in memory”??
Terraform v1.2.9
google = {
source = "hashicorp/google"
version = "4.15.0"
}
thank you
This can now be closed.
After remove the original terraform.tfstate, although a new file with same name will still be generated, it doesn't have all the information anymore, it only has the backend informaiton

How to specify a state file name in terraform backend?

I created a terraform gcs backend using the block :
terraform {
backend "gcs" {
bucket = "<redacted_bucket_name>"
prefix = "base/terraform.state"
impersonate_service_account = "<redacted_service_account>#<redacted_project_id>.iam.gserviceaccount.com"
}
}
By performing a terraform init, this creates the state file in the specified bucket but in a directory :
<bucket>
|--base (Directory)
|--terraform.state (Directory)
|--default.state (File)
How do I specify the name of the state file?
I know I've used the prefix wrong in this example, but there is nothing in the documentation about it.
The name is the name of the Terraform workspace that you're working in (hence default).
You use workspaces to separate your deployments when you're using the same code for multiple environments.
For example, if you were to perform a terraform init with a backend configured, it would use the default workspace and create a default.tfstate within the bucket.
If you were to do a terraform workspace new prod and performed a terraform init you would be working against a state file of prod.tfstate.
You don't have to use workspaces though as they can add complexity to the pipeline. You could just as easily have a different backend or place the state file under a different prefix; you can think of prefix in regards to GCS backends as a directory structure to place the state file.
e.g. prefix=terraform/myproject/nonprod would keep a default.tfstate under a nonprod directory so it's separate from the other environments. Whatever works for you.
prefix - (Optional) GCS prefix inside the bucket. Named states for workspaces are stored in an object called /.tfstate.
source

How to manage locally generated stateful files in Terraform

I have a Terraform (1.0+) script that generates a local config file from a template based on some inputs, e.g:
locals {
config_tpl = templatefile("${path.module}/config.tpl", {
foo = "bar"
})
}
resource "local_file" "config" {
content = local._config_tpl
filename = "${path.module}/config.yaml"
}
This file is then used by a subsequent command run from a local-exec block, which in turn also generates local config files:
resource "null_resource" "my_command" {
provisioner "local-exec" {
when = create
command = "../scripts/my_command.sh"
working_dir = "${path.module}"
}
depends_on = [
local_file.config,
]
}
my_command.sh generates infrastructure for which there is no Terraform provider currently available.
All of the generated files should form part of the configuration state, as they are required later during upgrades and ultimately to destroy the environment.
I also would like to run these scripts from a CI/CD pipeline, so naturally you would expect the workspace to be clean on each run, which means the generated files won't be present.
Is there a pattern for managing files such as these? My initial though is to create cloud storage bucket, zip the files up, and store them there before pulling them back down whenever they're needed. However, this feels even more dirty than what is already happening, and it seems like there is the possibility to run into dependency issues.
Or, am I missing something completely different to solve issues such as this?
The problem you've encountered here is what the warning in the hashicorp/local provider's documentation is discussing:
Terraform primarily deals with remote resources which are able to outlive a single Terraform run, and so local resources can sometimes violate its assumptions. The resources here are best used with care, since depending on local state can make it hard to apply the same Terraform configuration on many different local systems where the local resources may not be universally available. See specific notes in each resource for more information.
The short and unfortunate answer is that what you are trying to do here is not a problem Terraform is designed to address: its purpose is to manage long-lived objects in remote systems, not artifacts on your local workstation where you are running Terraform.
In the case of your config.yaml file you may find it a suitable alternative to use a cloud storage object resource type instead of local_file, so that Terraform will just write the file directly to that remote storage and not affect the local system at all. Of course, that will help only if whatever you intend to have read this file is also able to read from the same cloud storage, or if you can write a separate glue script to fetch the object after terraform apply is finished.
There is no straightforward path to treating the result of a provisioner as persistent data in the state. If you use provisioners then they are always, by definition, one-shot actions taken only during creation of a resource.

Use variable in Terraform remote backend

# Using a single workspace:
terraform {
backend "remote" {
hostname = "app.terraform.io"
organization = "company"
workspaces {
name = "my-app-prod"
}
}
}
For Terraform remote backend, would there be a way to use variable to specify the organization / workspace name instead of the hardcoded values there?
The Terraform documentation
didn't seem to mention anything related either.
The backend configuration documentation goes into this in some detail. The main point to note is this:
Only one backend may be specified and the configuration may not contain interpolations. Terraform will validate this.
If you want to make this easily configurable then you can use partial configuration for the static parts (eg the type of backend such as S3) and then provide config at run time interactively, via environment variables or via command line flags.
I personally wrap Terraform actions in a small shell script that runs terraform init with command line flags that uses an appropriate S3 bucket (eg a different one for each project and AWS account) and makes sure the state file location matches the path to the directory I am working on.
I had the same problems and was very disappointed with the need of additional init/wrapper scripts. Some time ago I started to use Terragrunt.
It's worth taking a look at Terragrunt because it closes the gap between Terraform and the lack of using variables at some points, e.g. for the remote backend configuration:
https://terragrunt.gruntwork.io/docs/getting-started/quick-start/#keep-your-backend-configuration-dry

understand the terraform for OCI

I have 3 questions here:
I have created terraform form scripts in Oracle Cloud Infrastructure to build the instance and other resources. But I am not able to get any script for route table configuration and service in network script. So i have made them manual. my current table has only the resource name, rest all configuration is blank. So i need help in getting a properly supported script for OCI to create route table with configuration.
As i did such things manually, i am not able to give terraform apply after doing some changes in the script, as terraform apply will delete all the rules which i created manually. So is it mandatory to give terraform apply every time when i change the script? or can i enter the config manually and simultaneously match that in the terraform script so that everything is intact?
After every terraform changes i could see 2 files is getting enlarge (terraform.tfstate, terraform.tfstate.backup) what are these two files? if that is a backup file, then how will it help me to restore if i mess up in my configuration?
In Terraform, the configuration script is always the source of truth. When you apply a configuration; Terraform will favor the settings of that configuration and override any changes that were manually done outside of Terraform.
To make sure your manual changes are not overwritten, you should make sure the configuration always matches the manual changes. One way to import manual resources into your configuration is using "terraform import" (see https://www.terraform.io/docs/import/index.html).
The terraform.tfstate and terraform.tfstate.backup files are used by Terraform to keep track of the latest state of the resources that Terraform has created. These files are used to help Terraform determine whether you configuration script has drifted from the state; so it knows how to apply your configuration script. To my knowledge, these state files are not intended to be backup files if you mess up your configuration. (see https://www.terraform.io/docs/state/index.html)
Hope this helps.
Here is an example for a route table resource in Terraform config file:
resource "oci_core_route_table" "webserver-rt" {
compartment_id = "${var.compartment_ocid}"
vcn_id = "${oci_core_virtual_network.oci-vcn.id}"
display_name = "webserver-rt"
route_rules = [{
destination = "0.0.0.0/0"
network_entity_id = "${oci_core_internet_gateway.internet-gateway.id}"
}]
}
You may find more details here: https://github.com/terraform-providers/terraform-provider-oci/blob/master/docs/examples/networking/route_table/route_table.tf

Resources