Search code examples
amazon-web-servicesterraformaws-application-load-balancer

Add multiple target group attachments using values from variables in terraform


I am trying to create a target group and attach it to 2 instances. I was able to achieve this by using the below code.

locals {
  app_servers = {
    "server1" = "${aws_instance.server1.id}",
    "server2" = "${aws_instance.server2.id}"
  }
}

resource "aws_lb_target_group" "internal" {
  name             = "internal-tg"
  port             = 9550
  protocol         = "HTTPS"
  vpc_id           = aws_vpc.main.id
  protocol_version = "HTTP1"

  health_check {
    healthy_threshold   = 5
    interval            = 15
    protocol            = "HTTPS"
    unhealthy_threshold = 2
    timeout             = 5
    matcher             = "200"
    path                = "/login"
  }

}

resource "aws_lb_target_group_attachment" "internal" {
  for_each         = local.app_servers
  target_group_arn = aws_lb_target_group.internal.arn
  port             = aws_lb_target_group.internal.port
  target_id        = each.value
}

Now I want to add many target groups and attach it to the same 2 instances. The properties that will change with each target group are name, port and matcher. I tried adding another variable as a map under locals like below

locals {
  app_servers = {
    "server1" = "${aws_instance.server1.id}",
    "server2" = "${aws_instance.server2.id}"
  }

  target_groups = {
    "internal" = {
      port    = 9550
      matcher = "200"
    },
    "dev1" = {
      port    = 9152
      matcher = "302"
    },
    "sso" = {
      port    = 9154
      matcher = "302"
    },
    "terra-test" = {
      port    = 9360
      matcher = "200"
    }
  }   
}

This doesn't seem to work. Need some guidance on how to achieve this. Thanks


Solution

  • You could use setproduct() to obtain a list with all the combinations and use it for the attachment resources. For example, as follows:

    locals {
      app_servers = {
        "server1" = "${aws_instance.server1.id}",
        "server2" = "${aws_instance.server2.id}"
      }
    
      target_groups = {
        "internal" = {
          port = 9550
          matcher = "200"
        },
        "dev1" = {
          port = 9152
          matcher = "302"
        },
        "sso" = {
          port = 9154
          matcher = "302"
        },
        "terra-test" = {
          port = 9360
          matcher = "200"
        }
      }
      product = setproduct(keys(local.target_groups), values(local.app_servers))
    }
    
    resource "aws_lb_target_group" "main" {
      for_each = local.target_groups
      
      name             = "${each.key}-tg"
      port             = each.value["port"]
      protocol         = "HTTPS"
      vpc_id           = aws_vpc.main.id
      protocol_version = "HTTP1"
    
      health_check {
        healthy_threshold   = 5
        interval            = 15
        protocol            = "HTTPS"
        unhealthy_threshold = 2
        timeout             = 5
        matcher             = each.value["matcher"]
        path                = "/login"
      }
    }
    
    resource "aws_lb_target_group_attachment" "main" {
      count = length(local.product)
    
      target_group_arn = aws_lb_target_group.main[local.product[count.index][0]].arn
      port             = aws_lb_target_group.main[local.product[count.index][0]].port
      target_id        = local.product[count.index][1]
    }
    

    Your product would be:

    [
        [
            "dev1",
            "<ID_1>",
        ],
        [
            "dev1",
            "<ID_2>",
        ],
        [
            "internal",
            "<ID_1>",
        ],
        [
            "internal",
            "<ID_2>",
        ],
        [
            "sso",
            "<ID_1>",
        ],
        [
            "sso",
            "<ID_2>",
        ],
        [
            "terra-test",
            "<ID_1>",
        ],
        [
            "terra-test",
            "<ID_2>",
        ],
    ]