Terraform 如何有条件地向动态标记添加属性?

Terraform 如何有条件地向动态标记添加属性?,terraform,Terraform,在config.meta文件中,我存储了对google bigquery数据集的访问。访问对象是一个字典列表,其中每个字典都包含作为第一个元素和第二个元素元素的角色(例如特殊组或通过电子邮件对组),这些元素在列表中变化 我的目标是动态地应用访问。当访问列表上的每个字典都有相同的第二个元素时(例如,仅特殊组),这种方法非常简单但如何动态应用它们取决于第二个元素名称/值? # config.meta file { "accesses": [ { "ro

在config.meta文件中,我存储了对google bigquery数据集的访问。
访问
对象是一个字典列表,其中每个字典都包含作为第一个元素和第二个元素元素的角色(例如
特殊组
通过电子邮件对组
),这些元素在列表中变化

我的目标是动态地应用访问。当
访问
列表上的每个字典都有相同的第二个元素时(例如,仅
特殊组
),这种方法非常简单但如何动态应用它们取决于第二个元素名称/值?

# config.meta file
{
    "accesses": [
        {
            "role": "OWNER",
            "special_group": "projectOwners"
        },
        {
            "role": "READER",
            "group_by_email": "myemail@myemail.com"
        },
       ...
    ]
    ...
}
地形文件:

resource "google_bigquery_dataset" "dataset" {
    dataset_id    = "${var.dataset}"
    location      = "${var.bq_region}"
    friendly_name = "${var.dataset}"

    dynamic "access" {
        # get accesses (list of dictionaries) from a file
        for_each = [for a in jsondecode(file("$config.meta"))["access"]: {
            role = a.role
            special_group = a.special_group
            # how to get special_group/group_by name conditionally?
            # like: if dictionary has the key 'special_group' create that variable
            # othervise create 'group_by_name'
        }]

        content {
            role = access.value.role
            special_group = access.value.special_group
            # how to get special_group/group_by name conditionally?
            # like: if the 'special_group' had been declared add 'special_group' to the access block
            # othervise add 'group_by_name'.
        }
    }

}
如何有条件地向动态标记添加属性

locals {
  items = fileexists("$config.meta") ? jsondecode(file("$config.meta")).accesses : []
  special_groups = [for v in local.items: v if lookup(v, "special_group", "") != ""]
  group_by_emails = [for v in local.items: v if lookup(v, "group_by_email", "") != ""]
}
您可以使用
动态
块的多个定义

resource "google_bigquery_dataset" "dataset" {

  ...

  dynamic "access" {
    for_each = [for a in local.special_groups: {
      role = lookup(a, "role", "")
      special_group = lookup(a, "special_group", "")
    }]

    content {
      role          = access.value.role
      special_group = access.value.special_group
    }
  }

  dynamic "access" {

    for_each = [for a in local.group_by_emails: {
      role = lookup(a, "role", "")
      group_by_email = lookup(a, "group_by_email", "")
    }]

    content {
      role           = access.value.role
      group_by_email = access.value.group_by_email
    }
  }

}
您可以使用
动态
块的多个定义

resource "google_bigquery_dataset" "dataset" {

  ...

  dynamic "access" {
    for_each = [for a in local.special_groups: {
      role = lookup(a, "role", "")
      special_group = lookup(a, "special_group", "")
    }]

    content {
      role          = access.value.role
      special_group = access.value.special_group
    }
  }

  dynamic "access" {

    for_each = [for a in local.group_by_emails: {
      role = lookup(a, "role", "")
      group_by_email = lookup(a, "group_by_email", "")
    }]

    content {
      role           = access.value.role
      group_by_email = access.value.group_by_email
    }
  }

}

在Terraform的配置块中,省略可选参数并将该参数设置为
null
是等效的。因为
access
是一个嵌套块,我们可以利用它来编写有条件地设置参数的表达式

  dynamic "access" {
    # get accesses (list of dictionaries) from a file
    for_each = [for a in jsondecode(file("$config.meta"))["access"]: {
      role           = a.role
      special_group  = try(a.special_group, null)
      group_by_email = try(a.group_by_email, null)
    }]

    content {
      role           = access.value.role
      special_group  = access.value.special_group
      group_by_email = access.value.group_by_email
    }
  }
这首先使用,以便丢失的属性将导致返回到
null
值,而不是错误。这意味着生成的对象将如下所示:

[
  {
    "role": "OWNER",
    "special_group": "projectOwners",
    "group_by_name": null,
  },
  {
    "role": "READER",
    "special_group": null,
    "group_by_email": "myemail@myemail.com",
  },
]
内容
块中,我们直接分配所有这些内容。由于我前面描述的行为,
null
将被Terraform视为根本没有设置。(请注意,在构造对象值时,将
null
视为unset的行为不适用:这是一种特殊行为,仅适用于块内的直接参数。)

这将产生与直接写出以下两个
access
块相同的效果:

access {
  role          = "OWNER"
  special_group = "projectOwners"
}

access {
  role           = "READER"
  group_by_email = "myemail@myemail.com"
}

在Terraform的配置块中,省略可选参数并将该参数设置为
null
是等效的。因为
access
是一个嵌套块,我们可以利用它来编写有条件地设置参数的表达式

  dynamic "access" {
    # get accesses (list of dictionaries) from a file
    for_each = [for a in jsondecode(file("$config.meta"))["access"]: {
      role           = a.role
      special_group  = try(a.special_group, null)
      group_by_email = try(a.group_by_email, null)
    }]

    content {
      role           = access.value.role
      special_group  = access.value.special_group
      group_by_email = access.value.group_by_email
    }
  }
这首先使用,以便丢失的属性将导致返回到
null
值,而不是错误。这意味着生成的对象将如下所示:

[
  {
    "role": "OWNER",
    "special_group": "projectOwners",
    "group_by_name": null,
  },
  {
    "role": "READER",
    "special_group": null,
    "group_by_email": "myemail@myemail.com",
  },
]
内容
块中,我们直接分配所有这些内容。由于我前面描述的行为,
null
将被Terraform视为根本没有设置。(请注意,在构造对象值时,将
null
视为unset的行为不适用:这是一种特殊行为,仅适用于块内的直接参数。)

这将产生与直接写出以下两个
access
块相同的效果:

access {
  role          = "OWNER"
  special_group = "projectOwners"
}

access {
  role           = "READER"
  group_by_email = "myemail@myemail.com"
}

这会起作用,但会增加复杂性。请参阅Martin Atkins答案,以获得更简单的解决方案和对底层机制更完整的解释。这将起作用,但会增加复杂性。参见Martin Atkins答案,以获得更简单的解决方案和对基本力学的更完整解释。