How can i extract the id from a list of EC2 instances in terraform to use in a ALB?

Viewed 811

I'm currently practicing terraform to code mi AWS infrastructure.

I'm stuck creating an aplication load balancer. In the module, it is required that you place the id of the instances to target inside the target groups.

My EC2 module looks like this

module "ec2_private" {
  depends_on = [module.vpc]
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "3.2.0"
  # insert the 34 required variables here
  name                   = "${var.environment}-PrivateVM"
  ami                    = data.aws_ami.amzlinux2.id
  instance_type          = var.instance_type
  key_name               = var.instance_keypair
  #monitoring            = true
  for_each               = toset(["0","1"])
  subnet_id              = module.vpc.private_subnets[each.value]
  user_data              = file("${path.module}/app1-install.sh")
  vpc_security_group_ids = [module.private_sg.security_group_id]
  tags                   = local.common_tags  
}

This creates 2 instances, each in one of the two private subnet i've created.

Now i need to extract the id from this module, to use in the ALB

    module "alb" {
      source  = "terraform-aws-modules/alb/aws"
      version = "6.5.0"
      # insert the 4 required variables here
      name = "${local.name}-alb01"
      load_balancer_type = "application"
      vpc_id = module.vpc.vpc_id
      subnets = [module.vpc.public_subnets[0],module.vpc.public_subnets[1]]
      security_groups = [module.loadbalancer_sg.security_group_id]

  # Listeners

      http_tcp_listeners = [
        {
          port               = 80
          protocol           = "HTTP"
          target_group_index = 0
        }
      ]
      # Target Groups
      target_groups = [
        # App1 Target Group - TG index 0
        {
          name_prefix          = "h1"
          backend_protocol     = "HTTP"
          backend_port         = 80
          target_type          = "instance"
          deregistration_delay = 10
          health_check = {
            enabled             = true
            interval            = 30
            path                = "/example/index.html"
            port                = "traffic-port"
            healthy_threshold   = 3
            unhealthy_threshold = 3
            timeout             = 6
            protocol            = "HTTP"
            matcher             = "200-399"
          }
          protocol_version = "HTTP1"
          # App1 Target Group - Targets
          targets = {
            my_app1_vm1 = {
              target_id = element(module.ec2_private.id,0)
              port      = 80
            },
            my_app1_vm2 = {
              target_id = element(module.ec2_private.id,1)
              port      = 8080
            }
          }
          tags= local.common_tags
        }
      ]
    }

Using this code i get this error

│ Error: Unsupported attribute
│
│   on c10-02-ALB-application-loadbalancer.tf line 43, in module "alb":
│   43:           target_id = element(module.ec2_private.id,0)
│     ├────────────────
│     │ module.ec2_private is a list of object, known only after apply
│
│ Can't access attributes on a list of objects. Did you mean to access attribute "id" for a specific element of the
│ list, or across all elements of the list?

I've tried to workaround this using the exact index

  targets = {
    my_app1_vm1 = {
      target_id = module.ec2_private.id[0]
      port      = 80
    },
    my_app1_vm2 = {
      target_id = module.ec2_private.id[1]
      port      = 8080
    }
  }

But i get the same error

│ Error: Unsupported attribute
│
│   on c10-02-ALB-application-loadbalancer.tf line 47, in module "alb":
│   47:           target_id = module.ec2_private.id[1]
│     ├────────────────
│     │ module.ec2_private is a list of object, known only after apply
│
│ Can't access attributes on a list of objects. Did you mean to access attribute "id" for a specific element of the
│ list, or across all elements of the list?

Is there any other way to extract the especific index?

Thanks.

2 Answers

You need to use Terraform outputs in this case. Inside your ec2_private module you may want to have something like this:

output "ec2_instance_ids" {
  value = [aws_instance.my_first_instance.id, aws_instance.my_second_instance.id]
}

The output of a module could than be referenced like this:

module.<MODULE NAME>.<OUTPUT NAME>

Example:

targets = {
  my_app1_vm1 = {
    target_id = module.ec2_private.ec2_instance_ids[0]
      port      = 80
  },
  my_app1_vm2 = {
    target_id = module.ec2_private.ec2_instance_ids[1]
    port      = 8080
  }
}

I too faced the same issue while creating ALB where I had to provide the target instance id. After carefully looking at the error message I realized my mistake.

module.ec2_private is a list of object, known only after apply. In my case it was ec2_instance module. so you need use element around ec2_private and extract the id.

In my case the below worked target_id = (element(module.ec2_instance,1)).id enter image description here same should work for you for ec2_private

Related