Skip to content

terraform: use state_file for apply and destroy - #12997

Merged
russoz merged 2 commits into
ansible-collections:mainfrom
fjvbn2003:terraform-state-file-apply-destroy
Oct 26, 2026
Merged

russoz merged 2 commits into
ansible-collections:mainfrom
fjvbn2003:terraform-state-file-apply-destroy

Conversation

@fjvbn2003

Copy link
Copy Markdown
Contributor
SUMMARY

Fixes #6490

state_file is passed to terraform plan (in build_plan()) and to terraform output, but not to the commands that change resources:

  • state: present builds the plan with -state <state_file> and then runs terraform apply ... <planfile> without -state. When the plan has changes, Terraform checks the plan against the default terraform.tfstate and fails with Error: Saved plan does not match the given state (OpenTofu says "... it was created from a different state lineage").
  • state: absent runs terraform destroy without -state. It reports No changes. No objects need to be destroyed, returns changed: false, and leaves the resources in state_file. In check mode the same task reports changed: true, because the check-mode plan uses state_file. This is the problem reported in Terraform module - ignores state_file when state=absent #6490.

This PR:

  • adds _state_args(module, state_file) to the destroy command for state: absent;
  • adds it to the apply command when the module built the plan itself. When the user gives plan_file with state: present, nothing changes, as the docs say state_file "is ignored when plan is specified";
  • adds an integration test (tasks/state_file.yml) that creates a resource with terraform apply -state=custom.tfstate, adds a second resource with the module (state: present, state_file), and destroys both (state: absent, state_file). It checks changed and the output of terraform state list -state=custom.tfstate;
  • adds a changelog fragment.

When state_file does not exist, _state_args() still warns and returns no arguments, so that case behaves as before.

ISSUE TYPE
  • Bugfix Pull Request
COMPONENT NAME

terraform

ADDITIONAL INFORMATION

I ran the module from main (e7f0aa1) and from this branch with ansible-core 2.21.5 (from the v2.21.5 tag, Python 3.12) and OpenTofu v1.9.0 as binary_path, with the hashicorp/null provider. I did not have a Terraform binary available, so I have not run the new integration test with Terraform 1.1.7 as CI does. apply -state=... <planfile>, destroy -state=... and state list -state=... are the legacy local-backend flags, which Terraform 1.x still has.

state: absent with a custom state file that holds null_resource.one:

# main (before)
absent(check_mode).changed=True
absent.changed=False cmd: tofu destroy -no-color -auto-approve -lock=true
absent.stdout: No changes. No objects need to be destroyed. ... Destroy complete! Resources: 0 destroyed.
custom.tfstate after absent: ['null_resource.one']

# this branch (after)
absent(check_mode).changed=True
absent.changed=True cmd: tofu destroy -no-color -auto-approve -lock=true -state /tmp/proja-after/custom.tfstate
absent.stdout: ... Plan: 0 to add, 0 to change, 1 to destroy. ... Destroy complete! Resources: 1 destroyed.
custom.tfstate after absent: []

state: present with the same state file and one new resource in the configuration:

# main (before)
fatal: [localhost]: FAILED! => {"cmd": "tofu apply -no-color -input=false -auto-approve -lock=true /tmp/tmp....tfplan",
  "msg": "\nError: Saved plan does not match the given state\n\nThe given plan file can not be applied because it was created from a\ndifferent state lineage."}

# this branch (after)
present.changed=True | custom.tfstate after present: ['null_resource.one', 'null_resource.two']

The new integration test, run as a role (include_role: terraform, tasks_from: state_file.yml) with terraform_binary_path=tofu:

