Dave Michaels
Dave Michaels

Reputation: 937

Terraform conditional specifying certain text

In Terraform I am trying to come up with a conditional that is searching for specific keys to perform an action later on. Below is an example of the map variable I have defined. What I'm trying to do is have Terraform "filter" out certain keys and do certain actions. Any advice how this can be accomplished would be helpful.

variable "volumes" {
 type = map(object({
    size              = string
    availability_zone = string
  }))
  default = {
    "Primary" = {
      size              = "200"
      availability_zone = "us-west-2a"
    }
    "PrimarySecondary" = {
      size              = "100"
      availability_zone = "us-west-2a"
    }
    "Worker1" = {
      size              = "200"
      availability_zone = "us-west-2b"
    }
    "Worker1Secondary" = {
      size              = "100"
      availability_zone = "us-west-2b"
    }
    "Worker2" = {
      size              = "200"
      availability_zone = "us-west-2c"
    }
    "Worker2Secondary" = {
      size              = "100"
      availability_zone = "us-west-2c"
    }
  }
}

resource "aws_ebs_volume" "partition" {
  for_each          = var.volumes
  availability_zone = each.value.availability_zone
  size              = each.value.size

  tags = {
    Name = each.key
  }
}

resource "aws_volume_attachment" "ebs_att" {
  for_each    = aws_ebs_volume.partition
  device_name = each.key == ("Primary" || "Worker1" || "Worker2") ? "/dev/sdf" : "/dev/sdg"
  volume_id   = each.value.id
  instance_id = aws_instance.private[each.key].id
}

Error

Error: Invalid operand

  on vpc.tf line 49, in resource "aws_volume_attachment" "ebs_att":
  49:   device_name = each.key == ("Primary" || "Worker1" || "Worker2") ? "/dev/sdf" : "/dev/sdg"

Unsuitable value for right operand: a bool is required.

Upvotes: 0

Views: 4045

Answers (1)

Martin Atkins
Martin Atkins

Reputation: 74789

The expression "Primary" || "Worker1" || "Worker2" here is being rejected by Terraform because || is the boolean OR operator, which can only be used with boolean values, not strings.

It looks like your intent here was to say "if each.key is one of these values", in which case one way to do that would be to use the contains function:

  device_name = contains(["Primary", "Worker1", "Worker2"], each.key) ? "/dev/sdf" : "/dev/sdg"

Another option I would consider is to create a local value with a map showing the device name for each key, like this:

locals {
  volume_device_names = {
    Primary = "/dev/sdf"
    Worker1 = "/dev/sdf"
    Worker2 = "/dev/sdf"
    PrimarySecondary = "/dev/sdg"
    Worker1Secondary = "/dev/sdg"
    Worker2Secondary = "/dev/sdg"
  }
}

Then your conditional expression can become a map lookup:

  device_name = local.volume_device_names[each.key]

This has some different tradeoffs, which may or may not be advantages depending on your needs:

  • If the caller specifies an unexpected key name in the variable value then the first example will just default to /dev/sdg, while the second example will produce a map lookup error. If your set of valid keys is a fixed set then returning an error could be helpful if the caller accidentally makes a typo.
  • In the first example, the rule for selecting a device name for a volume key is embedded inline in the aws_ebs_volume_attachment resource configuration, which means we can look at that resource name and understand directly how it will choose one. However, that means the rules are "further away" (from the perspective of someone reading the module) from the definition of variable "volumes", which may make it harder to see that the keys of that map are significant in deciding how a device gets attached. Factoring it out into a locals block means it could be placed adjacent to the variable "volumes" block so it's easier to find for someone reading the definition of that variable.

There are some other variants that strike different compromises between these two, but this answer is already long enough so I'll leave those as an exercise unless you have a specific question about it.

Upvotes: 2

Related Questions