1

Ooookay... This one is driving me insane. I've worked with AWS CloudFormation for a while now, and I've recently been tasked with 'converting' (or adapting) something I've created into a Terraform variant, ultimately to do the same thing (reasons).

For the most part, I'm getting along okay. But... I've come to my AWS_Instance section, which I was dreading in advance due to what I've learned about Terraform, and I'm completely and utterly stuck. I feel like I'm close, but I just cannot get it to work entirely, and so regarding the below; Thank you in advance for any help and suggestions!

The issue: I have an AWS instance to create - Depending on the users request, it will have X EBS storage devices attached to it. Either 2, 4, or none (let's say). In AWS CF, I simply do a condition via an IF statement; IF 2 then create A and B; ELIF 4 then create A, B, C and D, ELSE do nothing. Simple. In Terraform, I'm finding it VERY difficult to do that same simplicity. What I have so far is the following:

variable "test_list" {
  type = list
  default = [ "b", "c" ]
}

resource "aws_instance" "tf_instance" {
  #...#
  dynamic "ebs_block_device" {
    for_each = var.test_list
    content {
      device_name = "/dev/sd${ebs_block_device.value}"
      delete_on_termination = "true"
      volume_size = "2000"
      volume_type = "st1"
      encrypted = "${local.Instance_Encryption}"
    }
  }
}

This does create an instance with 2 attached disks (b and c) which is a step in the right direction, but the problem is that I cannot find a way to add in a conditional into that FOR_EACH step. I want to be able to have it create those 2 OR do nothing. I tried the following, but it errors out:

for_each = local.Single-Node ? [ var.test_list_2 ] : [ null ]

Potentially I'm just using it incorrectly (only been using Terraform for a few days, so some of my understanding is wrong for sure). Any help with this is highly appreciated, as I feel what I'm trying to do is a very basic thing [if this else do nothing] but I've scoured the internet to no avail!

1
  • You did not display your error message, but if I had to guess what went wrong, it is probably because you did a list(null) type. You probably actually wanted an empty list i.e. [] instead. If not, then please share your error message and other relevant information. Commented May 4, 2021 at 15:23

1 Answer 1

3

Focusing on your framing of the problem as making a decision based on a number, I think I'd approach this by making a lookup table for each valid number, like this:

variable "block_device_count" {
  type = number
}

locals {
  block_device_letters_by_count = {
    2 = ["a", "b"]
    4 = ["a", "b", "c", "d"]
  }
  block_device_letters = try(local.block_device_letters_by_count[var.block_device_count], [])
}

This is using a map lookup to achieve a similar result to your previous IF, ELSEIF, ELSE approach. The try here is acting as the "ELSE do nothing" part: if there's no element in the map matching var.block_device_count then it'll use an empty list as a fallback result.

Now local.block_device_letters is of a suitable shape to use with a dynamic block, so we can use it in a similar way as you showed in your example:

resource "aws_instance" "tf_instance" {
  #...#
  dynamic "ebs_block_device" {
    for_each = local.block_device_letters
    content {
      device_name = "/dev/sd${ebs_block_device.value}"
      delete_on_termination = "true"
      volume_size = "2000"
      volume_type = "st1"
      encrypted = "${local.Instance_Encryption}"
    }
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Martin Atkins, you legend of a man, this is the second time you have saved me with one annoying headache of a problem. Thank you, good sir!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.