Search code examples
amazon-ec2terraformterraform-provider-aws

Terraform: How to redirect the values of "Output" to a for_each statement


Below is a piece of my code that I am trying out to setup an ALB for my EC2.

#Create an EC2 Instance
resource "aws_instance" "terra_prj1_ec2" {
  ami = "ami-0014ce3e52359afbd"
  instance_type = "t3.micro"
  availability_zone = "eu-north-1a"
  count = 2
  key_name = "main-key"
  iam_instance_profile = aws_iam_instance_profile.terra_prj1_instance_profile.name
  user_data = file("userdata.sh")

  network_interface {
    device_index = 0
    network_interface_id = aws_network_interface.terra_prj1_sec_network_interface.id
  }  
}

#EC2 data set
output "ec2_target_group_arn" {
  value = join("", aws_instance.terra_prj1_ec2.*.id)
}

#Create a security group for load balancer
resource "aws_security_group" "terra_prj1_alb_sec_grp" {
  name        = "allow_terra_web_traffic"
  description = "Allow web inbound traffic"
  vpc_id      = aws_vpc.terra_prj1.id

  ingress {
    description      = "HTTP"
    from_port        = 80
    to_port          = 80
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
}

#Create a security group rule for EC2
resource "aws_security_group_rule" "terra_prj1_alb_sec_grp_rule" {
  type = "ingress"
  from_port = 8080
  to_port = 8080
  protocol = "tcp"
  security_group_id = aws_security_group.terra_prj1_sec_grp.id
  source_security_group_id = aws_security_group.terra_prj1_alb_sec_grp.id
}

#Create a target group for load balancer
resource "aws_lb_target_group" "terra_prj1_alb_target_grp" {
  name = "terra-prj1-alb-target-grp"
  port = 8080
  protocol = "HTTP"
  vpc_id = aws_vpc.terra_prj1.id
  load_balancing_algorithm_type = "round_robin"

  health_check {
    enabled = true
    port = 8081
    interval = 30
    protocol = "HTTP"
    path = "/health"
    matcher = 200
    healthy_threshold = 3
    unhealthy_threshold = 3
  }
}

#Create target group attachment
resource "aws_lb_target_group_attachment" "terra_prj1_alb_target_grp_attachment" {
  for_each = output.ec2_target_group_arn.id

  target_group_arn = aws_lb_target_group.terra_prj1_alb_target_grp.arn
  target_id = aws_instance.terra_prj1_ec2[each.key].id
  depends_on = [aws_lb_target_group.terra_prj1_alb_target_grp]
  port = 8080
}

#Create a load balancer
resource "aws_lb" "terra_prj1_alb" {
  name = "terra-prj1-alb"
  internal = false
  load_balancer_type = "application"
  security_groups = [aws_security_group.terra_prj1_alb_sec_grp.id]
  subnets = [aws_subnet.terra_prj1_subnet.id]
}

#Create a listener for load balancer
resource "aws_lb_listener" "terra_prj1_alb_listener" {
  load_balancer_arn = aws_lb.terra_prj1_alb.arn
  port = 80
  protocol = "HTTP"

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.terra_prj1_alb_target_grp.arn
}
}

I am facing the below error while running the code.

│ Error: Reference to undeclared resource
│ 
│   on Main.tf line 299, in resource "aws_lb_target_group_attachment" "terra_prj1_alb_target_grp_attachment":
│  299:   for_each = output.ec2_target_group_arn.id
│ 
│ A managed resource "output" "ec2_target_group_arn" has not been declared in the root module.

My attempt is: I am capturing the EC2 details in output, and I am trying to use them in the "for_each" statement in the "#Create target group attachment" block. When I apply, I get the above error. I tried a few online documents to debug this, hence not being able to spot a direct answer.

Appreciate if Could anyone point me what I am missing here ?


Solution

  • I updated locals as below,

    locals {
      ec2_instance_ids_map = { for idx, id in aws_instance.terra_prj1_ec2.*.id : idx => id }
    }
    

    then updated the target group attachment as below.

    #Create target group attachment
    resource "aws_lb_target_group_attachment" "terra_prj1_alb_target_grp_attachment" {
      for_each = local.ec2_instance_ids_map
    
      target_group_arn = aws_lb_target_group.terra_prj1_alb_target_grp.arn
      target_id = each.value
      depends_on = [aws_lb_target_group.terra_prj1_alb_target_grp]
      port = 8080
    }
    

    It worked for me.