skip to Main Content

Context: I am trying to create a list of EC2 instances. I want to avoid defining every single value in my .tfvars file, and instead want them to be inherited from the default block, but it’s not happening.

Question: Could you advise me on how to make it happen?

Detailed Description:

I create EC2 instances by iterating through a variable that I created. This variable is a list of objects, where each object contains all the attributes necessary for EC2 creation.

Here is an example of the iteration:

module "aws_instances" {
  for_each = {
    for index, ec2 in var.ec2_instances : tonumber(index) => ec2
  }
  source                                       = "../modules/instance"
  account                                      = var.account
  repo                                         = var.repo
  environment                                  = var.environment
  zone                                         = var.zone
  name                                         = each.value.name
  prefix                                       = each.value.prefix
  disable_api_termination                      = each.value.disable_api_termination
  os_type                                      = each.value.os_type
  instance_type                                = each.value.instance_type
  instance_count                               = each.value.instance_count
  root_volume_size                             = each.value.root_volume_size
  root_volume_delete_on_termination            = each.value.root_volume_delete_on_termination
  additional_data_volume_size                  = each.value.additional_data_volume_size
  additional_data_volume_delete_on_termination = each.value.additional_data_volume_delete_on_termination
  network_volume_size                          = each.value.network_volume_size
  port_ranges                                  = each.value.port_ranges
  public_port_ranges                           = each.value.public_port_ranges
  additional_ip_address_ranges                 = each.value.additional_ip_address_ranges
  extra_tags                                   = each.value.extra_tags
  custom_ami                                   = each.value.custom_ami
  custom_amis                                  = each.value.custom_amis
  custom_ingress_cidr                          = each.value.custom_ingress_cidr
  optional_people_ip_address_ranges            = each.value.optional_people_ip_address_ranges
  optional_default_ports_ip_address_ranges     = each.value.optional_default_ports_ip_address_ranges
  enforce_throughput                           = each.value.enforce_throughput
  enforce_iops                                 = each.value.enforce_iops
}

Here is the variable itself, along with the default block:

variable "ec2_instances" {
  type = list(object({
    name                                         = string
    prefix                                       = string
    disable_api_termination                      = bool
    os_type                                      = string
    instance_type                                = string
    metadata_options                             = map(string)
    instance_count                               = number
    root_volume_size                             = number
    root_volume_delete_on_termination            = bool
    additional_data_volume_size                  = number
    additional_data_volume_delete_on_termination = bool
    network_volume_size                          = number
    port_ranges = list(object({
      description = string
      from_port   = number
      to_port     = number
      protocol    = optional(string)
    }))
    public_port_ranges = list(object({
      description = string
      from_port   = number
      to_port     = number
      protocol    = optional(string)
    }))
    additional_ip_address_ranges = list(string)
    extra_tags                   = map(string)
    custom_ami                   = bool
    custom_amis                  = map(string)
    custom_ingress_cidr = list(object({
      description = string
      from_port   = number
      to_port     = number
      protocol    = string
      cidr_blocks = string
    }))
    keep_subnet                              = bool
    optional_people_ip_address_ranges        = optional(list(string))
    optional_default_ports_ip_address_ranges = optional(list(string))
    enforce_subnet                           = optional(string)
    enforce_throughput                       = optional(number)
    enforce_iops                             = optional(number)
    hibernation                              = optional(bool)
  }))
  default = [
    {
      name                    = null
      prefix                  = "app"
      disable_api_termination = true
      os_type                 = "ubuntu-bionic"
      instance_type           = null
      metadata_options = {
        "http_endpoint" = "enabled"
        "http_tokens"   = "required"
      }
      instance_count                               = 1
      root_volume_size                             = 120
      root_volume_delete_on_termination            = false
      additional_data_volume_size                  = 0
      additional_data_volume_delete_on_termination = false
      network_volume_size                          = 0
      port_ranges                                  = []
      public_port_ranges                           = []
      additional_ip_address_ranges                 = []
      extra_tags                                   = {}
      custom_ami                                   = false
      custom_amis = {
        "windows"                                   = "ami-019f2455a29c94910"
        "amazon-linux2"                             = "ami-08ef2d900be37a0ee"
        "ubuntu-xenial-16.04-amd64-server-20190628" = "ami-03746875d916becc0"
      }
      custom_ingress_cidr = []
      keep_subnet         = false
    }
  ]}

