Roberto Jobet
Roberto Jobet

Reputation: 323

Sequentially assign hostname to multiple hosts using inventory items

I have a playbook that creates 3 VMs in Hetzner cloud, and assigns their public IPs to an in-memory inventory in order to continue provisioning them.

Directive:

- name: Add new servers to dynamic inventory
  add_host:
    name: "{{ item.hcloud_server.ipv4_address }}"
    groups: new_servers
  with_items: "{{ hcloud_info.results }}"

And role:

- name: Bootstrap server
  hosts: new_servers
  gather_facts: false
  remote_user: root
  roles:  
  - bootstrap

During this second step, I would need to assign a hostname to each host.

Inventory:

[servers]
master.domain.tld
worker1.domain.tld
worker2.domain.tld

Checking a few values I see that the inventory_hostname fact, gathers VMs IPs instead of the hostnames:

Running debug:

- name: Checking
  debug:
    msg: "hostname is {{ inventory_hostname }}"

Output:

ok: [1st_IP] => {
    "msg": "hostname is 1st_IP"
}
ok: [2nd_IP] => {
    "msg": "hostname is 2nd_IP"
}
ok: [3rd_IP] => {
    "msg": "hostname is 3rd_IP"
}

I found that the hostnames can be gather using the groups['servers'] fact. The problem is that Ansible tries to assign all 3 hostnames to each host.

Running debug:

-  name: Checking inventory
  debug:
    msg: "hostname is {{ groups['servers'] }}"

I have this output:

ok: [1st_IP] => {
    "msg": "hostname is ['master.domain.tld', 'worker1.domain.tld', 'worker2.domain.tld']"
}
ok: [2nd_IP] => {
    "msg": "hostname is ['master.domain.tld', 'worker1.domain.tld', 'worker2.domain.tld']"
}
ok: [3rd_IP] => {
    "msg": "hostname is ['master.domain.tld', 'worker1.domain.tld', 'worker2.domain.tld']"
}

How can I pair each IP with its corresponding hostname?

1st_IP = master.domain.tld
2nd_IP = worker1.domain.tld
1st_IP = worker2.domain.tld

Upvotes: 1

Views: 1606

Answers (1)

George Shuklin
George Shuklin

Reputation: 7877

I would advise you to never treat inventory_hostname as IP address. It's a fallback and unreliable one.

inventory_hostname should be a name. srv01 is 'ok' name, 'click4' (or 'postgres4') is a better name.

Use ansible_host to specify ip address for Ansible to connect to. I saw many projects struggling with edge cases when they opt for inventory_hostname for anything but slugname in ansible output.

Therefore:

- name: Add new servers to dynamic inventory
  add_host:
    name: "hc{{ index }}"
    groups: new_servers
    ansible_host: "{{ item.hcloud_server.ipv4_address }}"
  with_items: "{{ hcloud_info.results }}"
  loop_control:
    index_var: index

Upvotes: 1

Related Questions