Output public_ip into file using template_file

I am trying to create a file with the public_ip addresses to use with ansible. So, I am looking to create a file to look like:

[server-type]
10.0.0.2
10.0.0.3
10.0.0.4

Is there a way to do this in terraform?

1 Like

Will your list of IPs change? Is this something you’ll want to do dynamically? I have actually done this using bash but I have a set list of instances.

I use bash to set env variables out of terraform outputs then SED a hosts file to replace placeholders with my env variables. Below is an example. hope this helps. I can provide more detail if needed.

# Create variables from Terraform output
echo "Generate env variables"
export INSTANCE_IP=$(terraform output instance_ip)

# SED Ansible hosts file
echo "SED hosts file"
sed -i'.original' -e "s/INSTANCE_IP/$INSTANCE_IP/g" hosts.txt

Now that I’m posting I bet you could do something similar by doing the SED command via local-exec. Then you can use interpolation to replace your placeholder with whatever the value is for your IP.

Look at the for-loop examples in the string template documentation

And use it to populate a local_file resource

1 Like

Also this looks just about perfect.

Update: I was able to make it work with one IP. I imagine combining a for loop could get you the rest of the way. Hope this helps.

data "template_file" "init" {
  template = file("hosts.tmpl")
  vars = {
    digitalocean_address = digitalocean_droplet.host.ipv4_address
  }
}

resource "null_resource" "export_rendered_template" {
  provisioner "local-exec" {
    command = "cat > test_output.json <<EOL\n${join(",\n", data.template_file.init.*.rendered)}\nEOL"
  }
}

starting template: hosts.tmpl

digitalocean ansible_ssh_host=${digitalocean_address}

ending rendered file: test_output.json

digitalocean ansible_ssh_host=167.99.225.2

Credits: https://blog.aurynn.com/2017/2/23-fun-with-terraform-template-rendering

So, In my template I have the following template and null_resource. I get the following error. Error: failed to render : <template_file>:1,14-24: Iteration over non-iterable value; A value of type string cannot be used as the collection in a ‘for’ expression.

data “template_file” “init” {
template = file("${path.module}/templates/test.tmpl")
count = length(aws_instance.web)
vars = {
public_ips = aws_instance.web[count.index].public_ip
}
}

resource “null_resource” “ansible_template” {
provisioner “local-exec” {
command = “cat > hosts <<EOL\n${data.template_file.init.*.rendered}\nEOL”
}

test.tmpl

locals {
  ips = ["127.0.0.1","10.0.0.1","192.168.0.1","172.16.0.1"]
}

resource "local_file" "ip_list" {
  filename = "playbook"
  content = <<-EOT
  [server-type]
  %{ for ip in local.ips }${ip}
  %{ endfor }
  EOT
}

What if the ips are dynamic?

just make a list from the resources containing them, you can use the splat
ie aws_instance.web.*.public_ip

1 Like