# main (before)
TASK [terraform : Add the second resource using the custom state file]
fatal: [localhost]: FAILED! => {... "msg": "\nError: Saved plan does not match the given state ...
localhost : ok=4 changed=3 unreachable=0 failed=1

# this branch (after)
localhost : ok=10 changed=5 unreachable=0 failed=0

Without state_file (default terraform.tfstate), present, absent in check mode, and absent behave the same before and after (all changed=True, and no resources are left).

This change was drafted with AI assistance and reviewed by me.

🤖 Generated with Claude Code

state_file was only passed to "terraform plan" (and "terraform output").
The commands that change resources did not get it:

- state=present applied the saved plan without -state. When the plan
  had changes, Terraform compared it with the default terraform.tfstate
  and failed with "Saved plan does not match the given state".
- state=absent ran "terraform destroy" without -state, so it reported
  no changes and left the resources in state_file. The same task in
  check mode reported changed=true, because its plan did use state_file.

Pass the state arguments to both commands, and add an integration test
that changes and destroys resources tracked in a custom state file.

Fixes ansible-collections#6490

Assisted-by: Claude Opus 5.5
Signed-off-by: YoungjuKim <[email protected]>
@fjvbn2003
fjvbn2003 force-pushed the terraform-state-file-apply-destroy branch from 24bf688 to e95bc84 Compare October 16, 2026 15:54
@ansibullbot

Copy link
Copy Markdown
Collaborator

@ansibullbot ansibullbot added bug This issue/PR relates to a bug integration tests/integration module module new_contributor Help guide this first time contributor plugins plugin (any type) tests tests labels Oct 16, 2026
@felixfontein felixfontein added check-before-release PR will be looked at again shortly before release and merged if possible. backport-12 Automatically create a backport for the stable-12 branch backport-13 Automatically create a backport for the stable-13 branch labels Oct 17, 2026

@russoz russoz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @fjvbn2003 thanks for your contribution!

I got only one nit to pick in the changelog fragment, other than that it LGTM

@@ -0,0 +1,2 @@
bugfixes:
- terraform - pass ``state_file`` to the ``apply`` and ``destroy`` commands, not only to ``plan``. Before, ``state=present`` failed with ``Saved plan does not match the given state`` when the plan had changes, and ``state=absent`` did not destroy the resources tracked in ``state_file`` (https://github.com/ansible-collections/community.general/issues/6490, https://github.com/ansible-collections/community.general/pull/12997).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to explain what happened before

Suggested change
- terraform - pass ``state_file`` to the ``apply`` and ``destroy`` commands, not only to ``plan``. Before, ``state=present`` failed with ``Saved plan does not match the given state`` when the plan had changes, and ``state=absent`` did not destroy the resources tracked in ``state_file`` (https://github.com/ansible-collections/community.general/issues/6490, https://github.com/ansible-collections/community.general/pull/12997).
- terraform - pass ``state_file`` to the ``apply`` and ``destroy`` commands, not only to ``plan`` (https://github.com/ansible-collections/community.general/issues/6490, https://github.com/ansible-collections/community.general/pull/12997).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Applied the suggestion.

Apply the review suggestion: describe the fix, not the old behaviour.

Assisted-by: Claude <[email protected]>
Signed-off-by: YoungjuKim <[email protected]>

@russoz russoz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@russoz
russoz merged commit 51224d7 into ansible-collections:main Oct 26, 2026
138 checks passed
@patchback

patchback Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Backport to stable-13: 💚 backport PR created

✅ Backport PR branch: patchback/backports/stable-13/51224d7e3d71e3a3a0b7e44b825f045c300a1d4c/pr-12997

Backported as #13055

🤖 @patchback
I'm built with octomachinery and
my source is open — https://github.com/sanitizers/patchback-github-app.

@patchback

patchback Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Backport to stable-12: 💚 backport PR created

✅ Backport PR branch: patchback/backports/stable-12/51224d7e3d71e3a3a0b7e44b825f045c300a1d4c/pr-12997

Backported as #13056

🤖 @patchback
I'm built with octomachinery and
my source is open — https://github.com/sanitizers/patchback-github-app.

@russoz

russoz commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

@fjvbn2003 thanks for contributing!
@felixfontein thanks for reviewing!

@felixfontein felixfontein removed the check-before-release PR will be looked at again shortly before release and merged if possible. label Oct 26, 2026
felixfontein added a commit that referenced this pull request Oct 26, 2026
…r apply and destroy (#13056)

* terraform: use state_file for apply and destroy (#12997)

* terraform: use state_file for apply and destroy

state_file was only passed to "terraform plan" (and "terraform output").
The commands that change resources did not get it:

- state=present applied the saved plan without -state. When the plan
  had changes, Terraform compared it with the default terraform.tfstate
  and failed with "Saved plan does not match the given state".
- state=absent ran "terraform destroy" without -state, so it reported
  no changes and left the resources in state_file. The same task in
  check mode reported changed=true, because its plan did use state_file.

Pass the state arguments to both commands, and add an integration test
that changes and destroys resources tracked in a custom state file.

Fixes #6490

Assisted-by: Claude Opus 5.5
Signed-off-by: YoungjuKim <[email protected]>

* Shorten the terraform state_file changelog fragment

Apply the review suggestion: describe the fix, not the old behaviour.

Assisted-by: Claude <[email protected]>
Signed-off-by: YoungjuKim <[email protected]>

---------

Signed-off-by: YoungjuKim <[email protected]>
(cherry picked from commit 51224d7)

* Address differences to main.

Co-authored-by: Felix Fontein <[email protected]>

---------

Signed-off-by: YoungjuKim <[email protected]>
Co-authored-by: Youngju KIM <[email protected]>
Co-authored-by: Felix Fontein <[email protected]>
felixfontein added a commit that referenced this pull request Oct 26, 2026
…r apply and destroy (#13055)

* terraform: use state_file for apply and destroy (#12997)

* terraform: use state_file for apply and destroy

state_file was only passed to "terraform plan" (and "terraform output").
The commands that change resources did not get it:

- state=present applied the saved plan without -state. When the plan
  had changes, Terraform compared it with the default terraform.tfstate
  and failed with "Saved plan does not match the given state".
- state=absent ran "terraform destroy" without -state, so it reported
  no changes and left the resources in state_file. The same task in
  check mode reported changed=true, because its plan did use state_file.

Pass the state arguments to both commands, and add an integration test
that changes and destroys resources tracked in a custom state file.

Fixes #6490

Assisted-by: Claude Opus 5.5
Signed-off-by: YoungjuKim <[email protected]>

* Shorten the terraform state_file changelog fragment

Apply the review suggestion: describe the fix, not the old behaviour.

Assisted-by: Claude <[email protected]>
Signed-off-by: YoungjuKim <[email protected]>

---------

Signed-off-by: YoungjuKim <[email protected]>
(cherry picked from commit 51224d7)

* Address differences to main.

Co-authored-by: Felix Fontein <[email protected]>

---------

Signed-off-by: YoungjuKim <[email protected]>
Co-authored-by: Youngju KIM <[email protected]>
Co-authored-by: Felix Fontein <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-12 Automatically create a backport for the stable-12 branch backport-13 Automatically create a backport for the stable-13 branch bug This issue/PR relates to a bug integration tests/integration module module new_contributor Help guide this first time contributor plugins plugin (any type) tests tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Terraform module - ignores state_file when state=absent

4 participants