Terraform Cloud & Terraform local with a for_each inconsistency

I have a problem with inconsistency between how Terraform locally on my laptop and Terraform Cloud works when using a for_each.

The setup is I would like to use one resource (in this case a azurerm_subnet) to deploy multiple resources. As you will see from the code below I have a map variable defined and then using an each.value.xxx to populate the attribute. When using a local tfvars file this works perfectly.

image

When running this code locally with an Apply (terraform apply -var-file .\variables.tfvars) it is successful :blush::

Now for the problem!

When running this from Terraform Cloud (same code but using the Cloud Variables over a tfvars file) it is never successful :frowning: - I have tried many different ways of expressing the variable but none have worked:

Am I missing something here, should this be possible but just isn’t, or, it’s not possible, are here any suggestions on alternatives?

Any help, guidance you’re able to offer would be a massive help!

Thanks, Joe

Hi @BuildingYourCloud,

The “Variables” UI in the Terraform Cloud workspace settings is essentially a GUI for building a .tfvars file from parts. Specifically, Terraform Cloud will use the information you enter into that form to generate a terraform.tfvars file and write it into the working directory, and then Terraform CLI will find that file and parse it in the same way as it would locally.

However, because Terraform Cloud is constructing the file from parts rather than just taking your input verbatim you need to structure it a little differently. If we look at the snippet in your screenshot we can see a couple of problems in what Terraform Cloud generated:

subnets = "subnet1 = {\n        name = \"subnet1\"\n        range = \"10.20.0.0/8\"\n    }"

(I shortened the input to just one definition here because that’s enough to see the two problems I’m about to describe, but your screenshot does show it including the subnet2 element also.)

Firstly, Terraform Cloud has interpreted what you entered as a literal string value, and so it’s written it out in quotes here. Terraform then correctly complained that it’s not of the correct type. To generate values of types other than string you must check the “HCL” checkbox to the right of the entry box, in which case Terraform Cloud will use your Value verbatim as the expression assigned to that variable, rather than turning it into a quoted string.

After doing that, Terraform Cloud would generate a terraform.tfvars something like the following:

subnets = subnet1 = {
  name = "subnet1"
  range = "10.20.0.0/8"
}
subnet2 = {
  name = "subnet2"
  range = "10.21.0.0/8"
}

Notice that this doesn’t match the .tfvars file you wrote locally, and has invalid syntax: the value you wrote into the Value box isn’t a valid, self-contained Terraform expression.

To fix that, you should add braces around the definitions so that the Value field contains a valid map/object constructor expression:

{
  subnet1 = {
    name = "subnet1"
    range = "10.20.0.0/8"
  }
  subnet2 = {
    name = "subnet2"
    range = "10.21.0.0/8"
  }
}

With the above, Terraform Cloud will generate a terraform.tfvars file like this:

subnets = {
  subnet1 = {
    name = "subnet1"
    range = "10.20.0.0/8"
  }
  subnet2 = {
    name = "subnet2"
    range = "10.21.0.0/8"
  }
}

…and that now matches the structure of your hand-written .tfvars file that worked locally, and so it should work in Terraform Cloud too.

If this isn’t a value that you need to manage through the Cloud UI or API then an alternative would be to rename your variables file to variables.auto.tfvars and include it in your working directory when you send the changes to Terraform Cloud. Terraform CLI automatically loads any files with the suffix .auto.tfvars in the current working directory, and so Terraform CLI running in Terraform Cloud should still find those and use them in addition to its own generated terraform.tfvars file. You could then leave this particular argument unset in the web UI and use the .auto.tfvars file as the definition of it instead.

1 Like

Thanks so much @apparentlymart , you’re awesome! I had tried each of the steps (HCL and the {}) individually but clearly not at the same time - doing both of these things fixed it.

Also really interesting to learn about .auto.tfvars - I wasn’t aware of that.

Thanks again! Have a great rest of the week.