带计数的Terraform模块不能有重复元素

时间:2018-07-29 17:35:49

标签: digital-ocean terraform

一个棘手的人在标题中进行解释,甚至围绕它提出一个问题,因此,我将从一些代码(简化,错误,简单)开始:

resource "digitalocean_domain" "this_domain" {
  name       = "${var.domain}"
  ip_address = "${var.main_ip}"
}

resource "digitalocean_record" "this_a_record" {
  count  = "${length(var.a_records)}"

  domain = "${var.domain}"
  type   = "A"
  name   = "${element(keys(var.a_records), count.index)}"
  value  = "${lookup(var.a_records, element(keys(var.a_records), count.index))}"
}

鉴于以上内容是名为dns的模块的一部分,我可以这样称呼它:

module "example_com_dns" {
  source = "./modules/dns"

  domain  = "example.com"
  main_ip = "1.2.3.4"

  a_records = {
    "@"    = "5.6.7.8"
    "self" = "9.10.11.12"
    "www"  = "5.6.7.8"
  }
}

按预期运行。我得到了我期望的A条记录; @,自我,www,都指向正确的IP。

但是,它不能处理重复的名称。例如,放入多个@记录只会导致其中一个记录被写入,我猜测是因为该名称的每次迭代都只会覆盖先前的@记录。

是否可以使用多个重复名称?即在上面的示例中,输入类似以下内容:

    ....
    "@" = "5.6.7.8"
    "@" = "20.21.22.23"
    "@" = "30.31.32.33"
    "self" = "9.10.11.12"
    "www" = 5.6.7.8"
    ...

2 个答案:

答案 0 :(得分:0)

在这种情况下,应该使用A记录到列表中,而不是使用获取地图键

from copy import deepcopy

# Within `recursiveTraversal`:
# ...
nextPath = deepcopy(recursiveTraversal(i, target, steps - 1))
# ...

并将名称分配为

a_records = [ 
  ["@" , "5.6.7.8"], 
  ["@" , "7.6.7.8"], 
  ["@" , "9.9.9.9"], 
  ["self", "7.10.11.12"], 
  ["self", "11.11.111.11"], 
  ["self", "12.12.12.12"], 
  ["self", "13.13.13.13"], 
  ["www" , "14.14.14.14"] 
] 

,您将获得所需的所有重复的A记录

以下是如何执行此操作的简单示例。您可以将代码剪切并粘贴到功能性的terraform会话中,它将正确运行,并创建重复的A记录。

您将需要扩展示例以适合外部模块等的需求。

name = "${element(var.a_records[count.index],0)}" 
value = "${element(var.a_records[count.index],1)}"

这是另一个示例。它显示了如何使用通过模块提供的外部数据来执行此操作。它也是可以复制并粘贴到功能性terraform会话中的代码,并且可以照常工作。

create-dup-A-records.tf

variable "a_records" { default = [
    ["@"   , "5.6.7.8"],
    ["@"   , "7.6.7.8"],
    ["@"   , "9.9.9.9"],
    ["self", "7.10.11.12"],
    ["self", "11.11.111.11"],
    ["self", "12.12.12.12"],
    ["self", "13.13.13.13"],
    ["www" , "14.14.14.14"],
    ["www" , "14.14.14.14"]
  ]
}

variable domain { default = "example20180731.com" }
variable main_ip { default = "1.1.1.1" }

resource "digitalocean_domain" "this_domain" {
  name       = "${var.domain}"
  ip_address = "${var.main_ip}"
}

resource "digitalocean_record" "this_a_record" {
  depends_on = ["digitalocean_domain.this_domain"]
  count  = "${length(var.a_records)}"

  domain = "${var.domain}"
  type   = "A"
  name   = "${element(var.a_records[count.index],0)}"
  value  = "${element(var.a_records[count.index],1)}"
}

./ modules / dns / dns.tf

module "dns" {
  source = "./modules/dns"
}

variable domain { default = "example20180731.com" }
variable main_ip { default = "1.1.1.1" }

resource "digitalocean_domain" "this_domain" {
  name       = "${var.domain}"
  ip_address = "${var.main_ip}"
}

resource "digitalocean_record" "this_a_record" {
  depends_on = ["digitalocean_domain.this_domain"]
  count  = "${length(module.dns.a_records_in_dns_module)}"

  domain = "${var.domain}"
  type   = "A"
  name   = "${element(module.dns.a_records_in_dns_module[count.index],0)}"
  value  = "${element(module.dns.a_records_in_dns_module[count.index],1)}"
}

答案 1 :(得分:0)

原来是Terraform的局限性

https://github.com/hashicorp/terraform/issues/18573#event-1765829698

@don大部分都在他的答案中,但是您不能通过传入变量来完成这项工作。您需要使用split hack来将其作为字符串传递,然后使其成为列表,如上面链接的问题所述:

从main.tf呼叫:

module "example_com_dns" {
  source = "./modules/dns"

  domain  = "example.com"
  main_ip = "${lookup(var.example_com_dns, "at01")}"

  a_records = [
    "@ 5.6.7.8",
    "@ 7.6.7.8",
  ]
}

dns.tf模块:

resource "digitalocean_record" "this_a_record" {
  depends_on = ["digitalocean_domain.this_domain"]
  count  = "${length(var.a_records)}"

  domain = "${var.domain}"
  type   = "A"
  name   = "${element(split(" ", var.a_records[count.index]),0)}"
  value  = "${element(split(" ", var.a_records[count.index]),1)}"
}

其他尝试通过Google搜索进行此操作的人;我的建议是不要。 0.12即将推出,并将解决所有这些疯狂的问题。