简体   繁体   中英

Terraform how to output object id that were created using count

I have a terraform module that creates 2 subnets. I need somehow to get the output for each subnet. When using the [count.index] as part of the output block I'm getting an error that count can not be used.

So what should be the solution since I need to associate ec2 to a specific subnet.

module "private_subnet" {
     source = "./modules/private_subnet"
     vpc_id = module.vpc.vpcid
     number_of_subnets = 2
     private-subnet-block = var.private-subnet-block
     tag_enviroment= var.tag_enviroment
     project_name = var.project_name }



 resource "aws_subnet" "private_subnet" {
        count = var.number_of_subnets
        cidr_block = var.private-subnet-block[count.index]
        availability_zone = var.availability_zone[count.index]
        vpc_id = var.vpc_id   
        map_public_ip_on_launch = false
        tags = {
        Name = "${var.project_name}-private-subnet-${count.index+1}"
        env = var.tag_enviroment   } }

output "privatesubnetid"{
    value = aws_subnet.private_subnet[count.index].id }

Error message :

Error: Reference to "count" in non-counted context │ │ on modules/private_subnet/output.tf line 2, in output "privatesubnetid": │ 2: value = aws_subnet.private_subnet[count.index].id │ │ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set

In order to proceed here you will need to decide what value you want to place in that output value in the situation where there are no instances of that subnet.


The most straightforward answer would be to just return a list of all of the ids, which will then be an empty list in the case where there are none:

output "private_subnet_ids" {
  value = aws_subnet.private_subnet[*].id
}

The [*] here is the splat operator , which is a concise way of saying to construct a list by taking the .id attribute of each element of the list on the left side of [*] , which is aws_subnet.private_subnet -- the list of all instances of that resource -- in your case.


Another option would be to return a map from availability zone name to subnet ID, in case the caller of your module needs to be able to distinguish between the different IDs for some reason:

output "private_subnet_ids" {
  value = tomap({
    for s in aws_subnet.private_subnet : s.availability_zone => s.id
  })
}

This is a for expression , which is perhaps a more general form of the splat expression we saw previously: it will produce a map where for each element of aws_subnet.private_subnet s it produces an element of the map whose key is s.availability_zone and whose value is s.id .

Similar to the previous example, this will produce an empty map if there aren't any subnets.


One more option that is perhaps closest to the example you gave in your question is to either return the first subnet only or to return null if there are zero subnets:

output "private_subnet_id" {
  value = length(aws_subnet.private_subnet) > 0 ? aws_subnet.private_subnet[0] : null
}

This is a conditional expression , which chooses one of two results ( aws_subnet.private_subnet[0] and null in this case) based on the result of a third boolean expression ( length(aws_subnet.private_subnet) > 0 ).

This one doesn't seem like a particularly useful option since it would leave no way to access the subsequent subnets. I included it only because in your example you used the singular name "private subnet ID" instead of the plural name "private subnet IDs" and so I wondered if you were intending to select just one of the subnet IDs somehow.


There are lots of other permutations here too. The general answer is that aws_subnet.private_subnet is a list of objects and so you can write any Terraform expression that is valid when working with lists of objects, to transform that list in whatever way makes sense for the result you want to produce. However, you must write an expression that is valid for any number of subnets -- including zero subnets -- to ensure that the module will work for all values of number_of_subnets .

You can use Terraform splat expression [1]:

output "privatesubnetid" {
    value = aws_subnet.private_subnet[*].id 
}

[1] https://www.terraform.io/language/expressions/splat

This can help you:

output "database_subnets" {
  description = "IDs of database subnets"
  value       = aws_subnet.database.*.id
}

output "database_subnet_group" {
  description = "ID of database subnet group"
  value       = concat(aws_db_subnet_group.database.*.id, [""])[0]
}

To output resource id that were created using count, do it like this:

output "private_subnet_ids" {
  value = one(aws_subnet.private_subnet[*].id)
}

The expression above first uses the splat operator to transform the list of objects into a list of just id values, which will also have either zero or one elements depending on the resource count.

The one function then deals with the two cases:

  • If the list has only one value, it'll return that value.
  • If the list has no values, it'll return null to represent the absence of a value.

Refernce

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM