用于 Localstack 的 Terraform Override Provider

Terraform Override Provider for use with Localstack

我有一个 Git 存储库,其中包含正在部署到 AWS 中的 Terraform 代码。我正在将 Localstack 添加到此存储库,以便我可以在计划之前进行更高级别的验证测试并将其应用到我的真实 AWS 帐户中。为了使用 Localstack,我必须使用自定义端点创建一个新的提供程序:

provider "aws" {
  alias  = "real"
  region = "${local.aws_region}"
}

provider "aws" {
  alias                       = "fake"
  region                      = "${local.aws_region}"
  access_key                  = "fake"
  secret_key                  = "fake"
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_requesting_account_id  = true

  endpoints {
    dynamodb = "http://localhost:4566"
    lambda   = "http://localhost:4566"
    kinesis  = "http://localhost:4566"
  }
}

如何在不复制我的代码的情况下,将一个提供商用于 Localstack,将一个提供商用于 AWS?

不幸的是,因为这两种情况下的配置结构有很大不同,所以如果不让结果配置看起来非常复杂,就不可能动态切换,但是可以使用 Terraform 语言表达式运算符和 dynamic 块有条件地设置所有提供者参数,因此具有具有动态设置的单个提供者配置而不是两个单独的提供者配置。

首先要决定的是您将如何在这两种可能性之间做出决定。由于您的 localstack 伪基础设施将不可避免地与“真实”基础设施不同,我希望您会希望为其使用单独的状态,因此这可能是使用单独的 workspace 的合理情况 development/testing,并且我将编写此示例,假设只要选择工作区 dev,localstack 配置就应该处于活动状态。如果这不是您想要的,那么希望这仍然足以满足您的需求。

locals {
  use_localstack = (terraform.workspace == "dev")

  aws_settings = (
    local.use_localstack ?
    {
      region     = local.aws_region
      access_key = "fake"
      secret_key = "fake"

      skip_credentials_validation = true
      skip_metadata_api_check     = true
      skip_requesting_account_id  = true

      override_endpoint = "http://localhost:4566"
    } :
    {
      region     = local.aws_region
      access_key = null
      secret_key = null
      
      skip_credentials_validation = null
      skip_metadata_api_check     = null
      skip_requesting_account_id  = null

      override_endpoint = null
    }
  )
}

provider "aws" {
  region     = local.aws_settings.region
  access_key = local.aws_settings.access_key
  secret_key = local.aws_settings.secret_key

  skip_credentials_validation = local.aws_settings.skip_credentials_validation
  skip_metadata_api_check     = local.aws_settings.skip_metadata_api_check
  skip_requesting_account_id  = local.aws_settings.skip_requesting_account_id

  dynamic "endpoints" {
    for_each = local.aws_settings.override_endpoint[*]
    content {
      dynamodb = endpoints.value
      lambda   = endpoints.value
      kinesis  = endpoints.value
    }
  }
}

以上依赖于 Terraform 语言的两个特定行为:

  • 设置将传递给提供者的参数时,设置 null 始终与省略该参数相同,因为 Terraform 内部通过隐式将它们设置为 null 来处理未设置的参数。
  • 仅当 override_endpoint 属性为非空时才使用 [*] with a non-list value automatically converts it into a zero-element list or a one-element list, depending on whether the value is null. That allows us to dynamically declare the endpoints block,然后将其值写入所有三个覆盖的端点参数。