Terraform to dynamically produce ansible inventory

Hi ,

I am trying to use terraform to create an ansible inventory file dynamically.
I have a terraform module which creates couple of ec2 instances using for_each.
Then I am using the following code to create the inventory

resource "local_file" "hosts_cfg" {
  content = templatefile("${path.module}/templates/hosts.tpl",
      wg_clients = values(module.ec2_instance)[*].public_ip
  filename = "./ansible/inventory/hosts.cfg"
  depends_on = [ module.ec2_instance ]

My template file looks like this

%{ for ip in wg_clients ~}
${ip} ansible_ssh_user=ubuntu app_ip=
%{ endfor ~}

For every host entry being added to the file , I would like to add an ip as a variable ( which would be the value of app_ip); i.e

x.x.x.x ansible_ssh_user=ubuntu app_ip=
x.x.x.x ansible_ssh_user=ubuntu app_ip=

Is there any way we can achieve this via terraform ?

Hi @adg.052022!

It looks like you already have the IP address at the start of each line. I assume you want to place a different IP address after the app_ip= part, but from what you shared I’m not sure where that other IP address would come from.

Can you share a little more about where this other set of IP addresses is intended to come from?

Unrelated side-note: The depends_on in your first example is redundant, because your resource configuration already includes a reference to module.ec2_instance as part of the content expression. I’d suggest removing that because redundant depends_on arguments tend to be confusing for future maintainers of a module who will often be unsure as to why they are there.

Hi @apparentlymart ,

Thanks for your response. I have removed my depends_on from my code , thanks for pointing that out. Regarding the additional ip address being passed on the template , its not the server ip address. Its an ip address being used by a certain software for its configuration; i.e I would need to provide one server an ip address of , another and so on. I was planning to provide the first ip address as input ; i.e and then next ones it will put automatically via increasing 1 at the last octet. I am finding bit difficult to implement it via the template option.

For generating IP addresses like that I suppose you could use the cidrhost function, like cidrhost("", 1) to calculate the first address.

That presents a problem though, because your source collection for this repetition seems to be a mapping rather than a sequence, and so the elements will always appear in lexical order by map key and so if you add new elements to the map later then it will renumber any hosts with a lexically later map key.

It is technically possible to do this though… I’m just worried it may not fully solve the problem. Here’s how you could implement it:

%{ for idx, ip in wg_clients ~}
${ip} ansible_ssh_user=ubuntu app_ip=${cidrhost("", idx+1)}
%{ endfor ~}

If you try this, I suggest testing what happens if you add a new instance of module.ec2_instance with a lesser instance key to those already existing, and make sure that behavior is acceptable for you. There is a risk here that this will work okay on the first create, because all of the initial instances will be created at once, but then this will become problematic the first time you need to add a new instance later, when various instances are already running.