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
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 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.