Search code examples
dynamicterraformlisteneraws-application-load-balancer

Write a dynamic Terraform block for a load balancer listener rule


I'm new to dynamic blocks and am having some trouble writing rules to listeners on a load balancer that was created using for_each.

Below are the resources I created:

resource "aws_lb_listener" "app_listener_forward" {
  for_each          = toset(var.app_listener_ports)
  load_balancer_arn = aws_lb.app_alb.arn
  port              = each.value
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS-1-2-Ext-2018-06"
  certificate_arn   = var.ssl_cert

  default_action {
    type = "forward"
    forward {
      dynamic "target_group" {
        for_each = aws_lb_target_group.app_tg
        content {
          arn = target_group.value["arn"]
        }
      }
      stickiness {
        enabled  = true
        duration = 86400
      }
    }
  }
}

resource "aws_lb_listener_rule" "app_https_listener_rule" {
  for_each     = toset(var.app_listener_ports)
  listener_arn = aws_lb_listener.app_listener_forward[each.value].arn

  action {
    type = "forward"
    forward {
      dynamic "target_group" {
        for_each = aws_lb_target_group.app_tg
        content {
          arn = target_group.value["arn"]
        }
      }
    }
  }

  dynamic "condition" {
    for_each = var.images
    path_pattern {
      content {
        values = condition.value["paths"]
      }
    }
  }
}

resource "aws_lb_target_group" "app_tg" {
  for_each    = var.images
  name        = each.key
  port        = each.value.port
  protocol    = "HTTP"
  target_type = "ip"
  vpc_id      = aws_vpc.app_vpc.id

  health_check {
    interval            = 130
    timeout             = 120
    healthy_threshold   = 10
    unhealthy_threshold = 10
  }

  stickiness {
    type            = "lb_cookie"
    cookie_duration = 86400
  }
}

Below are how the variables are defined:

variable "images" {
  type = map(object({
    app_port = number
    paths = set(string)
  }))
  {
    "app-one" = {
      app_port = 3000
      paths = [
        "/appOne",
        "/appOne/*"
      ]
    }
    "app-two" = {
      app_port = 4000
      paths = [
        "/appTwo",
        "/appTwo/*"
      ]
    }
  }

variable "app_listener_ports" {
  type = list(string)
  default = [
    80, 443, 22, 7999, 8999
  ]
}

Upon executing, I am getting an error dealing with the path_pattern being unexpected:

Error: Unsupported block type
│
│   on alb.tf line 78, in resource "aws_lb_listener_rule" "app_https_listener_rule":
│   78:     path_pattern {
│
│ Blocks of type "path_pattern" are not expected here.

I've tried a few ways to get this dynamic block but am having some difficulty. Any advice would be appreciated.

Thank you!


Solution

  • Try it like this:

      dynamic "condition" {
        for_each = var.images
        content {
          path_pattern {
            values = condition.value.paths
          }
        }
      }
    

    And change the type of paths from set(string) to list(string).