Unable to retrieve subnet ids in the terraform output block - giving multiple errors at a time

62 Views Asked by At

I'm trying to make subnets like the following way. I'm trying to loop over objects in the parent module:

  variable "list_of_subnets" {
  description = "list of vpc subnets"
  type = list(object({
    subnet_type = string
    cidr_block  = string
    av_zone     = string
  }))
  default = [ 
    {
      subnet_type  = "public"
      cidr_block   = "10.0.101.0/24"
      av_zone      = "us-west-1a"
    },
    {
      subnet_type  = "public"
      cidr_block   = "10.0.102.0/24"
      av_zone      = "us-west-1b"
    },
    {
      subnet_type  = "private"
      cidr_block   = "10.0.1.0/24"
      av_zone      = "us-west-1a"
    },
    {
      subnet_type  = "private"
      cidr_block   = "10.0.2.0/24"
      av_zone      = "us-west-1b"
    },
    {
      subnet_type  = "database"
      cidr_block   = "10.0.151.0/24"
      av_zone      = "us-west-1a"
    },
    {
      subnet_type  = "database"
      cidr_block   = "10.0.152.0/24"
      av_zone      = "us-west-1b"
    }
  ]
}

The above is my variable bloc through which I'm looping over to make multiple subnets:

module "subnets" {
  source = "./modules/subnets"
  for_each = {for i, v in var.list_of_subnets:  i => v}
  aws_vpc_id = module.VPC-Manual.vpc_id
  sub_cidr = each.value.cidr_block
  sub_av_zone = each.value.av_zone
  subnet_type = each.value.subnet_type
}

"./modules/subnets:" Now, in the child module, simply passing those variables:

resource "aws_subnet" "aws_subnets" {
  vpc_id = var.aws_vpc_id
  cidr_block = var.sub_cidr
  availability_zone = var.sub_av_zone
  tags = {
    subnet_type = var.subnet_type
  }
}

In the child output block trying to retrieve the ids based on tags so that only public subnet ids can be retrieved:

output "public_subnet_ids" {
  value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
}

parent output:

output "subnet_ids" {
  value = module.subnets.public_subnet_ids
}

Terraform apply gives the following errors:

Changes to Outputs:
  + vpc_id = (known after apply)
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (bool).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Attempt to get attribute from null value
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This value is null, so it does not have any attributes.
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (bool).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (bool).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (bool).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Attempt to get attribute from null value
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This value is null, so it does not have any attributes.
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (bool).
╵
╷
│ Error: Attempt to get attribute from null value
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This value is null, so it does not have any attributes.
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (bool).
╵
╷
│ Error: Attempt to get attribute from null value
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This value is null, so it does not have any attributes.
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Unsupported attribute
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ Can't access attributes on a primitive-typed value (string).
╵
╷
│ Error: Missing map element
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This map does not have an element with the key "tags".
╵
╷
│ Error: Missing map element
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This map does not have an element with the key "tags".
╵
╷
│ Error: Attempt to get attribute from null value
│
│   on modules/subnets/output.tf line 3, in output "public_subnet_ids":
│    3:   value = [for subnet in aws_subnet.aws_subnets: subnet.tags["subnet_type"] == "public" ? "${subnet.id}" : null]
│
│ This value is null, so it does not have any attributes.
2

There are 2 best solutions below

1
Carlo Luis Santos On

If I read your code correctly, you are trying to create a single subnet per subnet module. However, I believe your intention is to have a single module for all of your subnets, then you should not have a for_each loop in your module, rather passing the list_of_subnets inside the module itself where you apply the for_each loop onto the aws_subnet resource.

That being said to address your current issue/error, you don't need to loop through subnet in aws_subnet.aws_subnets because it will only ever be a single subnet.

output "public_subnet_ids" {
  value = aws_subnet.aws_subnets.tags_all["subnet_type"] == "public" ? "${aws_subnet.aws_subnets.id}" : null
}
0
Helder Sepulveda On

Here is how I would change your code...

In the module:

  • use a variable "data" to pass an entire object instead of individual variables
  • output the entire subnet, there is more info there that someone might need
variable "vpc_id" {
  description = "the vpc_id"
}

variable "data" {
  description = "object with subnet data"
}

resource "aws_subnet" "subnet" {
  vpc_id            = var.vpc_id
  cidr_block        = var.data.cidr_block
  availability_zone = var.data.av_zone
  tags = {
    subnet_type = var.data.subnet_type
  }
}

output "subnet" {
  value = aws_subnet.subnet
}

Calling the module

  • now we have less variables all we need is data = each.value
  • in the output we can loop over the module.subnets and get what you need
variable "list_of_subnets" {
  default = [
    {
      subnet_type = "public"
      cidr_block  = "172.31.1.0/24"
      av_zone     = "us-east-1a"
    },{
      subnet_type = "public"
      cidr_block  = "172.31.2.0/24"
      av_zone     = "us-east-1b"
    },{
      subnet_type = "private"
      cidr_block  = "172.31.3.0/24"
      av_zone     = "us-east-1a"
    },{
      subnet_type = "private"
      cidr_block  = "172.31.4.0/24"
      av_zone     = "us-east-1b"
    }
  ]
}

module "subnets" {
  source   = "./subnets"
  for_each = { for k, v in var.list_of_subnets : k => v }
  vpc_id   = "vpc-0627130d668a04f24"
  data     = each.value
}

output "public_subnet_ids" {
  value = [
    for k, v in module.subnets : v.subnet.id
    if v.subnet.tags_all["subnet_type"] == "public"
  ]
}