根据您的详细目标,有多种不同的方法可以实现此结果。最直接的答案是使用conditional expression 来选择两个地图值之一:
tags = (
var.rds_vpc ?
{
Name = "rds_vpc"
Type = "database"
} :
{
Cluster = "live_vpc"
Enviornment = "production"
}
)
如果你正在编写一个模块,它的抽象对于区分两种截然不同的标记结构是有意义的,那么这个 可能 是一个合理的方法,但是这样的结构确实建议您的模块可能试图一次解决太多问题,所以我也会考虑一些不同的设计。
如果您只是想编写一个适用于虚拟网络的通用模块,而实际上并不需要“知道”网络真正代表什么,那么您可以考虑让它只将任意标签作为输入变量,然后完全按照给定的方式传递它们,然后调用模块可以根据其对 VPC 用途的了解以不同方式选择这些标签:
variables "vpc_tags" {
type = map(string)
}
data "aws_vpc" "vpc" {
tags = var.vpc_tags
}
因为您似乎正在编写一个使用 VPC 的模块,而不是一个管理 VPC 的模块,所以您也可以考虑使用dependency inversion 方法,其中模块只是声明它需要一个 VPC,但由调用模块决定如何提供它:
variables "vpc" {
# Include here the subset of VPC attributes
# your module actually needs.
type = object({
id = string
cidr_block = string
})
}
然后,您可以在模块中的其他地方使用var.vpc.id,在与其他情况下使用data.aws_vpc.vpc.id 相同的情况下。 调用模块然后可以使用data "aws_vpc"块本身或传入它已经管理的VPC,具体取决于适合情况的内容:
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
}
这种将data "aws_vpc" 或resource "aws_vpc" 用于同一模块的方法可以工作,因为数据资源类型和托管资源类型都具有变量类型约束所需的id 和cidr_block 属性。
我不知道哪些设计假设和约束对您的系统最重要,因此我不能特别推荐这些方法中的任何一种,但我提出它们是因为根据布尔变量选择两个非常不同的值可以有时会提示separation of concerns不足。
例如,在您的情况下,如果我的整个系统有很多基于var.rds_vpc 的条件,我会担心,因为这意味着您的系统设计有很多刚性。如果以后的需求要求您添加第三个 VPC,您需要更新多少个不同的模块才能实现?
过早的泛化也可能是有害的——没有必要解决你在任何地方都没有的问题——但是我上面建议的两种替代模式是 Terraform 中关注点分离的常用方法不会导致太多额外的复杂性。