heroku/terraform-provider-heroku

Newly added `config_vars` should show a realistic diff if they already exist

mmrobins opened this issue ยท 10 comments

Currently config_vars don't show an accurate diff until after the first terraform apply has run with those config_vars set. This makes it very tedious to import apps with lots of config_vars into terraform since you have to manually inspect to make sure you're not accidentally changing things on your first apply run.

The same applies to sensitive_config_vars, mainly in that they shouldn't show a diff (by diff I mean mention that it's changing something when it's not since it doesn't show the actual diff) if there isn't a change when you're adding them.

Terraform Version

Terraform v0.12.20

Heroku Provider Version

+ provider.heroku v2.1.2

Affected Resource(s)

  • heroku_app

Terraform Configuration Files

resource "heroku_app" "app" {
  name   = var.app_name
  region = data.heroku_space.default.region
  space  = data.heroku_space.default.name
  acm    = false
  internal_routing = var.internal_routing
  organization {
    locked = false
    name = var.heroku_team_name
    personal = false
  }
  config_vars = [
    EXISTING_CONFIG_VAR = "Hopefully the same value but you can't tell"
  ]
}

Expected Behavior

When I run terraform plan I expect it to show no changes since the EXISTING_CONFIG_VAR I'm setting is the same as is already in the all_config_vars value in the state file.

Actual Behavior

It shows that there's going to be a change

  # module.my_module_app_name.heroku_app.app will be updated in-place
  ~ resource "heroku_app" "app" {
...
      ~ config_vars           = {
          + "EXISTING_CONFIG_VAR"            = "Hopefully the same value but you can't tell"
        }
...
Plan: 0 to add, 1 to change, 0 to destroy.

Steps to Reproduce

  1. terraform plan or terraform apply with a newly added config var in your tf files that already exists in the actual heroku app

Just to confirm, is your workflow the following:

  1. Import a heroku_app resource with either config_vars & sensitive_config_vars.
  2. Execute a terraform plan|apply, which shows a plan diff that terraform wants to create those vars again?

If so, does your state file have config_vars & sensitive_config_vars properly set post import?

Correct on the workflow

And yes, the state file does not have config_vars and sensitive_config_vars set correctly post import

I've found 2 super hacky ways of getting a decent diff

1

  1. terraform state pull > state.json
  2. increment the serial value in state.json
  3. Manually edit state.json with the proper keys for config_vars with any values so that it'll recognize a diff on next plan. Note it populates the config_vars values correctly on the next plan run once the right keys are in the config_vars section of the state, so it'll show the proper diff no matter what I put in the values when I manually modify the state file.
  4. terraform state push state.json
  5. terraform plan now shows a diff if I change things, or no diff if I matched the existing value, instead of showing it's creating the config_var

2

  1. make build this commit mmrobins@f408db6
  2. copy provider in for local use per the README https://github.com/terraform-providers/terraform-provider-heroku/blob/master/README.md#using-the-provider
  3. terraform plan now shows a diff of all config vars

Method 1 I've tried running terraform apply after checking out the diff, and it's fine. Method 2 I haven't run terraform apply after doing the diff because I don't really understand my hacky code modification enough to predict what will happen.

Gotcha. That's no good if the import on heroku_app isn't probably setting config_vars and sensitive_config_vars. This is why you're seeing a diff when you plan or apply. Luckily, Heroku API essentially will do nothing if you trying to add a config var that's already set on the target app.

mmrobins@f408db6 would set all of a config vars under heroku_app.config_vars. This would include any variables a user defined in heroku_app.sensitive_config_vars, thereby rendering sensitive_config_vars ineffective in preventing any 'sensitive' config vars like SOME_PRIVATE_API_TOKEN from being plaintexted in a CI system.

For background, Heroku doesn't differentiate between sensitive and non-sensitive config vars. We added this difference into the provider so that users have a bit more flexibility in managing their config vars in a CI system. Marking heroku_app.config_vars sensitive when the provider didn't have heroku_app.sensitive_config_vars would have masked every config vars during a plan|apply, which could hamper other users from determining if say RAILS_ENV will be the desired value.

Let me take a look at why the import isn't working properly for this resource. Once that is solved, your workflow shouldn't have any further issues.

I would really like to see this work too ๐Ÿ‘I wonder if the tricky part will be making it work smoothly with heroku_app_config_association etc.

mars commented

Note that config vars set by attached Heroku Addons should be ignored from Terraform state. They change dynamically (such as periodic Postgres credential rotation). IMO Inverting the ownership of their state to Terraform will confuse things.

While I believe that App import can be fixed to capture existing config variables, it will probably be a bit complicated to filter out Addons.

Yeah agreed that would really confuse things.

Could we make it work so that the import only pulls in config vars that are defined in the terraform config, and ignores the rest?

Could we make it work so that the import only pulls in config vars that are defined in the terraform config, and ignores the rest?

Yep, that was the original intent.

I would really like to see this work too ๐Ÿ‘I wonder if the tricky part will be making it work smoothly with heroku_app_config_association etc.

@bensymonds Is your statement above saying you're trying to manage the same config vars using heroku_app.config_vars and heroku_app_config_association.config_vars?

@davidji99 No. I was just thinking given there are two ways to specify config vars (directly in the heroku_app resource, or via a heroku_app_config_association resource) it might complicate things. I didn't think about it any further than that - it might not be complicated at all.

@davidji99 No. I was just thinking given there are two ways to specify config vars (directly in the heroku_app resource, or via a heroku_app_config_association resource) it might complicate things. I didn't think about it any further than that - it might not be complicated at all.

Ah gotcha. It won't be complicated so long as one doesn't manage the same config vars on both resources. Otherwise, you'll get an infinite plan loop.

For heroku_app.config_vars & heroku_app.sensitive_config_vars, the provider compares what the user has defined in both attributes with all of the config vars returned by the API to make sure each attribute's values exist remotely before setting them in state. Since the Heroku Platform API has no distinction of config var sensitivity, we need to do this comparison before setting these attributes in state.

However during a terraform resource importation, the provider SDK does not have access to the resource's schema so the comparison does not work and nothing is set in state. I've reached out to Hashicorp to see if there is a solution.

FYI, what I described above is why heroku_app_config_association does not allow imports.