skip to Main Content

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

Answers


  1. 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
    }
    
    Login or Signup to reply.
  2. 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"
      ]
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search