我正在创建一个terraform模板,它的一部分可以创建一个VPC。
用户可以选择指定参数create-vpc。这将传递给模块https://github.com/terraform-aws-modules/terraform-aws-vpc,该模块将根据该参数创建VPC,即
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
create_vpc = var.create-vpc
# ... omitted
}我现在试图使用一个data源代码来与我的模板的其余部分共享VPC,即
data "aws_vpc" "myvpc" {
id = "${module.vpc.vpc_id}"
}如果没有创建VPC,我如何更新它以使用变量vpc-id而不是模块输出?
理想情况下,我会做这样的事情:
data "aws_vpc" "myvpc" {
count = "${var.vpc-id != "" ? 1 : 0}"
id = "${module.vpc.vpc_id}"
}
data "aws_vpc" "myvpc" {
count = "${var.vpc-id != "" ? 0 : 1}"
id = var.vpc-id
}这将不起作用,因为资源名称必须是唯一的。
模板中的其他资源引用此VPC。
发布于 2020-04-22 22:10:31
我理解您问题的方式是,您正在编写一个以可选的vpc_id作为参数的模块,如果指定使用它,则使用它,如果没有指定,则创建一个新的VPC本身。然后,您需要在配置的其他地方使用VPC id,不管它是由调用方直接提供的,还是由VPC模块创建的。
如果我正确地理解了这一点,这里有一个方法来完成它。
首先,我们将为您自己的模块声明vpc_id变量,其馀部分将用于做出决定。
variable "vpc_id" {
type = string
default = null # optional with no default value
}由此,我们将得出是否创建VPC的决定,我将在这里以本地值的形式编写VPC,主要用于解释,但您可能会选择在实际使用时内联它,这取决于您觉得最易读的是什么:
locals {
create_vpc = var.vpc_id != null ? true : false
}现在,我们可以在模块和data资源中使用该值,这样我们就可以创建新的VPC或检索有关现有VPC的数据:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
create_vpc = local.create_vpc
# ...
}
data "aws_vpc" "selected" {
count = local.create_vpc ? 0 : 1
id = var.vpc_id
}然后,我们可以编写另一个本地值,选择从这两个位置中的哪个位置派生其他与VPC相关的值,例如id和cidr_block:
locals {
vpc = (
local.create_vpc ?
{
id = module.vpc.vpc_id
cidr_block = module.vpc.vpc_cidr_block
} :
{
id = data.aws_vpc.selected.id
cidr_block = data.aws_vpc.selected.cidr_block
}
)
}然后,您可以在配置的其他地方使用local.vpc.id和local.vpc.cidr_block来获取要使用的适当值,而不管这个模块是否创建了自己的VPC。
以上是对你问题最直接的回答。我还想分享一种不同的方法,它基于Terraform的文档中的模块组成部分中描述的模式,如果您正在构建一个要由另一个Terraform模块调用的共享模块,那么这个方法可能适合您。
使用组合来解决这个问题的另一种方法是,您的模块从来不创建自己的VPC,并且总是期望为其提供一个VPC。这是依赖反演原理的一个例子。下面是你的用例.
在您的模块中,您可以声明一个名为vpc的输入变量,它的结构与我们在前面的方法中创建的最终local.vpc相同:
variable "vpc" {
type = object({
id = string
cidr_block = string
})
# This time the VPC is required. The caller decides how to obtain it.
}然后,您自己的模块的表达式将获得VPC id为var.vpc.id,而不是像前面方法中的local.vpc.id那样。
然后,调用模块可以决定为该变量提供值的几种不同方法:
# Using the terraform-aws-modules/vpc/aws module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
# ...
}
module "your_module" {
source = "./modules/your-module"
vpc = {
id = module.vpc.vpc_id
cidr_block = module.vpc.vpc_cidr_block
}
}# Directly using the aws_vpc resource type
resource "aws_vpc" "example" {
# ...
}
module "your_module" {
source = "./modules/your-module"
vpc = aws_vpc.example
}# Using the aws_vpc data source to find an existing VPC
data "aws_vpc" "example" {
tags = {
Environment = "STAGE"
}
}
module "your_module" {
source = "./modules/your-module"
vpc = data.aws_vpc.example
}换句话说,这可以让您的新模块专注于它试图解决的任何新问题,同时将其与创建VPC的问题分离开来,从而允许调用模块以任何适当的方式获取VPC信息。获得VPC的适当方法可能会随着时间的推移而改变,这种组合方法意味着调用方可以更多地控制他们如何管理不同方法之间的转换,而不依赖于新模块的实现。
模块组合并不总是最好的选择,但我想指出这一点,因为Terraform文档特别建议考虑这种方法,并建议不要使用许多级别的嵌套模块调用。
https://devops.stackexchange.com/questions/11399
复制相似问题