-
Notifications
You must be signed in to change notification settings - Fork 10k
Description
Terraform v0.12.2
Use-cases
We often use count
to disable a resource (above all in modules) from a boolean var, with statements like count = var.enabled ? 1 : 0
or count = var.enabled ? 1 : length([some list of resources or datasources])
Here are among others some code snippets from terraform-aws-vpc
module :
resource "aws_subnet" "private" {
count = var.create_vpc && length(var.private_subnets) > 0 ? length(var.private_subnets) : 0
vpc_id = local.vpc_id
cidr_block = var.private_subnets[count.index]
availability_zone = element(var.azs, count.index)
tags = merge(
{
"Name" = format(
"%s-${var.private_subnet_suffix}-%s",
var.name,
element(var.azs, count.index),
)
},
var.tags,
var.private_subnet_tags,
)
}
resource "aws_network_acl" "public" {
count = var.create_vpc && var.public_dedicated_network_acl && length(var.public_subnets) > 0 ? 1 : 0
vpc_id = element(concat(aws_vpc.this.*.id, [""]), 0)
subnet_ids = aws_subnet.public.*.id
tags = merge(
{
"Name" = format("%s-${var.public_subnet_suffix}", var.name)
},
var.tags,
var.public_acl_tags,
)
}
resource "aws_network_acl_rule" "public_inbound" {
count = var.create_vpc && var.public_dedicated_network_acl && length(var.public_subnets) > 0 ? length(var.public_inbound_acl_rules) : 0
network_acl_id = aws_network_acl.public[0].id
egress = false
rule_number = var.public_inbound_acl_rules[count.index]["rule_number"]
rule_action = var.public_inbound_acl_rules[count.index]["rule_action"]
from_port = var.public_inbound_acl_rules[count.index]["from_port"]
to_port = var.public_inbound_acl_rules[count.index]["to_port"]
protocol = var.public_inbound_acl_rules[count.index]["protocol"]
cidr_block = var.public_inbound_acl_rules[count.index]["cidr_block"]
}
I have also witnessed some int
variable used as count = var.enabled * length([some list of resources or datasources])
.
It makes the triggers more complex to understand, as count
actually embeds both a boolean expression to enable the provisionning, together with the number of instances of the resource. It sounds like a twist of the initial expected count
usage.
Attempted Solutions
I have thought initially about having count
accepting booleans by automatically converting true->1
and false->0
.
I had a quick discussion with go-cty
developer that explained to me the intentional decision not to convert bool
to number
to avoid confusions, and indeed, I am aligned that the code should stay readable by segregating the scopes.
Therefore, I attempt this proposal below.
Proposal
Introducing a new parameter enabled
in resources accepting bool
values or logical statements to provision the resource (default) or not, independently from count
value (which can be 0 by the way).
It will increase the readibility of the code by avoiding sometines complex conditional operators ?:
The previous examples would become :
resource "aws_subnet" "private" {
enabled = var.create_vpc
count = length(var.private_subnets)
vpc_id = local.vpc_id
cidr_block = var.private_subnets[count.index]
availability_zone = element(var.azs, count.index)
tags = merge(
{
"Name" = format(
"%s-${var.private_subnet_suffix}-%s",
var.name,
element(var.azs, count.index),
)
},
var.tags,
var.private_subnet_tags,
)
}
resource "aws_network_acl" "public" {
enabled = var.create_vpc && var.public_dedicated_network_acl && length(var.public_subnets) > 0
vpc_id = element(concat(aws_vpc.this.*.id, [""]), 0)
subnet_ids = aws_subnet.public.*.id
tags = merge(
{
"Name" = format("%s-${var.public_subnet_suffix}", var.name)
},
var.tags,
var.public_acl_tags,
)
}
resource "aws_network_acl_rule" "public_inbound" {
enabled = var.create_vpc && var.public_dedicated_network_acl && length(var.public_subnets) > 0
count = length(var.public_inbound_acl_rules)
network_acl_id = aws_network_acl.public[0].id
egress = false
rule_number = var.public_inbound_acl_rules[count.index]["rule_number"]
rule_action = var.public_inbound_acl_rules[count.index]["rule_action"]
from_port = var.public_inbound_acl_rules[count.index]["from_port"]
to_port = var.public_inbound_acl_rules[count.index]["to_port"]
protocol = var.public_inbound_acl_rules[count.index]["protocol"]
cidr_block = var.public_inbound_acl_rules[count.index]["cidr_block"]
}
Another use case I often see is to to provision some resources only for prod configurations (audit logs buckets, special routes or firewall rules):
enabled = var.env == "production" || var.env == "qa"
enabled
shall preced the interpretation of count
interpretation.
IMO, it will make the code more readable by explicitly describing what may prevent the provisionning of count
resources. It will also allow to clearly distinguish bool
from int
variables.
References
I haven't found any ticket on that subject. Sorry if I have missed one.