Search code examples
amazon-web-servicesterraformterraform-provider-aws

Terraform Nested loop - Multiple EC2's with multiple EBS Storage blocks


The second for_each loop is not working. I'm trying to write a nested loop that will allow multiple EC2's and each ec2 would be able to have a list of mount names and sizes for ebs volumes

main.tf

# Create resources using for_each

resource "aws_instance" "ec2_instances" {
  for_each = { for inst in var.ec2_instances : inst.name => inst }
  # for_each = var.ec2_instances[].
  
  ami           = each.value.ami
  instance_type = each.value.instance_type
  key_name      = each.value.key_name
  
  
  tags = var.hp_standard_tags

  dynamic "ebs_block_device" {
    for_each = [for volume in var.ec2_instances.ebs_volume : volume.volume_name => volume {
      device_name = volume.volume_name,
      volume_size = volume.volume_size
    }]
    content {
      device_name           = ebs_block_device.value.device_name
      volume_type           = "gp3"
      volume_size           = ebs_block_device.value.volume_size
      delete_on_termination = true
    }
  }

#user_data = file("${path.module}/startup.sh")
}

Variable.tf

variable "ec2_instances" {
  description = "List of EC2 instances"
  type = list(object({
    name               = string
    instance_type      = string
    ami                = string
    key_name           = string
    enable_autoscaling = bool
    ebs_volume = list(object({
      volume_size = string,
    volume_location = string }))
    })
  )
}

variable "standard_tags" {
  description = "Standard set of tags"
  type = object({
    last_review        = string,
    ticket             = string,
    app_name           = string,
    environment        = string,
    hpit_contact_email = string,
    hpit_cost_center   = string,
    hpit_criticality   = string,
    hpit_environment   = string,
    hpit_eprid         = string,
    hpit_mru           = string,
    hpit_role          = string,
    map_id             = string,
    map_prefix         = string
  })
  default = {
    last_review        = "07-12-2024",
    ticket             = "",
    app_name           = "",
    environment        = "dev",
    hpit_contact_email = "",
    hpit_cost_center   = "",
    hpit_criticality   = "",
    hpit_environment   = "",
    hpit_eprid         = "",
    hpit_mru           = "",
    hpit_role          = "",
    map_id             = "",
  map_prefix = "" }
}

variable "date" {
  description = "Run date for the tag"
  type        = string
  default     = "STRING" #"${formatdate("YYYY-MM-DD", timeadd(timestamp(), "24h"))}T00:00:00Z"
}

variable "role" {
  description = "dev aws account iam role to be assumed by core tf user"
  type        = string
  default     = ""
}

terraform.tfvars

# List of EC2 instances
ec2_instances = [
  {
    name               = "instance1"
    instance_type      = "t2.micro"
    ami                = "ami-00000000000" # Linux Golden Image Amazon Linux 2023
    key_name           = "your_key_pair_name1"
    enable_autoscaling = false
    ebs_volume = [
      {
        volume_size = "10",
        volume_name = "root"
      },
      {
        volume_size = "60",
        volume_name = "/dev/sg1"
      }
    ]
    #subnet
    #Tags

  },
  {
    name               = "instance2"
    instance_type      = "t2.small"
    ami                = "ami-00000000000" # Windows Golden Image Win 2022
    key_name           = "your_key_pair_name2"
    enable_autoscaling = true
    ebs_volume = [
      {
        volume_size = "10",
        volume_name = "root"
      },
      {
        volume_size = "60",
        volume_name = "/dev/sg1"
      }
    ]
  }
  # Add more instances as needed
]

standard_tags = {
  last_review        = "07-12-2024",
  ticket             = "SR0001",
  app_name           = "TEST",
  environment        = "dev",
  hpit_contact_email = "",
  hpit_cost_center   = "Number",
  hpit_criticality   = "low",
  hpit_environment   = "itg",
  hpit_eprid         = "38001",
  hpit_mru           = "",
  hpit_role          = "",
  map_id             = "",
  map_prefix         = ""
}

Solution

  • Instead of:

      dynamic "ebs_block_device" {
        for_each = [for volume in var.ec2_instances.ebs_volume : volume.volume_name => volume {
          device_name = volume.volume_name,
          volume_size = volume.volume_size
        }]
        content {
          device_name           = ebs_block_device.value.device_name
          volume_type           = "gp3"
          volume_size           = ebs_block_device.value.volume_size
          delete_on_termination = true
        }
      }
    

    Try (not tested):

      dynamic "ebs_block_device" {
        for_each = each.value.ebs_volume
        content {
          device_name           = ebs_block_device.value.volume_location
          volume_type           = "gp3"
          volume_size           = ebs_block_device.value.volume_size
          delete_on_termination = true
        }
      }