将地图列表映射到terraform中选定字段值的列表

将地图列表映射到terraform中选定字段值的列表,terraform,Terraform,如果资源使用count参数指定terraform中的多个资源,则有一种简单的语法可用于为资源实例提供专用字段的列表/数组 比如说 aws_subnet.foo.*.id 由于有相当多的版本,可以用复杂的结构声明变量,例如映射列表 variable "data" { type = "list" default = [ { id = "1" ... }, { id = "10" ... } ] } 我正在

如果资源使用count参数指定terraform中的多个资源,则有一种简单的语法可用于为资源实例提供专用字段的列表/数组

比如说

aws_subnet.foo.*.id
由于有相当多的版本,可以用复杂的结构声明变量,例如映射列表

variable "data" {
  type = "list"
  default = [
    {
      id = "1"
      ...
    },
    {
      id = "10"
      ...
    }
  ]
}
我正在寻找一种可能性,可以对多资源的变量执行相同的操作:将数组投影到数组元素的字段值数组

不幸的是

var.data.*.id

不适用于资源。有没有可能做到这一点?

在撰写本文时,Terraform在其插值语言中没有通用的投影功能。“splat语法”是作为资源的特例实现的

虽然深部结构是可能的,但使用起来还不方便,所以建议还是保持相对平坦。将来可能会添加新的语言功能,以使这类功能更可用。

UPDATE 自从terraform 0.12发布以来,terraform中添加了大量奇特的功能,例如列表理解,解决方案非常简单

locals {
  ids = [for d in var.data: d.id]
  #ids = [for d in var.data: d["id"]]  #same
}

# Then you could get the elements this way,
#     local.ids[0]

地形0.12之前的解决方案

我可以帮你

data "template_file" "data_id" {
  count = "${length(var.data)}"
  template = "${lookup(var.data[count.index], "id")}"
}
然后您将得到一个列表
“${data.template\u file.data\u id.*.rendered}”
,其元素是“id”的值

您可以像这样通过索引获取它的元素

"${data.template_file.data_id.*.rendered[0]}"
或通过函数元素()执行


如果您找到了使用模板渲染绕过地图问题列表的有效解决方案:

resource "aws_instance" "k8s_master" {
  count                       = "${var.master_count}"
  ami                         = "${var.ami}"
  instance_type               = "${var.instance_type}"
  vpc_security_group_ids      = ["${aws_security_group.k8s_sg.id}"]
  associate_public_ip_address = false
  subnet_id                   = "${element(var.subnet_ids,count.index % length(var.subnet_ids))}"
  user_data                   = "${file("${path.root}/files/user_data.sh")}"
  iam_instance_profile        = "${aws_iam_instance_profile.master_profile.name}"

  tags = "${merge(
    local.k8s_tags,
    map(
      "Name", "k8s-master-${count.index}",
      "Environment", "${var.environment}"
    )
  )}"
}

data "template_file" "k8s_master_names" {
  count    = "${var.master_count}"
  template = "${lookup(aws_instance.k8s_master.*.tags[count.index], "Name")}"
}

output "k8s_master_name" {
  value = [
    "${data.template_file.k8s_master_names.*.rendered}",
  ]
}
这将产生以下输出:

k8s_master_name = [
    k8s-master-0,
    k8s-master-1,
    k8s-master-2
]

一个可能更简单的答案是使用
zipmap
函数

从与ECS模板定义兼容的环境变量映射开始:

locals {
  shared_env = [
    {
      name  = "DB_CHECK_NAME"
      value = "postgres"
    },
    {
      name  = "DB_CONNECT_TIMEOUT"
      value = "5"
    },
    {
      name  = "DB_DOCKER_HOST_PORT"
      value = "35432"
    },
    {
      name  = "DB_DOCKER_HOST"
      value = "localhost"
    },
    {
      name  = "DB_HOST"
      value = "my-db-host"
    },
    {
      name  = "DB_NAME"
      value = "my-db-name"
    },
    {
      name  = "DB_PASSWORD"
      value = "XXXXXXXX"
    },
    {
      name  = "DB_PORT"
      value = "5432"
    },
    {
      name  = "DB_QUERY_TIMEOUT"
      value = "30"
    },
    {
      name  = "DB_UPGRADE_TIMEOUT"
      value = "300"
    },
    {
      name  = "DB_USER"
      value = "root"
    },
    {
      name  = "REDIS_DOCKER_HOST_PORT"
      value = "6380"
    },
    {
      name  = "REDIS_HOST"
      value = "my-redis"
    },
    {
      name  = "REDIS_PORT"
      value = "6379"
    },
    {
      name  = "SCHEMA_SCRIPTS_PATH"
      value = "db-scripts"
    },
    {
      name  = "USE_LOCAL"
      value = "false"
    }
  ]
}
在同一文件夹中启动terraform console以测试内置功能。您可能需要
terraforminit
,如果您还没有

地形控制台
在控制台类型内:

zipmap([for m in local.shared_env: m.name], [for m in local.shared_env: m.value])
观察每个列表项映射作为单个映射的名称-值对的输出:

{
  "DB_CHECK_NAME" = "postgres"
  "DB_CONNECT_TIMEOUT" = "5"
  "DB_DOCKER_HOST" = "localhost"
  "DB_DOCKER_HOST_PORT" = "35432"
  "DB_HOST" = "my-db-host"
  "DB_NAME" = "my-db-name"
  "DB_PASSWORD" = "XXXXXXXX"
  "DB_PORT" = "5432"
  "DB_QUERY_TIMEOUT" = "30"
  "DB_UPGRADE_TIMEOUT" = "300"
  "DB_USER" = "root"
  "REDIS_DOCKER_HOST_PORT" = "6380"
  "REDIS_HOST" = "my-redis"
  "REDIS_PORT" = "6379"
  "SCHEMA_SCRIPTS_PATH" = "db-scripts"
  "USE_LOCAL" = "false"
}

在这种情况下,如果给定名称,我们如何获取值?
{
  "DB_CHECK_NAME" = "postgres"
  "DB_CONNECT_TIMEOUT" = "5"
  "DB_DOCKER_HOST" = "localhost"
  "DB_DOCKER_HOST_PORT" = "35432"
  "DB_HOST" = "my-db-host"
  "DB_NAME" = "my-db-name"
  "DB_PASSWORD" = "XXXXXXXX"
  "DB_PORT" = "5432"
  "DB_QUERY_TIMEOUT" = "30"
  "DB_UPGRADE_TIMEOUT" = "300"
  "DB_USER" = "root"
  "REDIS_DOCKER_HOST_PORT" = "6380"
  "REDIS_HOST" = "my-redis"
  "REDIS_PORT" = "6379"
  "SCHEMA_SCRIPTS_PATH" = "db-scripts"
  "USE_LOCAL" = "false"
}