hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.

Home Page:https://www.terraform.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TF state was not updated when `-target` and `-replace` options were used

EugenKon opened this issue · comments

Terraform Version

Terraform v1.8.5
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v5.51.1
+ provider registry.terraform.io/hashicorp/external v2.3.3
+ provider registry.terraform.io/hashicorp/local v2.5.1
+ provider registry.terraform.io/hashicorp/null v3.2.2
+ provider registry.terraform.io/hashicorp/random v3.6.2
+ provider registry.terraform.io/hashicorp/tls v4.0.5

Terraform Configuration Files

output "lb_address_consul_nomad" {
  value = "http://${module.private-cloud.server_public_ip[0]}"
}

output "IP_Addresses" {
  value = <<CONFIGURATION

Server public IPs: ${join(", ", module.private-cloud.server_public_ip[*])}

The Nomad UI can be accessed at http://${module.private-cloud.server_public_ip[0]}:4646/ui

The Consul UI can be accessed at http://${module.private-cloud.server_public_ip[0]}:8500/ui
with the token: ${module.private-cloud.consul_token}

SSH into server: ssh -i state.d/${local.project_name}-www.pem ubuntu@${module.private-cloud.server_public_ip[0]}
CONFIGURATION
}

Debug Output

terraform -chdir=derived-src/aws/ plan -state=../../state.d/terraform.tfstate -replace "module.private-cloud.aws_instance.server[0]" -target module.private-cloud.aws_instance.server -out repl
module.private-cloud.tls_private_key.pk: Refreshing state... [id=5b9517df936d0171f12123b7583bddf7832bc9b1]
module.private-cloud.random_uuid.consul_token: Refreshing state... [id=6320f9a1-6811-8ad1-b03b-82dea8c58ed6]
data.external.env: Reading...
data.external.env: Read complete after 0s [id=-]
module.private-cloud.data.aws_iam_policy_document.ec2-assume-role-policy: Reading...
module.private-cloud.aws_key_pair.ssh: Refreshing state... [id=nomad-ssh-key-pair]
module.private-cloud.aws_vpc.main: Refreshing state... [id=vpc-0e4adf182c44593af]
module.private-cloud.data.aws_iam_policy_document.ec2-assume-role-policy: Read complete after 0s [id=2851119427]
module.private-cloud.aws_iam_role.www: Refreshing state... [id=nomad_www-role]
module.private-cloud.aws_iam_instance_profile.www: Refreshing state... [id=nomad_www-role]
module.private-cloud.aws_subnet.main_a: Refreshing state... [id=subnet-09c658aea6fa5d6ce]
module.private-cloud.aws_security_group.allow_all_internal: Refreshing state... [id=sg-039093a16ab4664ed]
module.private-cloud.aws_security_group.ssh_ingress: Refreshing state... [id=sg-013a3f6f07d8280c2]
module.private-cloud.aws_security_group.consul_nomad_ui_ingress: Refreshing state... [id=sg-01c924f86724bdcc2]
module.private-cloud.aws_instance.server[0]: Refreshing state... [id=i-03cd0bb9e5537a91f]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # module.private-cloud.aws_instance.server[0] will be replaced, as requested
-/+ resource "aws_instance" "server" {
      ~ ami                                  = "ami-0d8dbcc9f7eb71ca2" -> "ami-0621ea406987e54ce" # forces replacement
      ~ arn                                  = "arn:aws:ec2:us-west-2:315400321086:instance/i-03cd0bb9e5537a91f" -> (known after apply)
      ~ availability_zone                    = "us-west-2a" -> (known after apply)
      ~ cpu_core_count                       = 1 -> (known after apply)
      ~ cpu_threads_per_core                 = 1 -> (known after apply)
      ~ disable_api_stop                     = false -> (known after apply)
      ~ disable_api_termination              = false -> (known after apply)
      ~ ebs_optimized                        = false -> (known after apply)
      - hibernation                          = false -> null
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      ~ id                                   = "i-03cd0bb9e5537a91f" -> (known after apply)
      ~ instance_initiated_shutdown_behavior = "stop" -> (known after apply)
      + instance_lifecycle                   = (known after apply)
      ~ instance_state                       = "running" -> (known after apply)
      ~ ipv6_address_count                   = 0 -> (known after apply)
      ~ ipv6_addresses                       = [] -> (known after apply)
      ~ monitoring                           = false -> (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      ~ placement_partition_number           = 0 -> (known after apply)
      ~ primary_network_interface_id         = "eni-0df57bbebe62b8d9a" -> (known after apply)
      ~ private_dns                          = "ip-172-31-3-62.us-west-2.compute.internal" -> (known after apply)
      ~ private_ip                           = "172.31.3.62" -> (known after apply)
      ~ public_dns                           = "ec2-54-214-178-221.us-west-2.compute.amazonaws.com" -> (known after apply)
      ~ public_ip                            = "54.214.178.221" -> (known after apply)
      ~ secondary_private_ips                = [] -> (known after apply)
      ~ security_groups                      = [] -> (known after apply)
      + spot_instance_request_id             = (known after apply)
        tags                                 = {
            "ConsulAutoJoin" = "nomad-auto-join"
            "Name"           = "nomad-server-0"
            "NomadType"      = "server"
        }
      ~ tenancy                              = "default" -> (known after apply)
      ~ user_data                            = "a8d1e42fbeef9bdab0c53ade3e608cae5b240612" -> "d5b7f646ca5c667578121ab1dcd37ecada0d5477"
      + user_data_base64                     = (known after apply)
        # (10 unchanged attributes hidden)

      - capacity_reservation_specification {
          - capacity_reservation_preference = "open" -> null
        }

      - cpu_options {
          - core_count       = 1 -> null
          - threads_per_core = 1 -> null
            # (1 unchanged attribute hidden)
        }

      - credit_specification {
          - cpu_credits = "standard" -> null
        }

      - enclave_options {
          - enabled = false -> null
        }

      - maintenance_options {
          - auto_recovery = "default" -> null
        }

      ~ metadata_options {
          ~ http_put_response_hop_limit = 1 -> (known after apply)
          ~ http_tokens                 = "optional" -> (known after apply)
            # (3 unchanged attributes hidden)
        }

      - private_dns_name_options {
          - enable_resource_name_dns_a_record    = false -> null
          - enable_resource_name_dns_aaaa_record = false -> null
          - hostname_type                        = "ip-name" -> null
        }

      ~ root_block_device {
          ~ device_name           = "/dev/sda1" -> (known after apply)
          ~ encrypted             = false -> (known after apply)
          ~ iops                  = 100 -> (known after apply)
          + kms_key_id            = (known after apply)
          - tags                  = {} -> null
          ~ tags_all              = {
              - "Project" = "nomad"
            } -> (known after apply)
          ~ throughput            = 0 -> (known after apply)
          ~ volume_id             = "vol-022d872631d8c356f" -> (known after apply)
            # (3 unchanged attributes hidden)
        }
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Changes to Outputs:
  ~ lb_address_consul_nomad = "http://54.214.178.221" -> (known after apply)
╷
│ Warning: Resource targeting is in effect
│
│ You are creating a plan with the -target option, which means that the result of this plan may not
│ represent all of the changes requested by the current configuration.
│
│ The -target option is not for routine use, and is provided only for exceptional situations such as
│ recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an
│ error message.
╵

───────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: repl

To perform exactly these actions, run the following command to apply:
    terraform apply "repl"
kes@Eugens-MacBook-Pro nomad $ terraform -chdir=derived-src/aws/ apply -state=../../state.d/terraform.tfstate "repl"
module.private-cloud.aws_instance.server[0]: Destroying... [id=i-03cd0bb9e5537a91f]
module.private-cloud.aws_instance.server[0]: Still destroying... [id=i-03cd0bb9e5537a91f, 10s elapsed]
module.private-cloud.aws_instance.server[0]: Still destroying... [id=i-03cd0bb9e5537a91f, 20s elapsed]
module.private-cloud.aws_instance.server[0]: Still destroying... [id=i-03cd0bb9e5537a91f, 30s elapsed]
module.private-cloud.aws_instance.server[0]: Still destroying... [id=i-03cd0bb9e5537a91f, 40s elapsed]
module.private-cloud.aws_instance.server[0]: Still destroying... [id=i-03cd0bb9e5537a91f, 50s elapsed]
module.private-cloud.aws_instance.server[0]: Destruction complete after 51s
module.private-cloud.aws_instance.server[0]: Creating...
module.private-cloud.aws_instance.server[0]: Still creating... [10s elapsed]
module.private-cloud.aws_instance.server[0]: Still creating... [20s elapsed]
module.private-cloud.aws_instance.server[0]: Still creating... [30s elapsed]
module.private-cloud.aws_instance.server[0]: Creation complete after 33s [id=i-0bc2962e6d252bcf2]
╷
│ Warning: Applied changes may be incomplete
│
│ The plan was created with the -target option in effect, so some changes requested in the
│ configuration may have been ignored and the output values may not be fully updated. Run the following
│ command to verify that no other changes are pending:
│     terraform plan
│
│ Note that the -target option is not suitable for routine use, and is provided only for exceptional
│ situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use
│ it as part of an error message.
╵

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

Outputs:

IP_Addresses = <<EOT

Server public IPs: 54.214.178.221

The Nomad UI can be accessed at http://54.214.178.221:4646/ui

The Consul UI can be accessed at http://54.214.178.221:8500/ui
with the token: *

SSH into server: ssh -i state.d/nomad-www.pem ubuntu@54.214.178.221
EOT

lb_address_consul_nomad = "http://35.89.231.151"

Expected Behavior

The output for IP_Addresses should be updated as it was done for lb_address_consul_nomad because both sections refers to the IP as ${module.private-cloud.server_public_ip[0]}.

Actual Behavior

The output was not updated.

You can see that changes to lb_address_consul_nomad are planned, but changes to IP_Addresses are not:

Changes to Outputs:
  ~ lb_address_consul_nomad = "http://54.214.178.221" -> (known after apply)

Steps to Reproduce

  1. terraform -chdir=derived-src/aws/ plan -state=../../state.d/terraform.tfstate -replace "module.private-cloud.aws_instance.server[0]" -target module.private-cloud.aws_instance.server -out repl
  2. terraform -chdir=derived-src/aws/ apply -state=../../state.d/terraform.tfstate "repl"

Additional Context

No response

References

No response

Duplicate of #29108

@jbardin Yes, it is related, but the interesting part here is that the one output variable is updated property, but the second does not.

Outputs aren't technically part of the -target since they are not a dependency of the targeted resource, but since outputs themselves can't be targeted, terraform makes an attempt at updating the outputs for convenience. The heuristic is that if a root module output can be entirely derived from the targeted resources, then we attempt to update it. If the output has any dependency on resources which were not targeted, then we can't be sure the new value is correct, so the old value is retained.

Since there's no way to know if re-evaluating IP_Addresses will produce a correct result, Terraform opts to not make the change at all. Maybe the old value of module.private-cloud.consul_token is invalid with a change to module.private-cloud.server_public_ip, or maybe it's fine, but Terraform has no way to make that determination. This is why -target includes in the warning: ... the output values may not be fully updated.

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.