46

Is there a way to write a conditional statement with multiple branches in terraform?

I'm setting up a terraform module to create an Amazon Aurora cluster. I need to have an option for cross region replication so I need to decide the region of the replica in relation to the source region.

hertzsprung
  • 9,445
  • 4
  • 42
  • 77
ConscriptMR
  • 656
  • 1
  • 7
  • 16

6 Answers6

59

This is one way using the coalesce() function:

locals{
  prod = "${var.environment == "PROD" ? "east" : ""}"
  prod2 = "${var.environment == "PROD2" ? "west2" : ""}"
  nonprod = "${var.environment != "PROD" && var.environment != "PROD2" ? "west" : ""}"
  region = "${coalesce(local.prod,local.prod2, local.nonprod)}"
}
victor m
  • 2,012
  • 2
  • 14
  • 23
  • Definitely the way to go, for more details I found this helpful too https://ataiva.com/how-to-write-if-else-statements-in-terraform/ – AO_ Mar 27 '23 at 12:30
28
locals {
  test = "${ condition ? value : (elif-condition ? elif-value : else-value)}"
}

For a more literal "if-elif-else" approach you can embed the if short hand with other ones to produce a similar effect. If you're use case is also inside a for loop, you can do that as well:

locals {
  test = {
    for i in list : 
      key => "${ condition ? value : (elif-condition ? elif-value : else-value)}"
  }
}

Will work in any situation where you would use the "${}" syntax

MrJ1m0thy
  • 457
  • 4
  • 8
16

You could try just using a map and lookup. Example:

/* In your variables.tf */
variable "region_mapping" {
  description = "mapping for cross-region replication"
  default = {
    "us-east-1" = "us-east-2",
    "us-west-1" = "us-west-2"
  }
}

/* Then create use lookup to get the replication region from the deployment region */
resource "example" "example" {
  region = "${lookup(var.region_mapping, var.region)}"
}

If var.region is where you have your current cluster deployed and its value is for example us-east-1, then the lookup will return us-east-2 as the region you should be deploying your replica.

Adjust this to your needs.

Esteban Garcia
  • 2,171
  • 16
  • 24
  • 1
    This helps, I end up using list instead of map which I need count.index to find the value, thanks @Esteban Garcia – zqcolor Mar 18 '20 at 19:36
9

From terraform 0.12, you can fake a switch by using maps, e.g.

locals {
  environments = {
    prod = "east",
    prod2 = "west2"
  }
  
  region = lookup(environment_region, lower(var.environment), "west")
}

Advantage of this is if the result is more complex you can return objects/lists from the map, rather than simple strings.

For example, I have a centralized naming module that composes name according to different rules based on the resource type etc.

locals {
  parts_map = {
    # NB Location should always be last to ensure geo-separation of names
    prefix = [ local.type.code, var.name, var.role, var.environment, module.location.code ]
    suffix = [ var.name, var.role, var.environment, local.type.code, module.location.code ]
    mode3  = [ var.name, local.type.code, var.role, var.environment, module.location.code ]
}

parts = compact(local.parts_map[local.type.order])
Paul Hatcher
  • 7,342
  • 1
  • 54
  • 51
8

I was dealing with this for several hours trying to create the array to achieve my requirement. Based on the answer from @MrJ1m0thy I create this ternary with multiple options that emulates if / elseif / else:

conditioning_a != "condition_a" ? "value1" : (conditioning_b == "condition_b" ? "value_b" : (conditioning_c == "condition_c" ? "value_c" : (conditioning_d == "condition_d" ? "value_d" : "value2")))
2

There is no such thing as if / elseif / else in Terraform < 0.12

However, you can use classic boolean logic in Terrafom Conditions

Quentin Revel
  • 1,400
  • 8
  • 11