Refresh state after "apply", recommendations/best practices

Hi,

I’m learning Terraform and was wondering are there best practices/recommendations for refreshing state after applying some changes?

For example, I have an example configuration that spins up a small cluster of EC2 instances and there are all the usual parts: VPC, sec. group, default routing table, Internet gateway, instances and EIPs associated with them, keypair to SSH into instances, etc.

Executing terraform apply for the first time works fine, everything is up and configured, all is well. However, if I run terraform plan without making any changes to the config, there will be configuration drift detected.

For example, I use aws_instance and aws_eip resources to spin up instances and attach EIPs to them. Running terraform plan right after the initial terraform apply, I’ll get something like:

  ~ resource "aws_instance" "node" {
      ~ associate_public_ip_address          = false -> true
        id                                   = "i-XXXXXXXXXXXXXX"
      + public_ip                            = "X.Y.Z.W"
        tags                                 = {
            "Name" = "example"
        }
        # (26 unchanged attributes hidden)

        # (5 unchanged blocks hidden)
    }

Some resources will report some optional attributes to have changed (with default values). For example, aws_key_pair and aws_default_route_table:

  ~ resource "aws_key_pair" "deployer" {
        id          = "deployer key"
      + tags        = {}
        # (6 unchanged attributes hidden)
    }

  # module.discovery.module.network.aws_default_route_table.discovery has changed
  ~ resource "aws_default_route_table" "example" {
        id                     = "rtb-XXXXXXXXXXXXXXXXXX"
      + propagating_vgws       = []
        tags                   = {
            "Name" = "test route table"
        }
        # (6 unchanged attributes hidden)
    }

Other examples are icmp_code and icmp_type attributes on aws_default_network_acl.ingress/egress. I can work around this by specifying the defaults in my configuration, but it feels a bit silly having to specify some optional attributes with their defaults just to achieve state idempotency.

I understand that some resources’ states change after applying other bits of configuration (e.g. aws_instance and aws_eip), but would it make sense for terraform to automatically refresh state after running apply in order for the state file to reflect actual post-apply state? Or are there reasons for not doing this?

Thank you!

Hi @bozho,

Each of the examples you gave here seems to show what is technically a bug in the provider: it should’ve returned those values when originally planning the change and when returning the “apply” result to Terraform.

Since the provider also presumably contains logic to e.g. treat an empty map the same as an unspecified map, it ends up just being noise in the subsequent plan as you saw here, rather than a more significant problem, but I do understand that it’s annoying even though it’s only cosmetic, because it means you need to carefully study the plan to see which changes are material and which aren’t.

Immediately refreshing after applying any change would indeed work around these provider quirks, but does come at the risk of also potentially incorporating changes that are not just cosmetic, and so I’d suggest caution in doing that. If you are running Terraform in automation and thus you can make the time window between the successful apply and the subsequent refresh as small as possible then it might be a reasonable tradeoff, since it would be unlikely (but still not impossible) that some actual drift could occur during that small interval.

Hi @apparentlymart,

Thank you for the reply. Would it make sense to open GitHub issues for these?

What about updating public_ip in aws_instance resource after attaching an EIP on the initial apply run? Is something like that even possible to be implemented in a provider, for a resource to update state of a related resource?

Hi @bozho,

Indeed, the design of the EC2 API is awkward in that case from Terraform’s perspective, because creating one object changes the settings of another and thus it doesn’t fit well into Terraform’s resource lifecycle. That’s a quirk that’s been there since the very early days of the AWS provider (since aws_instance and aws_eip were some of the earliest resource types) and so it stuck around because it wasn’t clear how to change it without significantly redesigning those two resource types. That one is represented by AWS provider issue #31.

For the other ones where the provider reports the default value for an unspecified “too late” I believe the provider teams are broadly aware of these quirks but are planning to address them more systematically by switching to the new Terraform plugin framework , which makes it easier for provider developers to handle these situations more robustly than the older SDK which relies more on hand-written provider logic to handle these situations. Therefore I think opening individual GitHub issues for each case would be frustrating for the provider maintainers.