Search code examples
terraformterraform-provider-aws

Terraform using count.index with tags


using terraform, i'm trying to include the count in the tags of my resource using count.index, but getting this error :

Error: Incorrect attribute value type │ │ on ..\modules\sn\ressources.tf line 16, in resource "aws_subnet" "prod_sn": │ 16: tags = var.sn_tags[count.index] │ ├──────────────── │ │ count.index is a number, known only after apply │ │ var.sn_tags is a list of string, known only after apply │ │ Inappropriate value for attribute "tags": map of string required.

vars.tf

variable "sn_tags" {
  type        = list (string)
  default     = ["aa", "bb"]
}

ressources.tf

resource "aws_subnet" "prod_sn" {
  count                   = length(var.sn_cidr)
  vpc_id                  = var.vpc_id
  cidr_block              = var.sn_cidr[count.index]
  availability_zone       = data.aws_availability_zones.azs.names[count.index]
  tags                    = var.sn_tags[count.index] 
}

main.tf

# Create Public Subnet on availability_zone "3a"
module "publicSn-a" {
  source            = "../modules/sn"
  vpc_id            = module.vpc.vpcId 
  sn_cidr           = ["10.0.1.0/24", "10.0.2.0/24"]
  sn_tags           = ["prodPublicA","prodPublicB"]
  
}

Solution

  • Your issue is that each loop iteration is trying to pass a string type to the tags parameter. If you break it down to just a single resource without the count (using the first element for now) then your current code is basically this:

    resource "aws_subnet" "prod_sn" {
      vpc_id                  = var.vpc_id
      cidr_block              = "10.0.1.0./24"
      availability_zone       = "eu-west-1a" # Note may not be this but the data source and the index will at least resolve to a single string AZ
      tags                    = "prodPublicA"
    }
    

    If we look at the documentation for the aws_subnet resource we can see that the tags parameter wants a map, not a string as the error implies.

    You could fix this by changing your list(string) variable into a list(map) so instead you have something like this instead:

    variable "sn_tags" {
      type = list(map)
    }
    

    and

    # Create Public Subnet on availability_zone "3a"
    module "publicSn-a" {
      source            = "../modules/sn"
      vpc_id            = module.vpc.vpcId 
      sn_cidr           = ["10.0.1.0/24", "10.0.2.0/24"]
      sn_tags           = [
        {
          name = "prodPublicA"
        },
        {
          name = "prodPublicB"
        },
      ] 
    }
    

    Alternatively if you just want to add a Name tag to all the subnets and don't want more flexibility with the tags instead you could rework it like this:

    variable "sn_names" {
      type = list(string)
    }
    
    resource "aws_subnet" "prod_sn" {
      count                   = length(var.sn_cidr)
      vpc_id                  = var.vpc_id
      cidr_block              = var.sn_cidr[count.index]
      availability_zone       = data.aws_availability_zones.azs.names[count.index]
      tags                    = {
        Name = var.sn_names[count.index]
      }
    }
    

    and call it like so:

    # Create Public Subnet on availability_zone "3a"
    module "publicSn-a" {
      source            = "../modules/sn"
      vpc_id            = module.vpc.vpcId 
      sn_cidr           = ["10.0.1.0/24", "10.0.2.0/24"]
      sn_names          = ["prodPublicA","prodPublicB"]
    }