My question is very simple but unable to find any example or solution on the entire internet. I want to use the if-else condition in the data source
of terraform and based on the value it should search the result. We have 2 different VPCs in our AWS account: 1. Prod VPC, 2. RDS VPC
Filter should work based on boolean variable var.rds_vpc
Pseudocode:
data "aws_vpc" "vpc" {
if var.rds_vpc == true:
tags = {
Name = "rds_vpc"
Type = "database"
}
else:
tags = {
Cluster = "live_vpc"
Enviornment = "production"
}
}
If both VPCs could have similar tags, I could simply pass the values via variables. But in the above case, the tags are also different.
I would highly appreciate it if someone can help.
There are various different ways to achieve this result depending on your detailed goals. The most direct answer would be to use a conditional expression to select one of two map values:
tags = (
var.rds_vpc ?
{
Name = "rds_vpc"
Type = "database"
} :
{
Cluster = "live_vpc"
Enviornment = "production"
}
)
If you are writing a module where its abstraction makes sense to distinguish between exactly two very different kinds of tagging structures like this then this could be a reasonable way to go, but a structure like this does suggest that your module might be trying to solve too many problems at once and so I'd also consider some different designs.
If you are just trying to write a general module that works with virtual networks, which doesn't really need to "know" what the network really represents, then you could consider making it just take arbitrary tags as an input variable and pass them through exactly as given, and then the calling module can choose those tags differently depending on its knowledge of the purpose of the VPC:
variables "vpc_tags" {
type = map(string)
}
data "aws_vpc" "vpc" {
tags = var.vpc_tags
}
Because it seems like you are writing a module that uses a VPC rather than one that manages a VPC, you might also consider using a dependency inversion approach where the module just declares that it needs a VPC but leaves it up to the calling module to decide how to provide it:
variables "vpc" {
# Include here the subset of VPC attributes
# your module actually needs.
type = object({
id = string
cidr_block = string
})
}
Elsewhere in your module you can then use var.vpc.id
in the same situations where you would otherwise have used data.aws_vpc.vpc.id
. The calling module can then either use a data "aws_vpc"
block itself or pass in a VPC it was already managing, depending on what's appropriate for the situation:
data "aws_vpc" "rds" {
tags = {
Name = "rds_vpc"
Type = "database"
}
}
module "uses_vpc" {
source = "./uses-vpc"
vpc = data.aws_vpc.rds
}
resource "aws_vpc" "production" {
cidr_block = "10.1.0.0/16"
tags = {
Cluster = "live_vpc"
Enviornment = "production"
}
}
module "uses_vpc" {
source = "./uses-vpc"
vpc = aws_vpc.production
}
This approach of using either data "aws_vpc"
or resource "aws_vpc"
with the same module can work because both the data resource type and the managed resource type have the id
and cidr_block
attributes that the variable's type constraint requires.
I can't know what design assumptions and constraints are most important for your system, so I can't recommend any one of these approaches in particular, but I raise them because selecting two very different values depending on a boolean variable can sometimes suggest an insufficient separation of concerns.
In your case, for example, I'd worry if my overall system had a lot of conditions based on var.rds_vpc
because that implies a lot of rigidity in your system design. If a later requirement calls for you to add a third VPC, how many different modules would you need to update to achieve that?
Premature generalization can be harmful too -- there's no need to solve problems that you don't have anywhere on the horizion -- but the two alternative patterns I've suggested above are common approaches to separation of concerns in Terraform that don't tend to lead to much additional complexity.