How to overwrite variables?

I’m working on a project with the following structure :

environments
|----development
|.            |_ main.tf
|.            |_ provider.tf
|
Stack
|----public
|.         |_ stack.tf
|.         |_ variables.tf
|
Modules
|----redis
|.       |_ redis.tf
|.       |_ variables.tf

You can see that there’s a variables.tf file on both Modules and Stacks folder, this file contains a redis variable.

variable "redis" {
    type = map(string)
    default = { }
}

The way we would like this to work is - value is added to the environment and if there is no value the stack then adds a default value. These values ​​will lastly be added to the module when executing the terraform plan.

The problem is that when running terraform plan, we’re getting a missing map element error because when I add a value in the environment (engine, engine Version or Node types) and execute a plan, the terraform presents an error stating that the values ​​not added must be added.

│ Error: Missing map element
│ 
│   on ../../modules/redis/redis.tf line 42, in resource "aws_elasticache_parameter_group" "custom_parameter_group":
│   42:     name   = var.redis.parameter_group_name
│     ├────────────────
│     │ var.redis is map of string with 1 element
│ 
│ This map does not have an element with the key "parameter_group_name".
╵

So the question is, how do I use standard attributes at the Stacks level and, if necessary, modify a certain attribute at the environment level?

Hi @gabrielpulga98,

There are two main ways to deal with map entries that might or might not be set.

The first and most direct way is to use the try function to provide a default value for that particular setting at the point of use:

  name = try(var.redis.parameter_group_name, "fallback value")

That style is best suited for situations where the fallback is situational, and thus it makes sense to inline it directly in the expression defining the name argument here.

The other way is to use the merge function to construct a new map which has the non-overlapping elements from two maps and prefers later arguments when two maps have overlapping keys. In this case you’ll often be using the result in many places, so it’s helpful to define a local value to factor out that common result to use in many places:

locals {
  default_redis = tomap({
    parameter_group_name = "fallback value"
  })
  redis = merge(
    local.default_redis,
    var.redis,
  )
}

With those definitions in place, you can use local.redis instead of var.redis to get the derived result:

  name = local.redis.parameter_group_name