Terraform 0.15.1 多提供商问题 - 参数“区域";是必需的,但未设置 [英] Terraform 0.15.1 Multiple Provider Issue - The argument "region" is required, but was not set

查看:19
本文介绍了Terraform 0.15.1 多提供商问题 - 参数“区域";是必需的,但未设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以下面是我的项目文件结构:

so below is my project file structure:

├── main.tf
├── tunnel
│   ├── main.tf
│   └── variables.tf
└── variables.tf

我正在尝试在 Terraform 0.15.1 中使用多个提供程序,如此处所述 ->https://www.terraform.io/docs/language/modules/开发/providers.html

I am trying to use multiple providers in Terraform 0.15.1 as described here -> https://www.terraform.io/docs/language/modules/develop/providers.html

按照示例后,我无法使其工作.我现在已经简化了我的代码,只使用一个提供者别名(尽可能简单).我得到的错误是:

After following the example I am not able to get it work. I have now simplified my code down to just use one single provider alias(keep it as simple as possible). The error I am getting is:

╷
│ Error: Missing required argument
│ 
│ The argument "region" is required, but was not set.
╵

我在根目录下的 main.tf 文件:

My main.tf file in root directory:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws.r = aws.requester
  }
}

我的 variables.tf 在根目录中:

my variables.tf in root directory:

provider "aws" {
  alias  = "requester"
  region = "ap-southeast-2"
  profile = "benchmark"
}

我的隧道/variables.tf 文件:

my tunnel/variables.tf file:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 2.7.0"
      configuration_aliases = [ aws.r ]
    }
  }
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

我的隧道/main.tf 文件:

my tunnel/main.tf file:

# 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 提供程序使用不同的凭据(上面示例中的一个提供程序以简化事情).

I don't understand why I am getting this error? The goal with this code eventually is to automate both sides of the vpc peering as shown here -> https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection_accepter . But I am currently stuck on getting two aws providers working with different credentials (one provider in the example above to simplify things).

当我从根 main.tf 中删除 alias = "requester" 时:

When I remove alias = "requester" from the root main.tf:

provider "aws" {
//  alias  = "requester"
  region = "ap-southeast-2"
  profile = "benchmark"
}

以及根路径中 main.tf 中的提供程序配置:

and the provider config from main.tf in root path:

module "tunnel" {
  source    = "./tunnel"
//  providers = {
//    aws.r = aws.requester
//  }
}

以及来自 tunnel/variables.tf 的别名配置:

and the alias config from 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 必须使更简单的情况变得更简单的一些自动行为的结果,但不幸的是,这导致情况在更复杂的情况下相当不清楚喜欢你的.

This error message is the result of a few automatic behaviors Terraform has to make simpler cases simpler, but which unfortunately lead to the situation being rather unclear in more complicated situations like yours.

在您的子模块中,您已声明它希望在调用者中传递一个替代(别名)提供程序配置,在此模块中将称为 aws.r.但是,您之后声明的数据资源不包含用于指定它们属于哪个提供程序配置的 provider 参数,因此 Terraform 选择 默认(无别名)提供程序配置.

In your child module you've declared that it expects an alternative (aliased) provider configuration to be passed in the caller, which within this module will be known as aws.r. However, the data resources you declared afterwards don't include a provider argument to specify which provider configuration they belong to, and so Terraform is choosing the default (unaliased) provider configuration.

不幸的是,您的配置实际上默认提供程序配置,因为根模块使用替代提供程序配置aws.requester.因此,Terraform 会自动构造一个空配置,因为这对于像 http 这样不需要任何特殊配置的简单提供程序来说是一种有用的行为.但这对 aws 提供程序最终不起作用,因为它需要 region 被设置.

Unfortunately, your configuration doesn't actually have a default provider configuration, because the root module is also using an alternative provider configuration aws.requester. As a result, Terraform is automatically constructing one with an empty configuration, because that's a useful behavior for simple providers like http which don't require any special configuration. But that doesn't end up working for the aws provider, because it requires region to be set.

至少有两种不同的方法可以更改子模块以使其工作.其中哪一个最合适将取决于该模块如何适应您的更广泛的配置.

There are at least two different ways you could change the child module to make this work. Which of these will be most appropriate will depend on how this module fits in with your broader configuration.

第一种选择是让子模块根本不声明 aws.r,而只使用其默认的提供程序配置:

The first option would be to have the child module not declare aws.r at all, and just use its default provider configuration throughout:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 2.7.0"
    }
  }
}

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

因为您的根模块没有 hashicorp/aws 的默认配置,所以您仍然需要在模块调用中明确指出该模块的默认提供程序是 aws.requester 提供者作为根模块看到它:

Because your root module doesn't have a default configuration for hashicorp/aws you'll still need to be explicit in the module call that the default provider for the module is the aws.requester provider as the root module sees it:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws = aws.requester
  }
}

