Problem with computed ansible_host and delegate_to

I recently added a table of host names mapped to IP addresses to my environment, because I needed this anyway to configure my DHCP server. I thought it was a nice idea to use this table as the Source of Truth™ for my playbooks. I introduced a variable expression for ansible_host which would look up the IP address in this table. This seemed to work nicely … until I started using delegate_to.

Here’s a test:

inventory.yml

all:
  hosts:
    zeus:
      # ansible_host: 192.168.1.20
      ansible_ssh_user: martin
    ananas:
      # ansible_host: 192.168.1.167
      ansible_ssh_user: p464v2
  vars:
    ip_addrs:
      zeus:  192.168.1.20
      ananas: 192.168.1.167
    ansible_host: "{{ ip_addrs[inventory_hostname] }}"

delegate-test.yml

- name: Test delegate_to with computed ansible_host
  hosts: zeus,ananas
  gather_facts: true
  become: false
  tasks:

    - name: Print host and user
      debug:
        msg: "Host: {{ ansible_host }}, User: {{ ansible_ssh_user }}"

    - name: Print host and user with delegate_to
      debug:
        msg: "Host: {{ ansible_host }}, User: {{ ansible_ssh_user }}"
      delegate_to: ananas
      when: inventory_hostname == 'zeus'

    - name: Check connectivity
      ping:

    - name: Check connectivity with delegate_to
      ping:
      delegate_to: ananas
      when: inventory_hostname == 'zeus'

The output of this playbook is:

> ansible-playbook -i inventory.yml delegate-test.yml

PLAY [Test delegate] ********************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************
ok: [zeus]
ok: [ananas]

TASK [Print host and user] **************************************************************************************************
ok: [zeus] => {
    "msg": "Host: 192.168.1.20, User: martin"
}
ok: [ananas] => {
    "msg": "Host: 192.168.1.167, User: p464v2"
}

TASK [Print host and user with delegate_to] *********************************************************************************
ok: [zeus -> ananas({{ ip_addrs[inventory_hostname] }})] => {
    "msg": "Host: 192.168.1.20, User: martin"
}
skipping: [ananas]

TASK [Check connectivity] ***************************************************************************************************
ok: [zeus]
ok: [ananas]

TASK [Check connectivity with delegate_to] **********************************************************************************
skipping: [ananas]
fatal: [zeus -> ananas]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Received disconnect from 192.168.1.20 port 22:2: Too many authentication failures\r\nDisconnected from 192.168.1.20 port 22", "unreachable": true}

PLAY RECAP ******************************************************************************************************************
ananas                     : ok=3    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   
zeus                       : ok=4    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   

In the last task with delegate_to, ansible is using the IP address of host zeus when connecting to ananas.

If I uncomment the constant expressions for ansible_host in the inventory.yml file, the playbook succeeds.

Is this a bug? Or is it generally not supported to use a variable for ansible_host?

inventory_hostname ALWAYS reflects the task’s original host, the next best thing is inventory_hostname_short, which does reflect the ‘delegated host’.

Wow, and that’s even documented. Thanks a lot!!

Yep, I had to write it down, cause asking me does not scale.

1 Like

Sorry for not having found it in the docs, and thanks again.