Could not get attribute id from instance resource type in the latest aws provider plugin

Hi Everyone,

I have created VPC and all other required things to setup complete networking by terraform. After that I written script for EC2 and ALB. While registering instance into target group, the target group has attribute target_id, it expecting instance id if using target type as instance. But I could not get instance id. Please help to fix this issue. Please let me know if there any other way to fix it.

error:

│ Error: Unsupported attribute
│
│ on alb.tf line 55, in resource "aws_lb_target_group_attachment" "web_tg_attachment":
│ 55: count = length(aws_instance.web_server[*].id)
│
│ This object does not have an attribute named "id".

resource "aws_lb_target_group_attachment" "web_tg_attachment" {
  count            = length(aws_instance.web_server[*].id)
  target_group_arn = aws_lb_target_group.web_tg.arn
  target_id        = element(aws_instance.web_server[*].id, count.index)
}

If you refer to the documentation for aws_instance, you’ll see that Terraform is right - they don’t have an id.

Yet the example in the documentation for aws_lb_target_group_attachment says they do.

Since there is apparently a bug in the documentation, I’d suggest you open a GitHub issue to let the provider authors know.

Perhaps there was an id in previous provider versions and it got removed.

Maybe arn is the replacement? I’m not sure but that seems plausible.

Yes I have also checked the documentation while facing the issue, there is no id attribute in instance resource type. So that I could not get id from instance resource type. Yeah this one is already I understand before raise this. But in target group attachment resource expecting id of the instance in target id argument while using target type as instance. Okay I will raise issue in github of terraform as per your concern.

Thank you for your reply.

Hi @marieswaran.k1995,

You have not included a complete example containing the aws_instance.web_server configuration (it would also help to format this correctly so we can see more easily what the original config looks like), but I’m guessing that the error is because it is not an expanded instance. This means you are trying to use the splat notation of the set of resource attributes which don’t all have their own id attributes.

As for what you have shown, it’s unnecessarily complicated. If aws_instance.web_server really is a collection of instances, then you could use length(aws_instance.web_server) to get the same effect, and there is no need for the element function. If you are trying to correlate instances though you should not be using count, but rather for_each:

resource “aws_lb_target_group_attachment” “web_tg_attachment” {
  for_each = aws_instance.web_server
  target_group_arn = aws_lb_target_group.web_tg.arn
  target_id = each.value.id
}

Hi,

The below one is ec2 configuration.

# EC2 instance creation
resource "aws_instance" "web_server" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "t2.micro"
  for_each               = toset(aws_subnet.public_subnet[*].id)
  subnet_id              = each.key
  iam_instance_profile   = "EC2_SSM_Role"
  vpc_security_group_ids = [aws_security_group.web_server_sg.id]
  key_name               = "web_server"
  tags = {
    Name = "${var.project_name}-${var.env_name}-web-server"
  }
  provisioner "remote-exec" {
    inline = ["#!/bin/bash", "sudo apt-get update", "sudo apt-get install nginx -y", "sudo service nginx start", "sudo service nginx enable", "sudo service nginx status"]
    connection {
      type        = "ssh"
      port        = 22
      host        = self.public_ip
      user        = "ubuntu"
      private_key = file("web.pem")
    }
  }
}

**Target group attachment configuration:**

#Target group attachment
resource "aws_lb_target_group_attachment" "web_tg_attachment" {
  count            = length(aws_instance.web_server[*].id)
  target_group_arn = aws_lb_target_group.web_tg.arn
  target_id        = element(aws_instance.web_server[*].id, count.index)
}

You have mentioned to use for_each meta argument, but I want to know why I cannot use count. This one is also repeat the resource creation.
Please go through my config and let me know if suppose I made any mistake.

Your code formatting is mangled and hard to read: Welcome to the forum - please reformat your message

I have reformatted my code. You can easily read now.

You have defined the keys of a for_each using an attribute (id) of another resource that is only known after that other resource has been created.

This will cause you trouble, as Terraform cannot complete a plan if for_each keys are values which will only be known after apply - it is an architectural choice / limitation.

You should use some identifier that can be known before the aws_subnet creations are applied.

To give more specific help on this point, you would have to show us your aws_subnet resource block.




@jbardin has already pointed out that this is unnecessarily complicated.

As you have not adopted any changes suggested in that message, I guess you want more details:

length(aws_instance.web_server[*].id) is an overly complicated way of arriving at the same result as length(aws_instance.web_server) as the [*].id just does a bunch of additional transformations which make no changes to the length.

element(aws_instance.web_server[*].id, count.index) is an extremely over-complicated way of writing aws_instance.web_server[count.index].id. As well as the needless use of [*], the element function is effectively obsolete in modern Terraform - it is less readable and has surprising extra behaviour which may hide errors, compared to a simple square-bracketed index expression.

However neither of these really matter, because you should be using for_each instead of count here.

Never use count unless all of the objects being created via the count are so identical, that you would not care which one was being destroyed during any future change.

The reason is that resource instances in a count are identified only by their index.

Let us suppose, for sake of example, that you have subnets A, B, C, each with their webserver instance and LB attachment.

Let us now suppose subnet B is removed.

If you have used count, Terraform does not know that the LB attachments are related to A, B, C. It only knows them as 0, 1, 2. As a result what it now does is:

  • Delete the LB attachment at count.index 2, for C
  • Replace or update the LB attachment at count.index 1, from being configured for B, to C

As a result, the change to remove B ends up messing with configuration for C.

Thanks @jbardin as per your suggestion I had change, it is working as expected.
Thanks @maxb