【问题标题】:Needing multiple counts on a Terraform resource?需要对 Terraform 资源进行多次计数?
【发布时间】:2019-12-14 03:51:53
【问题描述】:

我有以下 Terraform 资源,旨在为每个仓库创建一个单独的加密 EFS 卷,然后在两个子网中为每个创建挂载目标:

resource "aws_efs_file_system" "efs-data-share" {
  count      = "${length(var.warehouses)}"
  encrypted  = "${var.encrypted}"
  kms_key_id = "${element(data.aws_kms_key.encryption_key.*.arn,count.index)}"
  performance_mode = "${var.performance_mode}"

  tags {
    Name        = "${element(split(".",var.warehouses[count.index]),0)}-${var.name_suffix}"
    Warehouse   = "${element(split(".",var.warehouses[count.index]),0)}"
    Environment = "${var.environment}"
    Purpose  = "${var.purpose}"
  }
}

resource "aws_efs_mount_target" "mounts" {
  count           = "${length(var.subnets)}"
  file_system_id  = "${aws_efs_file_system.efs-data-share.*.id}"
  subnet_id       = "${element(var.subnets, count.index)}"
  security_groups = ["${var.efs_security_groups}"]
}

data "aws_kms_key" "encryption_key" {
  count = "${length(var.warehouses)}"
  key_id = "alias/${element(split(".",var.warehouses[count.index]),0)}-${var.key_alias_suffix}"
}

EFS 本身启动正常,但挂载失败,因为 file_system_id 必须是单个资源,而不是列表。

    * module.prod_multi_efs.aws_efs_mount_target.mounts[1]: file_system_id must be a single value, not a list
    * module.prod_multi_efs.aws_efs_mount_target.mounts[0]: file_system_id must be a single value, not a list

我不确定在 Terraform 语法方面我有什么办法。在每种情况下我都需要两个挂载,所以我的计数是子网变量的长度,为此我传入了子网 123456 和子网 567890。如何让系统为每个 EFS 进行两次挂载(按仓库列表的长度计算总共七个),而不能在 aws_efs_mount_target 中使用第二个计数?

这是我调用模块的方式:

module "prod_multi_efs" {
  source              = "../../../../Modules/Datastore/MultiEFS"
  efs_security_groups = ["${aws_security_group.prod-efs-group.id}"]
  environment         = "Prod"
  name_suffix         = "${module.static_variables.prod_efs_name}"
  key_alias_suffix    = "prod-efs-${module.static_variables.account_id}-us-east-1"
  subnets             = ["${module.prod_private_subnet_1.subnet_id}", "${module.prod_private_subnet_2.subnet_id}"]
  warehouses          = "${module.static_variables.warehouses}" #The list of seven warehouses
}

这是我的计划,尝试根据以下答案添加 [count.index] - 它执行两次安装,但仅安装到 7 个 FS ID 中的前 2 个:

  + module.stg_multi_efs.aws_efs_mount_target.mounts[0]
      id:                                      <computed>
      dns_name:                                <computed>
      file_system_arn:                         <computed>
      file_system_id:                          "fs-123456"
      ip_address:                              <computed>
      network_interface_id:                    <computed>
      security_groups.#:                       "1"
      security_groups.4286231943:              "sg-xxxxxxxxxx"
      subnet_id:                               "subnet-aaaaaaaa"

  + module.stg_multi_efs.aws_efs_mount_target.mounts[1]
      id:                                      <computed>
      dns_name:                                <computed>
      file_system_arn:                         <computed>
      file_system_id:                          "fs-567890"
      ip_address:                              <computed>
      network_interface_id:                    <computed>
      security_groups.#:                       "1"
      security_groups.4286231943:              "sg-xxxxxxxxxxx"
      subnet_id:                               "subnet-bbbbbbbbbb"

【问题讨论】:

    标签: terraform terraform-provider-aws amazon-efs


    【解决方案1】:

    Terraform 0.12 引入了一个新函数 setproduct,用于需要一组对象来表示来自两个或多个集合的元素的每个组合:

    locals {
      data_share_subnets = [
        for pair in setproduct(aws_efs_file_system.efs-data-share, var.subnets) : {
          file_system_id = pair[0].id
          subnet_id      = pair[1]
        }
      ]
    }
    

    上面将local.data_share_subnets 声明为这样的数据结构:

    [
      {"file_system_id": "fs-123456", "subnet_id": "subnet-aaaaaaaa"},
      {"file_system_id": "fs-123456", "subnet_id": "subnet-bbbbbbbb"}
      {"file_system_id": "fs-567890", "subnet_id": "subnet-aaaaaaaa"},
      {"file_system_id": "fs-567890", "subnet_id": "subnet-bbbbbbbb"}
    ]
    

    然后,您可以将其与 0.12.6 中引入的新 for_each 功能一起使用,为该集合中的每个条目声明一个 aws_efs_mount_target 实例:

    resource "aws_efs_mount_target" "mounts" {
      for_each = { for o in local.data_share_subnets : "${o.file_system_id}:${o.subnet_id}" => o }
    
      file_system_id  = each.value.file_system_id
      subnet_id       = each.value.subnet_id
      security_groups = var.efs_security_groups
    }
    

    for_each 参数中的for 表达式将上面显示的列表转换为一个映射,其键类似于"fs-123456:subnet-aaaaaaaa"。然后,Terraform 将使用如下地址跟踪这些实例:

    • aws_efs_mount_target.mounts["fs-123456:subnet-aaaaaaaa"]
    • aws_efs_mount_target.mounts["fs-123456:subnet-bbbbbbbb"]

    ...这意味着您可以安全地添加和删除单个文件系统和子网,而不会干扰任何其他不相关的挂载目标实例。 (使用count 则不正确,因为实例将通过它们在列表中的位置来识别。)

    在 Terraform 0.11 或更早版本中没有与上述直接等效的内容。

    【讨论】:

      【解决方案2】:

      如果我这样做,我会收到以下错误 “for_each”值取决于无法确定的资源属性 直到应用,因​​此 Terraform 无法预测将创建多少个实例。 要解决此问题,请使用 -target 参数首先仅应用 for_each 所依赖的资源。”

      【讨论】:

        猜你喜欢
        • 2021-12-19
        • 2020-06-28
        • 2015-12-29
        • 2023-03-18
        • 2019-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-02
        相关资源
        最近更新 更多