The example of the .tfvars file where I am testing :

ec2_instances = [
  {
    name                    = "1234"
    custom_ami              = true
    instance_count          = 1
    instance_type           = "t3.small"
    disable_api_termination = false
    os_type                 = "amazon-linux2"

    root_volume_delete_on_termination = true
    extra_tags = {
      "serl:os-version" = "Amazon Linux 2"
    }
    custom_amis = {
      "windows"                                   = "1234"
      "amazon-linux2"                             = "1234"
      "ubuntu-xenial-16.04-amd64-server-20190628" = "1234"
    }
    optional_people_ip_address_ranges        = ["1234"]
    optional_default_ports_ip_address_ranges = ["1234"]
    custom_ingress_cidr = [
      {
        description = "SSH"
        from_port   = 22
        to_port     = 22
        protocol    = 6
        cidr_blocks = "1234"
      },
      {
        description = "SSH"
        from_port   = 22
        to_port     = 22
        protocol    = 6
        cidr_blocks = "1234"
      },
    ]
  }]

The error that I’m getting :

The resolved value of variable “ec2_instances” is not appropriate: element
0: attributes “additional_data_volume_delete_on_termination”,
“additional_data_volume_size”, “additional_ip_address_ranges”,
“keep_subnet”, “metadata_options”, “network_volume_size”, “port_ranges”,
“prefix”, “public_port_ranges”, and “root_volume_size” are required.

I don’t understand why are those required to be defined in the .tfvars file.

I thought the whole point of the default block was to save myself lines of code and not having to specify values in the .tfvars file if the same values are present in the default block.

I would really appreciate advice in how to achieve the goal whch is creation of any amount of ec2s through a tfvars file but not having to define the attributes in the default block in tfvars file if the value is the same.

Thank you for reading the thread

I am trying to create a list of EC2 instances. I want to avoid defining every single value in my .tfvars file, and instead want them to be inherited from the default block, but it’s not happening.

UPDATE :

Let’s assume this is my variable for simplicity :

variable "ec2_instances" {
  type = list(object({
    name                                         = string
    prefix                                       = optional(string)
   
  }))
  default = [
    {
      name                    = null
      prefix                  = "A"}
     
    
  ]
}

In .tfvars I have :

ec2_instances = [
  {
    name                    = "example"
}]

Yet I get the error saying that value of prefix is null

Shouldn’t it pull the default value from the default block ?

Any advice ?

2

Answers


  1. Chosen as BEST ANSWER

    Marko,Marcin - just to put formatting im putting it here and shortened

    variable "ec2_instances" {
      type = list(object({
        name                                         = string
        prefix                                       = optional(string)
       
      }))
      default = [
        {
          name                    = null
          prefix                  = "A"
         
        }
      ]
    }
    

    In .tfvars I have :

    ec2_instances = [
      {
        name                    = "example"
    }]
    

    Yet I get the error saying that value of prefix is null where i thought it would pull the default value from the default block.

    Any advice ?


  2. optional takes second argument which is a default value. So you have to make everything optional, and use the second argument for a default value, e.g.:

    (only fraction of your code shown, for simplicity)

    
    variable "ec2_instances" {
      type = list(object({
        name                                         = optional(string, null)
        prefix                                       = optional(string, "app")
        disable_api_termination                      = optional(bool, true)
        instance_type                                = optional(string, "t2.micro")
        os_type                                      = optional(string, "ubuntu-bionic")
      }))
    }
    

    then in your vars:

    ec2_instances = [
      {
        name                    = "1234"
        custom_ami              = true
        instance_count          = 1
        disable_api_termination = false
        os_type                 = "amazon-linux2"
      }]
    

    This will successful use default values if not explicitly given in the vars.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search