About Terraform upgrade from v0.12 to 1.x

Hi experts,

We are planning to upgrade our terraform version from v0.12 to 1.x. We have tons of terraform configs so we cannot guarantee that terraform plan show no diff. Here is our upgrade plan:

Upgrade path 0.12 —apply----> v0.13 ----- v0.14 plan succeed → v1.3

We mainly have 3 concerns/questions

  1. Considering the number of configs we have (2000+). We cannot guarantee that TF plans show no proposed changes. Can we run 2 plans: one with current terraform version, one with next terraform version. We Make sure those 2 plans are same and then we say we are good to apply. Hence we will apply some changes during TF upgrade apply.

  2. If we take the above strategy, what if the apply fail? Any concern for the rollback? (Considering there is no syntax change, we think rollback should just work)

  3. For those old syntax removed in v0.15, is there any good tool to detect or fix them ? As far as I know, terraform fmt will only fix some interpolation string issue. But for map/tomap, string/tostring, and lifecycle { ignore_changes = [“*”]}, we can only find it from terraform plan/validate. Is that correct?

Thanks a lot for your help!

Hi @tzyhuster ,

From personal exp:

  1. you can ran plan with old and new version. It will not change backend state unless you explicitly specify --refresh-only
  2. If apply will fail it will not write changes to state (but better just to keep states separated with terragrunt and enable versioning).
  3. If there some incompatibility between versions or version and provider the earliest way is to run validate and plan

Regards,
Serhii

Hi @chell0veck!

Thanks for sharing that information. It is broadly correct but I wanted to add a caveat to one of your statements just because there is an additional risk you didn’t mention:

It’s best to assume that terraform apply can always potentially create a new state snapshot. You are right that if Terraform encounters an error before making any changes then it won’t have any new information to save and so will skip writing a new snapshot, but if Terraform was able to successfully change something before encountering an error with some other action then it will still need to save the outcome of the first action and so it will still create a new state snapshot to capture that.

Terraform v0.12 cannot read state snapshots created by later versions, so this is unfortunately a “one way door” where rolling back would require restoring the old state snapshot from a backup, and thus potentially losing the record of what changed during the upgrade. This is one reason why we recommend getting your configurations all converged (no pending changes) before upgrading: that way the consequences of actions such as restoring state from backup are less consequential than if you were simultaneously making infrastructure changes as the same time as upgrading.

@apparentlymart @chell0veck

Thanks for both of your reply. Those replies are really helpful.

1 more questions regarding TF upgrade from 0.12 to 0.13:

When we talk about rollback, there are 2 scenarios:

  1. One scenario is roll back to use 0.12. In this case, you can do it only if you have 0 pending changes in Terraform plan during upgrade. Otherwise, some of your applied changes will be lost from state file.

  2. Another scenario is to roll back to a previous version of terraform config
    Suppose I have a git repo which stores our terraform config files.

  1. I applied commit A with TF v0.12 successfully
  2. I did plan with commit B with TF v0.13 successfully (pending changes showed up)
  3. I did apply with commit B and apply failed because of error. One new resources failed to create, other resources were added/changed successfully.

In this case, we should be ok right? v0.12 and v0.13 has no syntax change. We can just fix the issue and apply with v0.13.

We went through the same thing just last year. In my opinion the safest way to perform this upgrade is to force a state change without introducing any new resource or changes to existing resource. You can do that easily with null_resource:

resource "null_resource" "tf_upgrade" {
  triggers = {
    tf_upgrade = true
  }
}

Once you are at version 0.13.*, you can then remove the null_resource, re-plan with the 1.* version, and work out any sort of syntax changes then.