-1

Is it possible to create resource contents conditionally in terraform?

Let's say I want the default_action for this aws_lb_listener to be have "type" set to "forward" if "default" variable is set to 1; otherwise, set "type" to "fixed-response" and add additional "fixed_response" part like below:

resource "aws_lb_listener" "listener_https" {
  load_balancer_arn = aws_lb.lb.arn
  certificate_arn   = aws_acm_certificate.certificate.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"

  default_action {
     if var.default == 1 { # pseudocode, does not work with terraform!
        target_group_arn = aws_lb_target_group.tg.arn
        type             = "forward"

     } else { # pseudocode, does not work with terraform!
        type  = "fixed-response"

        fixed_response {
            content_type = "text/plain"
            message_body = "not found"
            status_code  = "404"
        }
     }
  }        
}
Tomasz
  • 179
  • 12
  • You can create two resources: one if `var.default == 1` and another otherwise. They will never coexist. To define a resource existence conditionally, you can use [this Q](https://stackoverflow.com/questions/60231309/terraform-conditional-creation-of-a-resource-based-on-a-variable-in-tfvars) for reference. To define conditional blocks, read [this](https://developer.hashicorp.com/terraform/language/expressions/dynamic-blocks) - you can pick either solution depending on how much do these resources differ. – STerliakov May 11 '23 at 22:34
  • Resource existence conditionally - it leads to a lot of code duplication in this case. This resource will exist always - but "default_action" block in it will differ depending on the variable set. So I'd have to repeat load_balancer_arn, port, protocol, ssl_policy, tags, timeouts etc. over and over again (there will be more than just 2 cases). While it will work, I don't really like this way. Conditional blocks might be something I'm looking for, but so far, I wasn't able to create a "dynamic" block to produce different default_action { ... }, depending on some variables set or not. – Tomasz May 11 '23 at 22:53

2 Answers2

3

Does the following work for you?

resource "aws_lb_listener" "listener_https" {
    load_balancer_arn = aws_lb.lb.arn
    certificate_arn   = aws_acm_certificate.certificate.arn
    port              = 443
    protocol          = "HTTPS"
    ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"

    dynamic "default_action" {
        for_each = var.default == 1 ? [0] : []
        content {
            target_group_arn = aws_lb_target_group.tg.arn
            type             = "forward"
        }
    }
    dynamic "default_action" {
        for_each = var.default == 1 ? [] : [0]
        content {
            type  = "fixed-response"
            fixed_response {
                content_type = "text/plain"
                message_body = "not found"
                status_code  = "404"
            }
        }
     }
  }
}

Here we just define two separate default_action blocks, only one of them will be created depending on var.default value.

Documentation for dynamic blocks can be found here.

STerliakov
  • 4,983
  • 3
  • 15
  • 37
1

In the end, produced something like this and leaving here for reference. It lets me use many different "default_action" blocks, depending on which variables are set. Accepting the solution by SUTerliakov above.

resource "aws_lb_listener" "listener_https" {
  load_balancer_arn = aws_lb.lb.arn
  certificate_arn   = aws_acm_certificate.certificate.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"

  dynamic "default_action" {
    for_each = var.rules_404 ? [true] : []

    content {
      type = "fixed-response"

      fixed_response {
        content_type = "text/plain"
        message_body = "not found"
        status_code  = "404"
      }
    }
  }

  dynamic "default_action" {
    for_each = var.rules_single ? [true] : []

    content {
      target_group_arn = aws_lb_target_group.tg.arn
      type             = "forward"

    }
  }

  timeouts {}

  depends_on = [aws_acm_certificate_validation.certificate_validation]

  tags = module.label.tags
}
Tomasz
  • 179
  • 12