首页 > 解决方案 > 在 Terraform 0.12 中迭代地图

问题描述

我需要建立一个templatefile这样的列表:

templatefile("${path.module}/assets/files_eth0.nmconnection.yaml", {
  interface-name = "eth0",
  addresses = element(values(var.virtual_machines), count.index),
  gateway = element(var.gateway, count.index % length(var.gateway)),
  dns = join(";", var.dns_servers),
  dns-search = var.domain,
  }),
templatefile("${path.module}/assets/files_etc_hostname.yaml", {
  hostname = element(keys(var.virtual_machines), count.index),
  }),

通过遍历如下地图的地图:

variable templatefiles {
  default = {
    "files_eth0.nmconnection.yaml" = {
      "interface-name" = "eth0",
      "addresses" = "element(values(var.virtual_machines), count.index)",
      "gateway" = "element(var.gateway, count.index % length(var.gateway))",
      "dns" = "join(";", var.dns_servers)",
      "dns-search" = "var.domain",
    },
    "files_etc_hostname.yaml" = {
      "hostname" = "host1"
    }
  }
}

我对文件列表做了类似的事情:

file("${path.module}/assets/files_90-disable-console-logs.yaml"),
file("${path.module}/assets/files_90-disable-auto-updates.yaml"),

...但想将其扩展到templatefiles(以上)。

这是我为列表所做的代码files

主文件

variable files {
  default = [
    "files_90-disable-auto-updates.yaml",
    "files_90-disable-console-logs.yaml",
  ]
}

output "snippets" {
  value = flatten(module.ingition_snippets.files)
}

模块/main.tf

variable files {}

resource "null_resource" "files" {
  for_each = toset(var.files)
  triggers = {
    snippet = file("${path.module}/assets/${each.value}")
  }
}

output "files" {
  value = [for s in null_resource.files: s.triggers.*.snippet]
}

感谢任何帮助!

标签: terraformnested-loops

解决方案


这两个用例都可以在不使用任何resource块的情况下满足,因为必要的功能内置于 Terraform 语言中。

这是使用静态文件编写示例的更短方法:

variable "files" {
  type = set(string)
}

output "files" {
  value = tomap({
    for fn in var.files : fn => file("${path.module}/assets/${fn}")
  })
}

上面会生成从文件名到文件内容的映射,因此调用模块可以更轻松地访问单个文件内容。

我们可以templatefile这样调整:

variable "template_files" {
  # We can't write down a type constraint for this case
  # because each file might have a different set of
  # template variables, but our later code will expect
  # this to be a mapping type, like the default value
  # you shared in your comment, and will fail if not.
  type = any
}

output "files" {
  value = tomap({
    for fn, vars in var.template_files : fn => templatefile("${path.module}/assets/${fn}", vars)
  })
}

同样,结果将是从文件名到使用给定变量渲染模板的结果的映射。


如果您的目标是构建一个模块,用于从源目录渲染模板以发布到某个地方,您可能会发现该模块hashicorp/dir/template很有用。它结合了filesetfiletemplatefile,希望能够方便静态网站发布和类似的用例。(在我写这篇文章的时候,这个模块正在从我的个人 GitHub 帐户转变为在 HashiCorp 组织中,所以如果你在不久之后查看它,你可能会看到文档更新时出现一些混乱等)


推荐阅读