Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expected "apply" not to do anything, but creates duplicate #1783

Closed
JeanMertz opened this issue May 3, 2015 · 5 comments · Fixed by #4766
Closed

Expected "apply" not to do anything, but creates duplicate #1783

JeanMertz opened this issue May 3, 2015 · 5 comments · Fixed by #4766

Comments

@JeanMertz
Copy link
Contributor

What happens:

  • I plan a specific target
  • I apply the plan
  • Resource gets created
  • I plan the same target
  • Terraform tells me no changes are needed
  • I apply the plan
  • Resource gets created (duplicate)

What I expected to happen:

  • I plan a specific target
  • I apply the plan
  • Resource gets created
  • I plan the same target
  • Terraform tells me no changes are needed
  • I apply the plan
  • No changes are made

Am I misunderstanding the Terraform workflow, or could this be a bug?

I added the full command output below:

$ terraform plan -var 'os_password=xxx' -var-file staging.tfvars -state staging.tfstate -out staging.plan -target openstack_compute_secgroup_v2.coach
Refreshing Terraform state prior to plan...


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed.

Your plan was also saved to the path below. Call the "apply" subcommand
with this plan file and Terraform will exactly execute this execution
plan.

Path: staging.plan

+ openstack_compute_secgroup_v2.coach
    description:        "" => "Security rules for all \"coach\" nodes"
    name:               "" => "coach"
    rule.#:             "0" => "2"
    rule.0.cidr:        "" => "0.0.0.0/0"
    rule.0.from_port:   "" => "1"
    rule.0.id:          "" => "<computed>"
    rule.0.ip_protocol: "" => "tcp"
    rule.0.self:        "" => "0"
    rule.0.to_port:     "" => "65535"
    rule.1.cidr:        "" => "0.0.0.0/0"
    rule.1.from_port:   "" => "1"
    rule.1.id:          "" => "<computed>"
    rule.1.ip_protocol: "" => "udp"
    rule.1.self:        "" => "0"
    rule.1.to_port:     "" => "65535"
$ terraform apply -state staging.tfstate staging.plan
openstack_compute_secgroup_v2.coach: Creating...
  description:        "" => "Security rules for all \"coach\" nodes"
  name:               "" => "coach"
  rule.#:             "0" => "2"
  rule.0.cidr:        "" => "0.0.0.0/0"
  rule.0.from_port:   "" => "1"
  rule.0.id:          "" => "<computed>"
  rule.0.ip_protocol: "" => "tcp"
  rule.0.self:        "" => "0"
  rule.0.to_port:     "" => "65535"
  rule.1.cidr:        "" => "0.0.0.0/0"
  rule.1.from_port:   "" => "1"
  rule.1.id:          "" => "<computed>"
  rule.1.ip_protocol: "" => "udp"
  rule.1.self:        "" => "0"
  rule.1.to_port:     "" => "65535"
openstack_compute_secgroup_v2.coach: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: staging.tfstate
$ terraform plan -var 'os_password=xxx' -var-file staging.tfvars -state staging.tfstate -out staging.plan -target openstack_compute_secgroup_v2.coach
Refreshing Terraform state prior to plan...

openstack_compute_secgroup_v2.coach: Refreshing state... (ID: bd3d9cb1-8538-4053-b4f0-aeb1a1f4ef47)

No changes. Infrastructure is up-to-date. This means that Terraform
could not detect any differences between your configuration and
the real physical resources that exist. As a result, Terraform
doesn't need to do anything.
$ terraform apply -state staging.tfstate staging.plan
openstack_compute_secgroup_v2.coach: Creating...
  description:        "" => "Security rules for all \"coach\" nodes"
  name:               "" => "coach"
  rule.#:             "0" => "2"
  rule.0.cidr:        "" => "0.0.0.0/0"
  rule.0.from_port:   "" => "1"
  rule.0.id:          "" => "<computed>"
  rule.0.ip_protocol: "" => "tcp"
  rule.0.self:        "" => "0"
  rule.0.to_port:     "" => "65535"
  rule.1.cidr:        "" => "0.0.0.0/0"
  rule.1.from_port:   "" => "1"
  rule.1.id:          "" => "<computed>"
  rule.1.ip_protocol: "" => "udp"
  rule.1.self:        "" => "0"
  rule.1.to_port:     "" => "65535"
openstack_compute_secgroup_v2.coach: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: staging.tfstate
@JeanMertz
Copy link
Contributor Author

note: I understand why this happens; plan doesn't detect any required changes so doesn't write anything to the plan file, so when running apply with the plan file, it will apply the old recorded changes.

Still, I would expect running plan to always write to the plan file, even if no changes are required, so that apply always returns the expected result.

Note that in our case we invoke plan and apply programmatically, so there is no human in between to determine if we should use the plan when calling apply.

@sparkprime
Copy link
Contributor

You can delete the old plan after applying it / before running terraform plan. (This is what I do anyway).

@phinze
Copy link
Contributor

phinze commented May 4, 2015

Hi there - thanks for this report, and sorry for the confusing behavior.

Generally speaking, the plan file encodes the expected state along with the diff, and refuses to apply if the state it sees during application does not match. This doesn't cover the "create" case, though, since the expected plan is "nothing there", and TF doesn't have visibility into resources whose IDs it hasn't already recorded.

Still, I would expect running plan to always write to the plan file, even if no changes are required, so that apply always returns the expected result.

Yep at first glance this seems like a reasonable expectation to me. Flagging as a POLA violation bug and we'll get this looked at.

@sparkprime
Copy link
Contributor

I just had a quick look at terraform plan --help and it looks like -detailed-exitcode will allow you to detect the empty plan case as well.

But I also think writing the plan file every time is reasonable.

phinze added a commit that referenced this issue Jan 20, 2016
This makes the planfile workflow more consistent. If a plan yields a
noop, the apply of that planfile will noop.

Fixes #1783
bigkraig pushed a commit to bigkraig/terraform that referenced this issue Mar 1, 2016
This makes the planfile workflow more consistent. If a plan yields a
noop, the apply of that planfile will noop.

Fixes hashicorp#1783
@ghost
Copy link

ghost commented Apr 28, 2020

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.

@ghost ghost locked and limited conversation to collaborators Apr 28, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants