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
Marko,Marcin - just to put formatting im putting it here and shortened
In .tfvars I have :
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 ?
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)
then in your vars:
This will successful use default values if not explicitly given in the vars.