对于不需要多个 AWS 提供程序配置的共享模块,这种方法是一个不错的选择,因为模块本身可能完全不知道其调用者中的多个配置,而只是期望获得一个hashicorp/aws 使用的默认配置.

This approach is a good choice for a shared module that doesn't need more than one AWS provider configuration, because the module itself can then be totally unaware of the multiple configurations in its caller, and instead just expect to be given a default configuration for hashicorp/aws to use.

但是,如果您的子模块也需要为 hashicorp/aws 进行多个配置,则它不会起作用.在这种情况下,您将需要我接下来要描述的另一个选项.

However, it wouldn't work if your child module needs to have more than one configuration for hashicorp/aws too. In that case, you'll need the other option I'll describe next.

当一个共享模块将使用多个提供者配置时,我们需要为它希望从其调用者传递的每个配置声明一个 configuration_aliases 条目.您在示例中只显示了一个名为 r 的内容,我不知道r"是什么.代表,所以为了这里的例子,我将称它们为src".(对于源")和dst"for ("destination") 只是为了举例说明一些有意义的术语.

When a shared module will work with more than one provider configuration, we need to declare a configuration_aliases entry for each configuration it expects to be passed from its caller. You only showed one called r in your examples, and I don't know what "r" represents, so for the sake of examples here I'm going to call them "src" (for "source") and "dst" for ("destination") just to have some meaningful terms to hook onto for the sake of example.

我们将从 configuration_aliases 配置开始:

We'll start with the configuration_aliases configuration:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 2.7.0"
      configuration_aliases = [ aws.src, aws.dst ]
    }
  }
}

configuration_aliases 中给出的每一项都声明了一个配置地址,在对该模块的任何调用中,该地址必须在 providers 参数中具有相应的条目,我们将看到稍后.

Each of the items given in configuration_aliases declares a configuration address that must have a corresponding entry in the providers argument in any call to this module, which we'll see later.

由于该模块不希望使用默认(无别名)配置,我们现在需要为每个资源块告诉 Terraform 它属于哪个提供程序配置.从您的数据资源开始,让我们假设它们属于源";结束:

Since this module is not expecting to use a default (unaliased) configuration, we are now required to tell Terraform for each resource block which provider configuration it belongs to. Starting with your data resources, let's assume they belong to the "source" end:

data "aws_region" "current" {
  provider = aws.src
}

data "aws_caller_identity" "current" {
  provider = aws.src
}

我怀疑在您的真实系统中,您显示的 aws_vpc_peering_connection 资源可能在逻辑上属于源"资源.侧面也是,但由于您没有显示任何其他资源,我只是将其任意分配给 aws.dst 以显示它的样子:

I suspect that in your real system the aws_vpc_peering_connection resource you showed probably logically belongs to the "source" side too, but since you didn't show any other resources I'm just going to arbitrarily assign it to aws.dst to show what that looks like:

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"
  }
}

该模块中的每个 dataresource 块都需要设置 provider,因为默认情况下没有可供选择的默认提供程序配置在这个模块中.

Every data and resource block in that module will need to have provider set, because there is no default provider configuration to select by default in this module.

当您调用模块时,您需要告诉 Terraform 调用者中的哪些提供程序配置映射到被调用模块中的 srcdst 配置:

When you call the module, you'll need to tell Terraform which of the provider configurations in the caller map to the src and dst configurations in the called module:

module "tunnel" {
  source    = "./tunnel"
  providers = {
    aws.src = aws.requester
    aws.dst = aws.peer
  }
}

正如我之前提到的,对于模块内声明的每个 configuration_aliases,我们需要在 providers 中添加一个条目.将这些替代提供程序配置视为与输入变量有些相似可能会有所帮助,但它们具有更专业的声明和定义语法,因为提供程序对于 Terraform 的执行模型非常基础,需要在正常表达式评估之前解决.

As I mentioned earlier, we need one entry in providers for each of the configuration_aliases declared inside the module. It might be helpful to think of these alternative provider configurations as being somewhat similar to input variables, but they have a more specialized syntax for declaration and definition because providers are so fundamental to Terraform's execution model and need to be resolved before normal expression evaluation is possible.

这里我只是随意选择了peer";作为您在根模块中声明的假定第二个配置的名称.将调用者中的默认配置分配给被调用模块中的替代配置也是有效的,例如 aws.src = aws,但这似乎不适用于您的情况,因为您没有在根模块中也有默认配置.

Here I just arbitrarily chose "peer" as the name for a presumed second configuration you have declared in your root module. It's also valid to assign a default configuration in the caller to an alternative configuration in the called module, like aws.src = aws, but that doesn't seem to apply in your situation because you don't have a default configuration in the root module either.

这篇关于Terraform 0.15.1 多提供商问题 - 参数“区域";是必需的,但未设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