Terraform: Specified state path ignored by Plan and/or Apply

Created on 22 Mar 2017  ยท  11Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.9.1

Terraform Configuration Files

provider "docker" {
}

data "docker_registry_image" "ubuntu" {
  name = "rastasheep/ubuntu-sshd:latest"
}

resource "docker_image" "ubuntu" {
  name = "${data.docker_registry_image.ubuntu.name}"
  pull_triggers = ["${data.docker_registry_image.ubuntu.sha256_digest}"]
  keep_locally = true
}

resource "docker_container" "ubuntu" {
  image = "${docker_image.ubuntu.name}"
  name = "ubuntu_container"
  ports {
    internal = 22
    external = 2222
  }
  must_run = true
}

Debug Output

https://gist.github.com/ncs-alane/f518e72ed928a9788bfad2919ad55ff0

Expected Behavior

  1. terraform plan -out=specified.tfplan -state=specified.tfstate should create specified.tfplan that specifies the use of the state file specified.tfstate

  2. terraform apply specified.tfplan should apply specified.tfplan to specified.tfstate

  3. terraform plan -destroy -out=specified.tfplan -state=specified.tfstate should create specified.tfplan that specifies a destructive plan for the existing specified.tfstate

  4. terraform apply specified.tfplan should destroy the state in specified.tfstate

Actual Behavior

  1. terraform plan -out=specified.tfplan -state=specified.tfstate creates specified.tfplan

  2. terraform apply specified.tfplan applies specified.tfplan to terraform.tfstate

  3. terraform plan -destroy -out=specified.tfplan -state=specified.tfstate creates specified.tfplan

  4. terraform apply specified.tfplan fails citing a state with differing lineage than the current state

Steps to Reproduce

  1. terraform plan -out=specified.tfplan -state=specified.tfstate
  2. terraform apply specified.tfplan
  3. terraform plan -destroy=specified.tfplan -state=specified.tfstate
  4. terraform apply specified.tfplan
bug core

Most helpful comment

So after some thoughts and studying terraform code, I believe the originating issue isn't so much of an issue as much as it being a misunderstanding of the documentation. The example of using the terraform plan -out=specified.tfplan -state=specified.tfstate would not actually write the state file path in to the terraform plan. If I understand the documentation and take it as literally as possible, the plan file stores the state itself and thus the reason why state path cannot be specified in conjunction with terraform apply specified.tfplan. Now, if you do not specify a terraform plan file, you can specify the state file to use to read from and write to. Otherwise, if you want to specify a non-default state file to write to while using the terraform plan file, you must use terraform apply -state-out=specified.tfstate specified.tfplan.

Example

  1. terraform plan -out=specified.tfplan -state=specified.tfstate
  2. terraform apply -state-out=specified.tfstate specified.tfplan
  3. terraform plan -destroy -out=specified.tfplan -state=specified.tfstate
  4. terraform apply -state-out=specified.tfstate specified.tfplan

All 11 comments

This affects me too, I have nothing more to add as the bug report was very detailed and explains the issue very well. It breaks our current usage of multiple-statefiles so I had to revert back to 0.8 for now.

Issue persists with 0.9.2 release.

Is there any planned resolution to this? It sounds like a number of users will be stuck on the latest 0.8 release until this is fixed, unless there is a workaround?

@r0p0s3c Yes, indeed, it's a rather big deal for me, as I rely on being able to use custom state paths for a couple of our workflows. Running 0.8 for now.

I was able to figure out what is causing the issue. It appears when the tfstate file is generated, it is not generated in the same directory as the tfplan file. This causes the lineage error. When moving the tfstate file in to the same directory as the tfplan file and running terraform apply it will be successful.

$ /usr/local/bin/terraform plan -out=${HOME}/dev/git/github.com/ncs-sburns/kitchen-terraform/examples/docker_provider/.kitchen/kitchen-terraform/default-terraform/terraform.tfplan -state=${HOME}/dev/git/github.com/ncs-sburns/kitchen-terraform/examples/docker_provider/.kitchen/kitchen-terraform/default-terraform/terraform.tfstate

$ ll .kitchen/kitchen-terraform/default-terraform
total 16
drwxr-xr-x  3 sburns  staff   102 Apr 10 01:19 .
drwxr-xr-x  3 sburns  staff   102 Apr 10 01:00 ..
-rw-r--r--  1 sburns  staff  5437 Apr 10 01:18 terraform.tfplan

