terraform

Read key/value file and update the value of a specific key


Using Terraform, I'm trying to read key/value pairs from an external file, update one of the values, and use the resulting data as an input into a resource.

I can successfully read key/value pairs from the external file, but I'm having difficulty in updating the required value.

My exact scenario is that I have multiple deployments with the same S3 backend, but a different key, and I need to reference the output of one of these deployments as an input in another using the terraform_remote_state resource.

For example, if my file ./backend/myenv.tfbackend contained the following...

bucket = "mybucket"
key    = "path/to/my/key"
region = "us-east-1"

I'd like for a local variable called backend_conf_other to contain the following object, where key has been updated:

{
  bucket = "mybucket"
  key    = "path/to/another/key"
  region = "us-east-1"
}

So far I have the following. How can I amend this code so that the value of local.backend_conf_other is as described above?

variable "other_key" {
  type    = string
  default = "path/to/another/key"
}


data "local_file" "backend_conf" {
  filename = "./backend/myenv.tfbackend"
}

locals {
  backend_conf_other = {
    for key, value in data.local_file.backend_conf.content :
      key => key == "key" ? value : var.other_key
  }
}

data "terraform_remote_state" "other_state" {
  backend = "s3"
  config  = local.backend_conf_other
}

Solution

  • The easiest path forward here is to use the merge function to overwrite key-value pairs in your map and return a new map to be assigned to the local variable:

    locals {
      backend_conf_other = merge(jsondecode(data.local_file.backend_conf.content), { "key" = "path/to/another/key" })
    }
    

    Note the following from the documentation:

    If more than one given map or object defines the same key or attribute, then the one that is later in the argument sequence takes precedence.

    Additionally the file needs to be converted to a format which can be decoded by Terraform with a native function. This answer selects JSON arbitrarily. The file content would then need to appear like:

    {
      "bucket": "mybucket",
      "key": "path/to/my/key",
      "region": "us-east-1"
    }