如何动态构建 terraform local_file

Bip*_*lab 4 amazon-ec2 terraform terraform-provider-aws

我想创建一些 EC2 实例并将其 private_ip 放入 ec2.ini 样式文件中,以便进一步与 Ansible 一起使用。

resource "local_file" "ec2_id" {
  count = var.instance_count
  content  = "${aws_instance.instance[count.index].private_ip} ansible_ssh_user=ec2-user\n"
  filename = "ec2.ini"
}
Run Code Online (Sandbox Code Playgroud)

这始终打印创建的最新 EC2 实例的 private_ip。

任何想法如何解决这个问题。

更新:-

data "template_file" "hehe" {
  count = var.instance_count
  template = "${element(aws_instance.instance.*.private_ip, count.index)} ansible_ssh_user=ec2-user subnetmask=${element(split("/", data.aws_subnet.selected-subnet-id.cidr_block),1)}\n"
}


resource "local_file" "ec2_id" {
  count = var.instance_count
  content  = "${element(data.template_file.hehe.*.rendered, count.index)}"
  filename = "ec2.ini"
}
Run Code Online (Sandbox Code Playgroud)

不起作用。给我最后创建的实例 private_ip。

Mar*_*ins 14

当您在资源内部使用时,count您要求 Terraform 创建该资源的多个实例。但是,在您的情况下,您没有包含count.indexfilename参数中,因此您的所有实例都在竞争覆盖相同的 filename ec2.ini,因此只有其中一个可以“获胜”。

听起来您的目标是只创建一个包含所有 IP 地址的文件。这与我撰写本文时Terraform字符串模板文档中的示例之一非常接近,我们可以按照您的目标进行调整,如下所示:

resource "local_file" "ec2_iini" {
  filename = "ec2.ini"
  content = <<-EOT
    %{ for ip in aws_instance.instance.*.private_ip ~}
    ${ip} ansible_ssh_user=ec2-user
    %{ endfor ~}
  EOT
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,local_file资源本身没有设置count因为我们的目标是只创建一个文件。相反,我们使用 Terraform 的模板for指令为每个实例重复一次字符串模板,将结果收集为单个字符串,local_file然后将其用作其content参数。

我在这里使用了字符串文字的“heredoc”样式,因为我认为通过将指令拆分为多行,可以使for指令更易于阅读。in-使<<-EOTTerraform 查看开头<<-EOT和结尾之间的所有线条EOT,并找到这些线条共有的最小数量的前导空格,然后在渲染时将其剥离。这意味着您可以在配置中缩进模板,但避免在呈现的字符串中出现这些缩进,该字符串应如下所示:

10.1.0.34 ansible_ssh_user=ec2-user
10.1.0.5 ansible_ssh_user=ec2-user
10.1.0.92 ansible_ssh_user=ec2-user
Run Code Online (Sandbox Code Playgroud)

~两个指令末尾的标记指示%{ ... }Terraform 的模板引擎忽略它们后面的换行符和空格,因此我们可以将模板包装在多行中,而无需在结果中引入额外的换行符。模板中唯一生成尾随换行符的行是包含 IP 地址插值和该ansible_ssh_user部分的中间行,因此结果最终每个条目只有一个换行符,正如此处所预期的那样。