$ ll
total 88
drwxr-xr-x  13 sburns  staff    442 Apr 10 01:19 .
drwxr-xr-x   5 sburns  staff    170 Apr 10 00:49 ..
drwxr-xr-x   5 sburns  staff    170 Apr 10 01:00 .kitchen
-rw-r--r--   1 sburns  staff    466 Apr 10 00:49 .kitchen.yml
-rw-r--r--   1 sburns  staff  12288 Apr 10 01:18 .kitchen.yml.swp
-rw-r--r--   1 sburns  staff    111 Apr 10 00:49 Gemfile
-rw-r--r--   1 sburns  staff   3437 Apr 10 00:59 Gemfile.lock
-rw-r--r--   1 sburns  staff   2369 Apr 10 00:49 README.md
-rw-r--r--   1 sburns  staff    492 Apr 10 00:50 main.tf
-rw-r--r--   1 sburns  staff     46 Apr 10 00:49 output.tf
-rw-r--r--   1 sburns  staff   4040 Apr 10 01:15 terraform.tfstate
drwxr-xr-x   3 sburns  staff    102 Apr 10 00:49 test
-rw-r--r--   1 sburns  staff     84 Apr 10 00:49 variables.tf

$ mv terraform.tfstate .kitchen/kitchen-terraform/default-terraform

$ /usr/local/bin/terraform apply -no-color -input=false -parallelism=10 ${HOME}/dev/git/github.com/ncs-sburns/kitchen-terraform/examples/docker_provider/.kitchen/kitchen-terraform/default-terraform/terraform.tfplan

$ terraform show .kitchen//kitchen-terraform/default-terraform/terraform.tfstate
data.docker_registry_image.ubuntu:
  id = sha256:a82e1f68ada1289c12f0a0f9d09327b05f19069e9f5f969eeb3e927999a4fe65
  name = rastasheep/ubuntu-sshd:latest
  sha256_digest = sha256:a82e1f68ada1289c12f0a0f9d09327b05f19069e9f5f969eeb3e927999a4fe65
docker_image.ubuntu:
  id = sha256:07e63bce704ce63320e0f796f1ad79a7dcb89737d8f6c2f62337a8838c615c63rastasheep/ubuntu-sshd:latest
  keep_locally = true
  latest = sha256:07e63bce704ce63320e0f796f1ad79a7dcb89737d8f6c2f62337a8838c615c63
  name = rastasheep/ubuntu-sshd:latest
  pull_triggers.# = 1
  pull_triggers.4087032343 = sha256:a82e1f68ada1289c12f0a0f9d09327b05f19069e9f5f969eeb3e927999a4fe65


Outputs:

localhost = localhost

Same thing happens with terraform console - it uses whatever tfstate is set by the currently active environment, ignoring the -state arg.

So after some thoughts and studying terraform code, I believe the originating issue isn't so much of an issue as much as it being a misunderstanding of the documentation. The example of using the terraform plan -out=specified.tfplan -state=specified.tfstate would not actually write the state file path in to the terraform plan. If I understand the documentation and take it as literally as possible, the plan file stores the state itself and thus the reason why state path cannot be specified in conjunction with terraform apply specified.tfplan. Now, if you do not specify a terraform plan file, you can specify the state file to use to read from and write to. Otherwise, if you want to specify a non-default state file to write to while using the terraform plan file, you must use terraform apply -state-out=specified.tfstate specified.tfplan.

Example

  1. terraform plan -out=specified.tfplan -state=specified.tfstate
  2. terraform apply -state-out=specified.tfstate specified.tfplan
  3. terraform plan -destroy -out=specified.tfplan -state=specified.tfstate
  4. terraform apply -state-out=specified.tfstate specified.tfplan

Thanks @ncs-sburns, this seems to work in v0.9.3 with the given example, save for one issue with the plan-destroy step, it should be:

terraform plan -destroy -state=specified.tfstate -out=specified.tfplan

Also, it'd be good to get an "official" answer on whether the usage/expectation that the OP, myself, and others, was indeed incorrect and not the result of a bug/missing functionality (given this touches the state functionality refactored as of v 0.9) - @jbardin or @mitchellh, can you clarify?

Hi,

Thanks @r0p0s3c and @ncs-sburns for the synopsis.

Yes, this is the intended behavior, and it makes more sense when you see the commands in combination this way. The failure due to the lineage check is an added safety feature to ensure that you're not modifying a state that you didn't intend to modify.

While it may be possible to store the -state argument in the plan, I think it would still cause confusion if running apply wrote to a state file path that wasn't represented in either the configuration or the cli flags. Since we now have the lineage check to prevent writing to the wrong state file, continuing to err on the side of being more explicit seems reasonable.

On a related note, this particular workflow is often a good candidate to migrate to "environments", which are essentially named states, so that specifying or renaming state files is no longer necessary.

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings