Terraform 如何从地形列表中拾取图元

Terraform 如何从地形列表中拾取图元,terraform,Terraform,我正在terraform中创建一系列资源(在本例中为dynamo DB表)。我想将IAM策略应用于其中的子组。例如 resource "aws_dynamodb_table" "foo" { count = "${length(var.tables)}" name = "foo-${element(var.tables,count.index)}" tags { Name = "foo-${element(var.tables,count.index)}"

我正在terraform中创建一系列资源(在本例中为dynamo DB表)。我想将IAM策略应用于其中的子组。例如

resource "aws_dynamodb_table" "foo" {
  count = "${length(var.tables)}"
  name           = "foo-${element(var.tables,count.index)}"
  tags {
    Name = "foo-${element(var.tables,count.index)}"
    Environment = "<unsure how to get this>"
    Source = "<unsure how to get this>"
  }
}
因此:

我想获取已创建的dynamo表的
arn
,这些表具有
c
(即名称为
[“c:dev”,“c:qa”,“c:prod”]
)或
prod
(即名称为
[“a:prod”,“b:prod”,“c:prod”]
)的表

在terraform 0.11(甚至是0.12)上有什么明智的方法可以做到这一点吗

我希望:

  • 通过一些输入(
    environment
    source
    )对dynamo db表资源进行分组,以便我可以对每个组应用一些策略
  • 提取每个创建的输入,以便应用正确的标记
  • 我想,与其创建跨产品列表,不如为每个输入创建地图:

    {
      "a": ["dev","qa","prod"],
      "b": ["dev","qa","prod"],
      "c": ["dev","qa","prod"]
    }
    

    这样可以很容易地找到每个资源的目标名称,因为我可以通过输入查找,但这只会给出名称,而不便于获取实际资源(因此,
    arn
    s)


    谢谢

    Terraform 0.12解决方案是自动导出笛卡尔积(使用
    setproduct
    ),并使用
    for
    表达式将其塑造成适合您需要的形式。例如:

    locals {
      environments = ["dev", "qa", "prod"]
      sources      = ["a", "b", "c"]
    
      tables = [for pair in setproduct(local.environments, local.sources) : {
        environment = pair[0]
        source      = pair[1]
        name        = "${pair[1]}:${pair[0]}"
      })
    }
    
    resource "aws_dynamodb_table" "foo" {
      count = length(local.tables)
      name  = "foo-${local.tables[count.index].name}"
      tags {
        Name        = "foo-${local.tables[count.index].name}"
        Environment = local.tables[count.index].environment
        Source      = local.tables[count.index].source
      }
    }
    
    在我写这篇文章的时候,每个功能的资源仍在开发中,但是在不久的将来Terraform v0.12的小版本中,应该可以通过使这些表实例都通过它们的名称而不是它们在
    本地表中的位置来进一步改进这一点。表
    列表:

    # (with the same "locals" block as in the above example)
    
    resource "aws_dynamodb_table" "foo" {
      for_each = { for t in local.tables : t.name => t }
    
      name  = "foo-${each.key}"
      tags {
        Name        = "foo-${each.key}"
        Environment = each.value.environment
        Source      = each.value.source
      }
    }
    
    除了清除语法中的一些冗余之外,这个新的
    for_each
    表单将使Terraform使用
    aws_dynamodb_table.foo[“a:dev”]
    等地址来识别这个实例,而不是
    aws_dynamodb_table.foo[0]
    ,这意味着您可以自由地添加和删除两个初始列表的成员,而不会因为列表索引的更改而导致其他实例的混乱和替换


    在Terraform0.11中,这类事情将更难实现。有一些通用模式可以帮助将某些仅0.12版本的结构转换为0.11版本的兼容功能,在这里可能会起作用:

    • 如果结果仅是字符串值的映射,则可以使用
      数据“null\u data\u source”
      块模拟
      for
      表达式返回的序列(其周围是方括号,而不是大括号)
    • 原则上,命名局部值中的Terraform 0.12对象可以替换为每个对象属性的局部值的单独简单贴图,使用每个贴图中的一组公共关键点
    • Terraform 0.11没有
      setproduct
      功能,但是对于这么小的序列,像在这里的问题中那样自己写出笛卡尔积并不是什么大问题

    结果肯定会非常不美观,但我希望如果你应用上述想法并做出一些妥协,就有可能在Terraform 0.11上实现某种效果。

    我在阅读答案时,想,“响应者真的了解Terraform!”然后我看到它是
    显然是智能的,这是有意义的。:-)是的,我想在0.12中实现它,但是这里的用例仍然有0.11依赖项,所以还不太可行。为了回答您的问题,我不能手工写出产品,因为它是传入的变量。我在示例中使用了
    locals
    ,以简化并使其易于运行。
    {
      "dev":  ["a","b","c"],
      "qa":   ["a","b","c"],
      "prod": ["a","b","c"]
    }
    
    locals {
      environments = ["dev", "qa", "prod"]
      sources      = ["a", "b", "c"]
    
      tables = [for pair in setproduct(local.environments, local.sources) : {
        environment = pair[0]
        source      = pair[1]
        name        = "${pair[1]}:${pair[0]}"
      })
    }
    
    resource "aws_dynamodb_table" "foo" {
      count = length(local.tables)
      name  = "foo-${local.tables[count.index].name}"
      tags {
        Name        = "foo-${local.tables[count.index].name}"
        Environment = local.tables[count.index].environment
        Source      = local.tables[count.index].source
      }
    }
    
    # (with the same "locals" block as in the above example)
    
    resource "aws_dynamodb_table" "foo" {
      for_each = { for t in local.tables : t.name => t }
    
      name  = "foo-${each.key}"
      tags {
        Name        = "foo-${each.key}"
        Environment = each.value.environment
        Source      = each.value.source
      }
    }