In Terraform I want to spin up a node for_each of these, using variable variables or variable interpolation but I can’t get it working. I get the error:
Error: Invalid character
on droplets.tf line 23, in resource “digitalocean_droplet” “droplets”:
23: image = “{var.{each.value}_DIGITALOCEAN_NAME}”
This character is not used within the language.
I think best way to do this is to use a map data structure for your input variables so that you can look up the values you need dynamically by key, like this:
variable "digitalocean" {
type = map(object({
name = string
size = number
}))
}
resource "digitalocean_droplet" "droplets" {
for_each = var.digitalocean
name = each.key
image = each.value.name
size = each.value.size
}
You can then set this variable to define both the node names and their associated attributes at once:
If the MANAGER and WORKER node names should not be customizable by the end-user, you can get there by using a more restrictive type for the variable that forces setting both of those:
variable "digitalocean" {
type = object({
MANAGER = object({
name = string
size = number
})
WORKER = object({
name = string
size = number
})
})
}
With the type constraint above, Terraform will return an error if the caller doesn’t provider both MANAGER and WORKER objects. To use this object-typed variable with for_each might require an explicit conversion to map, though:
Terraform cannot directly read variable values from environment variables so I assume there must be something outside of Terraform making those values be set. If you could adjust that to map the environment variables to Terraform in a different way then that would be one way to do it.
Another option, if you can’t control how those variables are being passed to Terraform, would be to build that mapping inside Terraform itself, like this:
variable "MANAGER_DIGITALOCEAN_NAME" {
type = string
}
variable "MANAGER_DIGITALOCEAN_SIZE" {
type = number
}
variable "WORKER_DIGITALOCEAN_NAME" {
type = string
}
variable "WORKER_DIGITALOCEAN_SIZE" {
type = number
}
locals {
digitalocean = tomap({
MANAGER = {
name = var.MANAGER_DIGITALOCEAN_NAME
size = var.MANAGER_DIGITALOCEAN_SIZE
}
WORKER = {
name = var.WORKER_DIGITALOCEAN_NAME
size = var.WORKER_DIGITALOCEAN_SIZE
}
})
}
Now you can follow the same principle as what I suggested before but you’d use local.digitalocean instead of var.digitalocean because this is now a local value rather than an input variable.