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

Incorrect "Provider produced inconsistent final plan" error when changing count or for_each of resources with create_before_destroy #25631

Closed
jbardin opened this issue Jul 21, 2020 · 5 comments · Fixed by #26470
Labels
bug confirmed a Terraform Core team member has reproduced this issue core

Comments

@jbardin
Copy link
Member

jbardin commented Jul 21, 2020

When referencing multiple instances of a resource with create_before_destroy, reducing the number of instances will not be correctly updated on the first apply.

For example:

locals {
  things = {
    first = "one"
    second = "two"
  }
}

resource "null_resource" "a" {
  for_each = local.things
  lifecycle {
    create_before_destroy = true
  }
}

resource "null_resource" "b" {
  triggers = {for i, a in null_resource.a: i => a.id}
}

This will create 2 null_resource.a instances, and record their keys and ids in the single null_resource.b instance.

Now if the "second" map value is removed, the resulting plan will look like

  # null_resource.a["second"] will be destroyed
  - resource "null_resource" "a" {
      - id = "5837642811259646161" -> null
    }

  # null_resource.b must be replaced
-/+ resource "null_resource" "b" {
      ~ id       = "13446854340418721" -> (known after apply)
      ~ triggers = { # forces replacement
            "first"  = "2410135502881497988"
          - "second" = "5837642811259646161" -> null
        }
    }

This however will fail during apply with:

Error: Provider produced inconsistent final plan

When expanding the plan for null_resource.b to include new values learned so
far during apply, provider "registry.terraform.io/hashicorp/null" produced an
invalid new value for .triggers: new element "second" has appeared.

This is a bug in the provider, which should be reported in the provider's own
issue tracker.

This is because the evaluation for the resource.a during apply will also contain nodes that are scheduled for destruction, which does not happen during the plan phase. This was fixed for 0.13, but needed to be reverted when it was discovered that provider and destroy provisioner evaluation was not equipped to handle this, and we must continue to include the deposed instances in the resource evaluation.

@danieldreier danieldreier added new new issue not yet triaged and removed new new issue not yet triaged labels Aug 5, 2020
@apparentlymart apparentlymart added the confirmed a Terraform Core team member has reproduced this issue label Aug 19, 2020
@apparentlymart apparentlymart changed the title Cannot change count or for_each of referenced instances with create_before_destroy "Provider produced inconsistent final plan" when changing count or for_each of resources with create_before_destroy Aug 19, 2020
@apparentlymart apparentlymart changed the title "Provider produced inconsistent final plan" when changing count or for_each of resources with create_before_destroy Incorrect "Provider produced inconsistent final plan" result when changing count or for_each of resources with create_before_destroy Aug 19, 2020
@apparentlymart apparentlymart changed the title Incorrect "Provider produced inconsistent final plan" result when changing count or for_each of resources with create_before_destroy Incorrect "Provider produced inconsistent final plan" error when changing count or for_each of resources with create_before_destroy Aug 19, 2020
@Nuru
Copy link

Nuru commented Sep 16, 2020

Is there a workaround for this?

@jbardin
Copy link
Member Author

jbardin commented Sep 16, 2020

For now you should be able to target the resource that needs to be removed first, then complete the rest of the apply afterwards. In this case it would be terraform apply -target 'null_resource.a["second"]' to remove that instance, then the other resources can be updated correctly.

@Nuru
Copy link

Nuru commented Sep 18, 2020

@jbardin Thank you for handling the other bugs (#26226, #26252, #26166, #26180) so quickly. Unfortunately, this one is still a significant problem for me.

The resource that needs to be destroyed is an AWS security group, and to destroy that, it needs to have anything using it destroyed first, which includes create-before-destroy resources. Targeting the resource that needs to be removed would defeat the whole create-before-destroy idea.

Is there perhaps a way to convert this to the now fixed #26252 ?

UPDATE: I think I've got the workaround. Still looking forward to this getting fixed.

@yupwei68
Copy link

yupwei68 commented Sep 27, 2020

@jbardin Does it treat an update and a destroy situation? In my case, I want to update a NIC field and destroy the PIP resource.
I have added this lifecycle in the PIP resource, but it shows error:

resource "azurerm_network_interface" "vm" {
  count                         = var.nb_instances
  name                          = "${var.vm_hostname}-nic-${count.index}"
  resource_group_name           = data.azurerm_resource_group.vm.name
  location                      = coalesce(var.location, data.azurerm_resource_group.vm.location)
  enable_accelerated_networking = var.enable_accelerated_networking

  ip_configuration {
    name                          = "${var.vm_hostname}-ip-${count.index}"
    subnet_id                     = var.vnet_subnet_id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = length(azurerm_public_ip.vm.*.id) > 0 ? element(azurerm_public_ip.vm.*.id, count.index) : ""
  }

  tags = var.tags
}

resource "azurerm_public_ip" "vm" {
  count               = var.nb_public_ip
  name                = "${var.vm_hostname}-pip-${count.index}"
  resource_group_name = data.azurerm_resource_group.vm.name
  location            = coalesce(var.location, data.azurerm_resource_group.vm.location)
  allocation_method   = var.allocation_method
  domain_name_label   = element(var.public_ip_dns, count.index)
  tags                = var.tags
  lifecycle {
    create_before_destroy = true
  }
}
Error: Provider produced inconsistent final plan

When expanding the plan for
module.windowsservers.azurerm_network_interface.vm[0] to include new values
learned so far during apply, provider
"registry.terraform.io/hashicorp/azurerm" produced an invalid new value for
.ip_configuration[0].public_ip_address_id: was cty.StringVal(""), but now
cty.StringVal("/subscriptions/.../resourceGroups/example-resources-compute-yup/providers/Microsoft.Network/publicIPAddresses/mywinvm-pip-0").

This is a bug in the provider, which should be reported in the provider's own
issue tracker.

@ghost
Copy link

ghost commented Nov 5, 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 as resolved and limited conversation to collaborators Nov 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug confirmed a Terraform Core team member has reproduced this issue core
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants