Terraform 0.15.1 多提供程序问题 - 参数 "region" 是必需的,但未设置
Terraform 0.15.1 Multiple Provider Issue - The argument "region" is required, but was not set
下面是我的项目文件结构:
├── main.tf
├── tunnel
│ ├── main.tf
│ └── variables.tf
└── variables.tf
我正尝试按照此处所述在 Terraform 0.15.1 中使用多个提供程序 -> https://www.terraform.io/docs/language/modules/develop/providers.html
按照示例进行操作后,我无法使其正常工作。我现在已经将我的代码简化为只使用一个提供者别名(尽可能简单)。我得到的错误是:
╷
│ Error: Missing required argument
│
│ The argument "region" is required, but was not set.
╵
我的main.tf根目录下的文件:
module "tunnel" {
source = "./tunnel"
providers = {
aws.r = aws.requester
}
}
我的variables.tf在根目录:
provider "aws" {
alias = "requester"
region = "ap-southeast-2"
profile = "benchmark"
}
我的 tunnel/variables.tf 文件:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.r ]
}
}
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
我的 tunnel/main.tf 文件:
# Requester's side of the connection.
resource "aws_vpc_peering_connection" "peer" {
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_owner_id = data.aws_caller_identity.current.account_id
peer_region = data.aws_region.current.name
auto_accept = false
tags = {
Side = "Requester"
}
}
我不明白为什么会出现此错误?这段代码的最终目标是自动化 vpc 对等的两端,如此处所示 -> https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection_accepter 。但我目前坚持让两个 aws 提供者使用不同的凭据(上面示例中的一个提供者来简化事情)。
当我从根 main.tf 中删除 alias = "requester"
时:
provider "aws" {
// alias = "requester"
region = "ap-southeast-2"
profile = "benchmark"
}
和根路径中 main.tf 的提供程序配置:
module "tunnel" {
source = "./tunnel"
// providers = {
// aws.r = aws.requester
// }
}
和来自 tunnel/variables.tf:
的别名配置
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
// configuration_aliases = [ aws.r ]
}
}
}
计划工作正常:
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.tunnel.aws_vpc_peering_connection.peer will be created
+ resource "aws_vpc_peering_connection" "peer" {
+ accept_status = (known after apply)
+ auto_accept = false
+ id = (known after apply)
+ peer_owner_id = "xxxxxxx"
+ peer_region = "ap-southeast-2"
+ peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
+ tags = {
+ "Side" = "Requester"
}
+ vpc_id = "vpc-xxxxxxxxxxx"
+ accepter {
+ allow_classic_link_to_remote_vpc = (known after apply)
+ allow_remote_vpc_dns_resolution = (known after apply)
+ allow_vpc_to_remote_classic_link = (known after apply)
}
+ requester {
+ allow_classic_link_to_remote_vpc = (known after apply)
+ allow_remote_vpc_dns_resolution = (known after apply)
+ allow_vpc_to_remote_classic_link = (known after apply)
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
此错误消息是 Terraform 必须使更简单的情况变得更简单的一些自动行为的结果,但不幸的是,这导致在像您这样的更复杂的情况下情况变得相当不清楚。
在您的子模块中,您已声明它希望在调用方中传递一个替代(别名)提供程序配置,在该模块中将称为 aws.r
。但是,您之后声明的数据资源不包含 provider
参数来指定它们属于哪个提供者配置,因此 Terraform 选择 default(无别名)提供者配置.
不幸的是,您的配置实际上 没有 默认提供程序配置,因为根模块 也 使用备用提供程序配置aws.requester
。因此,Terraform 会自动构建一个空配置,因为这对于像 http
这样不需要任何特殊配置的简单提供程序来说是一种有用的行为。但这并不能最终为 aws
提供商工作,因为它 需要设置 region
。
至少有两种不同的方法可以更改子模块以使其工作。其中哪一个最合适将取决于此模块如何适应您的更广泛的配置。
第一个选项是让子模块根本不声明 aws.r
,而是始终使用其默认提供程序配置:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
因为您的根模块没有 hashicorp/aws
的默认配置,您仍然需要在模块调用中明确指出该模块的默认提供程序是 aws.requester
提供程序,因为根模块看到它:
module "tunnel" {
source = "./tunnel"
providers = {
aws = aws.requester
}
}
对于不需要多个 AWS 提供商配置的共享模块来说,这种方法是一个不错的选择,因为模块本身可以完全不知道其调用者中的多个配置,而只是期望给出 hashicorp/aws
使用的默认配置。
但是,如果您的子模块也需要对 hashicorp/aws
进行不止一种配置,那么它将无法工作。在这种情况下,您将需要我接下来将描述的其他选项。
当共享模块将使用多个提供者配置时,我们需要为它希望从其调用者传递的每个配置声明一个 configuration_aliases
条目。你在你的例子中只展示了一个叫做 r
的,我不知道“r”代表什么,所以为了这里的例子我将称它们为“src”(“源”)和"dst" for ("destination") 只是为了举例说明一些有意义的术语。
我们将从 configuration_aliases
配置开始:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.src, aws.dst ]
}
}
}
configuration_aliases
中给出的每一项都声明了一个配置地址,在对该模块的任何调用中,providers
参数中必须有一个对应的条目,我们稍后会看到。
由于此模块不希望使用 默认(无别名)配置,我们现在需要为每个资源块告诉 Terraform 它属于哪个提供者配置。从您的数据资源开始,假设它们属于“源”端:
data "aws_region" "current" {
provider = aws.src
}
data "aws_caller_identity" "current" {
provider = aws.src
}
我怀疑在您的真实系统中,您显示的 aws_vpc_peering_connection
资源在逻辑上可能也属于“源”端,但由于您没有显示任何其他资源,我将任意分配它到 aws.dst
以显示它的样子:
resource "aws_vpc_peering_connection" "peer" {
provider = aws.dst
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_owner_id = data.aws_caller_identity.current.account_id
peer_region = data.aws_region.current.name
auto_accept = false
tags = {
Side = "Requester"
}
}
该模块中的每个 data
和 resource
块都需要设置 provider
,因为默认情况下此模块中没有 select 的默认提供程序配置.
调用模块时,需要告诉 Terraform 调用方中的哪些提供程序配置映射到被调用模块中的 src
和 dst
配置:
module "tunnel" {
source = "./tunnel"
providers = {
aws.src = aws.requester
aws.dst = aws.peer
}
}
正如我之前提到的,我们需要在 providers
中为模块中声明的每个 configuration_aliases
分配一个条目。将这些替代提供程序配置视为与输入变量有些相似可能会有所帮助,但它们具有更专业的声明和定义语法,因为提供程序是 Terraform 执行模型的基础,需要在正常表达式评估成为可能之前解决.
这里我只是任意选择“peer”作为您在根模块中声明的假定第二个配置的名称。将调用者中的默认配置分配给被调用模块中的替代配置也是有效的,例如 aws.src = aws
,但这似乎不适用于您的情况,因为您在根目录中没有默认配置模块之一。
下面是我的项目文件结构:
├── main.tf
├── tunnel
│ ├── main.tf
│ └── variables.tf
└── variables.tf
我正尝试按照此处所述在 Terraform 0.15.1 中使用多个提供程序 -> https://www.terraform.io/docs/language/modules/develop/providers.html
按照示例进行操作后,我无法使其正常工作。我现在已经将我的代码简化为只使用一个提供者别名(尽可能简单)。我得到的错误是:
╷
│ Error: Missing required argument
│
│ The argument "region" is required, but was not set.
╵
我的main.tf根目录下的文件:
module "tunnel" {
source = "./tunnel"
providers = {
aws.r = aws.requester
}
}
我的variables.tf在根目录:
provider "aws" {
alias = "requester"
region = "ap-southeast-2"
profile = "benchmark"
}
我的 tunnel/variables.tf 文件:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.r ]
}
}
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
我的 tunnel/main.tf 文件:
# Requester's side of the connection.
resource "aws_vpc_peering_connection" "peer" {
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_owner_id = data.aws_caller_identity.current.account_id
peer_region = data.aws_region.current.name
auto_accept = false
tags = {
Side = "Requester"
}
}
我不明白为什么会出现此错误?这段代码的最终目标是自动化 vpc 对等的两端,如此处所示 -> https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection_accepter 。但我目前坚持让两个 aws 提供者使用不同的凭据(上面示例中的一个提供者来简化事情)。
当我从根 main.tf 中删除 alias = "requester"
时:
provider "aws" {
// alias = "requester"
region = "ap-southeast-2"
profile = "benchmark"
}
和根路径中 main.tf 的提供程序配置:
module "tunnel" {
source = "./tunnel"
// providers = {
// aws.r = aws.requester
// }
}
和来自 tunnel/variables.tf:
的别名配置terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
// configuration_aliases = [ aws.r ]
}
}
}
计划工作正常:
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.tunnel.aws_vpc_peering_connection.peer will be created
+ resource "aws_vpc_peering_connection" "peer" {
+ accept_status = (known after apply)
+ auto_accept = false
+ id = (known after apply)
+ peer_owner_id = "xxxxxxx"
+ peer_region = "ap-southeast-2"
+ peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
+ tags = {
+ "Side" = "Requester"
}
+ vpc_id = "vpc-xxxxxxxxxxx"
+ accepter {
+ allow_classic_link_to_remote_vpc = (known after apply)
+ allow_remote_vpc_dns_resolution = (known after apply)
+ allow_vpc_to_remote_classic_link = (known after apply)
}
+ requester {
+ allow_classic_link_to_remote_vpc = (known after apply)
+ allow_remote_vpc_dns_resolution = (known after apply)
+ allow_vpc_to_remote_classic_link = (known after apply)
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
此错误消息是 Terraform 必须使更简单的情况变得更简单的一些自动行为的结果,但不幸的是,这导致在像您这样的更复杂的情况下情况变得相当不清楚。
在您的子模块中,您已声明它希望在调用方中传递一个替代(别名)提供程序配置,在该模块中将称为 aws.r
。但是,您之后声明的数据资源不包含 provider
参数来指定它们属于哪个提供者配置,因此 Terraform 选择 default(无别名)提供者配置.
不幸的是,您的配置实际上 没有 默认提供程序配置,因为根模块 也 使用备用提供程序配置aws.requester
。因此,Terraform 会自动构建一个空配置,因为这对于像 http
这样不需要任何特殊配置的简单提供程序来说是一种有用的行为。但这并不能最终为 aws
提供商工作,因为它 需要设置 region
。
至少有两种不同的方法可以更改子模块以使其工作。其中哪一个最合适将取决于此模块如何适应您的更广泛的配置。
第一个选项是让子模块根本不声明 aws.r
,而是始终使用其默认提供程序配置:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
因为您的根模块没有 hashicorp/aws
的默认配置,您仍然需要在模块调用中明确指出该模块的默认提供程序是 aws.requester
提供程序,因为根模块看到它:
module "tunnel" {
source = "./tunnel"
providers = {
aws = aws.requester
}
}
对于不需要多个 AWS 提供商配置的共享模块来说,这种方法是一个不错的选择,因为模块本身可以完全不知道其调用者中的多个配置,而只是期望给出 hashicorp/aws
使用的默认配置。
但是,如果您的子模块也需要对 hashicorp/aws
进行不止一种配置,那么它将无法工作。在这种情况下,您将需要我接下来将描述的其他选项。
当共享模块将使用多个提供者配置时,我们需要为它希望从其调用者传递的每个配置声明一个 configuration_aliases
条目。你在你的例子中只展示了一个叫做 r
的,我不知道“r”代表什么,所以为了这里的例子我将称它们为“src”(“源”)和"dst" for ("destination") 只是为了举例说明一些有意义的术语。
我们将从 configuration_aliases
配置开始:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
configuration_aliases = [ aws.src, aws.dst ]
}
}
}
configuration_aliases
中给出的每一项都声明了一个配置地址,在对该模块的任何调用中,providers
参数中必须有一个对应的条目,我们稍后会看到。
由于此模块不希望使用 默认(无别名)配置,我们现在需要为每个资源块告诉 Terraform 它属于哪个提供者配置。从您的数据资源开始,假设它们属于“源”端:
data "aws_region" "current" {
provider = aws.src
}
data "aws_caller_identity" "current" {
provider = aws.src
}
我怀疑在您的真实系统中,您显示的 aws_vpc_peering_connection
资源在逻辑上可能也属于“源”端,但由于您没有显示任何其他资源,我将任意分配它到 aws.dst
以显示它的样子:
resource "aws_vpc_peering_connection" "peer" {
provider = aws.dst
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_vpc_id = "vpc-xxxxxxxxxxxxxxxxx"
peer_owner_id = data.aws_caller_identity.current.account_id
peer_region = data.aws_region.current.name
auto_accept = false
tags = {
Side = "Requester"
}
}
该模块中的每个 data
和 resource
块都需要设置 provider
,因为默认情况下此模块中没有 select 的默认提供程序配置.
调用模块时,需要告诉 Terraform 调用方中的哪些提供程序配置映射到被调用模块中的 src
和 dst
配置:
module "tunnel" {
source = "./tunnel"
providers = {
aws.src = aws.requester
aws.dst = aws.peer
}
}
正如我之前提到的,我们需要在 providers
中为模块中声明的每个 configuration_aliases
分配一个条目。将这些替代提供程序配置视为与输入变量有些相似可能会有所帮助,但它们具有更专业的声明和定义语法,因为提供程序是 Terraform 执行模型的基础,需要在正常表达式评估成为可能之前解决.
这里我只是任意选择“peer”作为您在根模块中声明的假定第二个配置的名称。将调用者中的默认配置分配给被调用模块中的替代配置也是有效的,例如 aws.src = aws
,但这似乎不适用于您的情况,因为您在根目录中没有默认配置模块之一。