How to create a for loop inside remote-exec inline command

Dear Team,

I am trying to create internal hostnames with private IPs with all servers created in previous steps. So I want inside each server I have created the /etc/hosts file to have “IP HOSTNAME” of each server created.

So the question is how can I create a for loop:

for i in ${count.index} inside the inline = [] so that each time the count index run the inline will run 3 times for each server for ${scaleway_instance_server.db_nodes[$i].name}

Here is an example of what I am trying to achieve :

> # Create Hostnames on all nodes
> resource "null_resource" "set_hostnames" {
>   depends_on=[scaleway_instance_server.db_nodes,scaleway_instance_server.db_nodes]
>   count = length(scaleway_instance_server.db_nodes.*.id)
> 
>   triggers = {
>       db_instance_ids = "${join(",", scaleway_instance_server.db_nodes.*.id)}"
>   }
> 
>   provisioner "remote-exec" {
>       inline = [
>           "echo ${scaleway_instance_server.db_nodes[0].private_ip} ${scaleway_instance_server.db_nodes[0].name} >> /etc/hosts",
>           "echo ${scaleway_instance_server.db_nodes[1].private_ip} ${scaleway_instance_server.db_nodes[1].name} >> /etc/hosts",
>           "echo ${scaleway_instance_server.db_nodes[2].private_ip} ${scaleway_instance_server.db_nodes[2].name} >> /etc/hosts"
>       ]
>     connection {
>       type     = "ssh"
>       user     = "root"
>       private_key = file("~/.ssh/id_rsa")
>       host = scaleway_instance_server.db_nodes[count.index].public_ip
>     }
>   }
> }

thank you in advance for your support.

Vasilios Tzanoudakis

scaleway_instance_server.db_nodes is a list-of-maps, so you should be able to use it as a list in a for directive of a string interpolation.

Dear @bentterp,

Thank you for you reply and your directions.

I am trying to combine {ip} and {name} into one line so that each host.txt
to have :

IP1 NAME1
IP2 NAME2
IP3 NAME3

The example here

<<EOT
%{ for ip in aws_instance.example.*.private_ip ~}
server ${ip}
%{ endfor ~}
EOT

is working for only 1 dynamic variable. --> ${ip}
In my case I would like to have 2 variables with the same counter in the same line.

Variable 1 ---> ${ip}
Variable 2 ---> ${name}

I would like to implement something like this in the inline with [count.index] from the null_resource

provisioner "remote-exec" {
      inline = [<<EOT
        %{ for i in scaleway_instance_server.db_nodes.*.id ~}
            echo scaleway_instance_server.db_nodes[count.index].public_ip scaleway_instance_server.db_nodes[count.index].name > /root/hosts.txt
        %{ endfor ~}
       EOT
      ]

thank you in advance for your support.
Vasilios Tzanoudakis

I have implemented that like this but I am pretty sure there is better way to do it.

  inline = [<<EOT
    %{ for ip in scaleway_instance_server.db_nodes.*.private_ip ~}
      echo ${ip} >> /root/ips.txt
    %{ endfor ~}
    %{ for name in scaleway_instance_server.db_nodes.*.name ~}
      echo ${name} >> /root/names.txt
    %{ endfor ~}
    paste /root/ips.txt /root/names.txt > /root/hosts.final
   EOT
  ]

thank you in advance
Best Regards

I’ll try and see if I can find time for working through an example tomorrow. I don’t know if it will work but the idea was to loop over the list-of-maps, and then referring to specific keys of the map in the template.

Dear @bentterp,

Thank you for your support on this case.
Best Regards

Vasilios Tzanoudakis

It worked as I hoped it would :smiley:

locals {
  hosts = [
    {private_ip: "10.0.1.4", name: "server1"},
    {private_ip: "10.0.2.4", name: "server2"},
    {private_ip: "10.0.3.4", name: "server3"}
  ]
}

output "hostfile" {
  value = <<-EOT
    %{ for server in local.hosts }
    ${server.private_ip} ${server.name}
    %{ endfor ~}
    EOT
}

Dear @bentterp,

Thank you very much for your reply!!!

In my situation the variables are returned directly from the provider which means they are returned that way :

scaleway_instance_server.db_nodes.*.private_ip = ["IP1","IP2","IP3"]
scaleway_instance_server.db_nodes.*.name = ["name1","name2","name3"]

which means locals would be

 hosts = [
        { private_ips: "IP1","IP2","IP3", names: "name1","name2","name3" },
      ]

This is the reason I was looking for a loop with the counter so that I can print them in the same line.

thank you very much for your support.

Regards
Vasilios Tzanoudakis

scaleway_instance_server.db_nodes is the list, try using it in an output directly. No need to splat it.

I can’t run the full config as I don’t have scaleway, so I used the local.hosts list to illustrate the principle.

Dear @bentterp
thank you very much for your support. I will try it.

Regards
Vasilios Tzanoudakis