如果条件的默认值,Terraform 不尊重根模块动态块

问题描述 投票:0回答:1

我正在尝试创建一个通用的 dynamodb terraform 根模块,它可以处理我的组织团队中的一些用例。一些团队需要创建一个具有

PAY_PER_REQUEST
计费模式的 dynamodb,并且该数据库表还需要有一个或多个
global_secondary_index
块。我宁愿用一些条件值来处理所有这些,而不是围绕多个可以保存不同设置的地图创建一些“奇怪”的逻辑。

但是,当其他一些变量未设置或具有特定值时,Terraform 不尊重我的条件默认值。

我目前正在使用它作为我的提供程序和 terraform 版本:

hashicorp/aws v5.32.1
Terraform v1.4.6

例如:如果

billing_mode
PROVISIONED
,团队需要为
global_secondary_index
read_capacity
设置
write_capacity
值,而
billing_mode
PAY_PER_REQUEST
则无法设置这些值或者至少在我查看
0
后需要默认的
terraform.tfstate
。还有一个问题是,当
projection_type
的值为
INCLUDE
时,需要设置
non_key_attributes
,否则无法设置或需要默认为
[]
,再次查看
 terraform.tfstate
其他当前部署的表。

所以我在我的

variables.tf
中为此创建了一个对象映射列表。

variable "global_secondary_indexes" {
  description = "A list of maps defining global secondary indexes"
  type = list(object({
    name               = string
    hash_key           = string
    range_key          = string
    projection_type    = string
    gsi_read_capacity  = number
    gsi_write_capacity = number
    non_key_attributes = list(string)
  }))
  default = []
}

我还尝试将其中一些可选值设置为

any
,以便它可以处理
null
值。

variable "global_secondary_indexes" {
  description = "A list of maps defining global secondary indexes"
  type = list(object({
    name               = string
    hash_key           = string
    range_key          = any
    projection_type    = string
    gsi_read_capacity  = any
    gsi_write_capacity = any
    non_key_attributes = any
  }))
  default = []
}

在我的

main.tf
中,我定义了一个
dynamic
块,如下

resource "aws_dynamodb_table" "general_dynamodb_table" {
  name             = var.name
  billing_mode     = var.billing_mode
  hash_key         = var.hash_key
  range_key        = var.range_key
  read_capacity    = var.read_capacity
  write_capacity   = var.write_capacity

  dynamic "global_secondary_index" {
    for_each = var.global_secondary_indexes
    content {
      name               = global_secondary_index.value.name
      hash_key           = global_secondary_index.value.hash_key
      range_key          = lookup(global_secondary_index.value, "range_key", "")
      projection_type    = global_secondary_index.value.projection_type
      non_key_attributes = global_secondary_index.value.projection_type == "INCLUDE" ? lookup(global_secondary_index.value, "non_key_attributes", []) : []
      read_capacity      = var.billing_mode == "PROVISIONED" ? lookup(global_secondary_index.value, "gsi_read_capacity", 0) : 0
      write_capacity     = var.billing_mode == "PROVISIONED" ? lookup(global_secondary_index.value, "gsi_write_capacity", 0) : 0
    }
  }
}

这是我一直用来部署的测试模块

module "test_dynamodb" {
    source = "../dynamodb"

    name = "test_dynamodb"
    billing_mode = "PAY_PER_REQUEST"
    hash_key = "user_id"

    global_secondary_indexes = [
        {
            name = "my-index-2"
            hash_key = "user_id"
            projection_type = "ALL"
        }
    ]
}

在我将

global_secondary_indexes
块值设置为
any
的示例中,我将其作为我的动态块

  dynamic "global_secondary_index" {
    for_each = var.global_secondary_indexes
    content {
      name               = global_secondary_index.value.name
      hash_key           = global_secondary_index.value.hash_key
      range_key          = lookup(global_secondary_index.value, "range_key", null)
      projection_type    = global_secondary_index.value.projection_type
      non_key_attributes = global_secondary_index.value.projection_type == "INCLUDE" ? lookup(global_secondary_index.value, "non_key_attributes", []) : null
      read_capacity      = var.billing_mode == "PROVISIONED" ? lookup(global_secondary_index.value, "gsi_read_capacity", null) : null
      write_capacity     = var.billing_mode == "PROVISIONED" ? lookup(global_secondary_index.value, "gsi_write_capacity", null) : null
    }
  }

当我尝试部署此模块时,我在所有尝试中都收到此错误

 attributes "gsi_read_capacity", "gsi_write_capacity", "non_key_attributes", and "range_key" are required.

range_key
遵循类似的逻辑,可能不需要在所有情况下都必须进行定义。

amazon-web-services terraform amazon-dynamodb terraform-provider-aws
1个回答
0
投票

在您当前的配置中,所有属性都是必需的

variable "test" {
  type = list(object({
    name = string
    data = number
  }))
}

terraform.tfvars

test = [
  {
    data = 1
    name     = "value"
  },
  {
    name = "foo"
  }
]

如果我们对此进行 Terraform 计划,我们会收到错误:

Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: Invalid value for input variable
│ 
│   on terraform.tfvars line 1:
│    1: test = [
│    2:   {
│    3:     data = 1
│    4:     name     = "value"
│    5:   },
│    6:   {
│    7:     name = "foo"
│    8:   }
│    9: ]
│ 
│ The given value is not suitable for var.test
| declared at main.tf:1,1-16: element 1: attribute "data" is required.
╵

我们可以使用可选修饰符来解决这个问题:
https://developer.hashicorp.com/terraform/language/expressions/type-constraints#optical-object-type-attributes

variable "test" {
  type = list(object({
    name = string
    data = optional(number, 0)
  }))
}

output "test" {
    value = var.test
}

这将向我们展示以下计划:

Changes to Outputs:
  + test = [
      + {
          + data = 1
          + name = "value"
        },
      + {
          + data = 0
          + name = "foo"
        },
    ]

You can apply this plan to save these new output values to the Terraform state,
without changing any real infrastructure.
© www.soinside.com 2019 - 2024. All rights reserved.