Hostvars ansible_local from another host

Bonjour, :wave:

I’m unable to get “locals facts” from another host. I tried to create collection for Wireguard.

on wireguard-server.dev, I have a local fact as:
cat /etc/ansible/facts.d/wireguard_client_nextusable_ipv4.fact

{"wireguard_client_nextusable_ipv4": "10.8.0.5"}

On another role, when I try to get this local facts of wireguard-server.dev host.

- name: Deploy Wireguard
  hosts: wireguard-client.dev
  become: yes
  tasks:
  - name: Install Wireguard
    ansible.builtin.import_role:
      name: quanticware.wireguard.install
      tasks_from: tests
    vars:
      wireguard_server_host: "wireguard-server.dev"

tasks tests.yml


- ansible.builtin.setup:
    filter: "ansible_local"
  delegate_to: "{{ wireguard_server_host }}"

- ansible.builtin.debug:
    msg: "{{ hostvars[wireguard_server_host][ansible_local][wireguard_client_nextusable_ipv4][wireguard_client_nextusable_ipv4] }}"

And execution gives:

PLAY [Deploy Wireguard] *******************************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************************************************************************
Vendredi 26 avril 2024  09:47:23 +0200 (0:00:00.009)       0:00:00.009 ******** 
ok: [wireguard-client.dev]

TASK [quanticware.wireguard.install : ansible.builtin.setup] ******************************************************************************************************************************************************************************************************************************************
Vendredi 26 avril 2024  09:47:24 +0200 (0:00:01.201)       0:00:01.210 ******** 
ok: [wireguard-client.dev -> wireguard-server.dev(192.168.67.6)]

TASK [quanticware.wireguard.install : ansible.builtin.debug] ******************************************************************************************************************************************************************************************************************************************
Vendredi 26 avril 2024  09:47:26 +0200 (0:00:01.235)       0:00:02.446 ******** 
fatal: [wireguard-client.dev]: FAILED! => 
  msg: |-
    The task includes an option with an undefined variable. The error was: ansible.vars.hostvars.HostVarsVars object has no element {'wireguard_client_nextusable_ipv4': {'wireguard_client_nextusable_ipv4': '10.8.0.5'}, 'wireguard_server_ipv4': '{\n  "wireguard_client_nextusable_ipv4": "10.8.0.2"\n\n} | to_nice_json\n', 'wireguard_server_ipv6': {'wireguard_server_ipv6': 'fd1d:7e7d:ced8::1/64'}}. ansible.vars.hostvars.HostVarsVars object has no element {'wireguard_client_nextusable_ipv4': {'wireguard_client_nextusable_ipv4': '10.8.0.5'}, 'wireguard_server_ipv4': '{\n  "wireguard_client_nextusable_ipv4": "10.8.0.2"\n\n} | to_nice_json\n', 'wireguard_server_ipv6': {'wireguard_server_ipv6': 'fd1d:7e7d:ced8::1/64'}}
  
    The error appears to be in '/Users/fred/labo/devopsotheque/ansible_collections/quanticware/wireguard/roles/install/tasks/tests.yml': line 116, column 3, but may
    be elsewhere in the file depending on the exact syntax problem.
  
    The offending line appears to be:
  
  
    - ansible.builtin.debug:
      ^ here

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************************************************************
wireguard-client.dev       : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

Playbook run took 0 days, 0 hours, 0 minutes, 2 seconds
Vendredi 26 avril 2024  09:47:26 +0200 (0:00:00.017)       0:00:02.463 ******** 
=============================================================================== 
Gathering Facts -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1.20s
quanticware.wireguard.install : ansible.builtin.setup ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 1.24s
quanticware.wireguard.install : ansible.builtin.debug ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 0.02s

Undefined? But have elements?

When I try:
ansible -m setup wireguard-server.dev > setup.json

        "ansible_local": {
            "wireguard_client_nextusable_ipv4": {},
            "wireguard_server_ipv4": {},
            "wireguard_server_ipv6": {}
        },

Why empty?!

I don’t understand :worried:

Thanks :ring_buoy:

When you use delegate_to, that will run the task against the delegated target, but the context still belongs to the current inventory host.

So the facts you gathered will be under the current host, not the delegate’s. E.g.

---
- hosts: host1
  gather_facts: false
  tasks:
    - ansible.builtin.setup:
      delegate_to: host2

    - ansible.builtin.debug:
        msg: "{{ ansible_facts.fqdn }}"

PLAY [host1] ****************************************************************************************************************************************************************************

TASK [ansible.builtin.setup] *********************************************************************************************************************************************************************************
ok: [host1 -> host2]

TASK [ansible.builtin.debug] *********************************************************************************************************************************************************************************
ok: [host1] => {
    "msg": "host2"
}

PLAY RECAP ***************************************************************************************************************************************************************************************************
host1 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

So, what you’re looking for is the local facts that now belong to the current host even though they came from the delegate:

- ansible.builtin.setup:
    filter: "ansible_local"
  delegate_to: "{{ wireguard_server_host }}"

- ansible.builtin.debug:
    msg: "{{ ansible_local[wireguard_client_nextusable_ipv4][wireguard_client_nextusable_ipv4] }}"

That said, if you include the wireguard_server_host in your play and gather its facts without delegating; then your hostvars[wireguard_server_host] string will work because that host’s vars are now part of the play. You’ll have to use conditionals to keep it from being configured like the rest of your hosts if you need to avoid that.

2 Likes

If your delegated-to host is in your inventory, then you can combine delegate_to: with “delegate_facts: true” to cause the retrieved facts to be associated with the delegated-to host. See Delegating facts.

(In my limited testing, if the delegate_to: host is not in your inventory, then “delegate_facts: true” causes the facts just evaporate!)

3 Likes

Bonjour, :wave:

Thanks! Between my initial post and today, I have changed somes variables. But it’s similar situation.

This is works:

- name: Deploy Wireguard
  hosts: wireguard-client-01.dev
  become: yes
  vars:
    wireguard_server_host: "wireguard-server.dev"
  tasks:
  - ansible.builtin.setup:
      filter: "ansible_local"
    delegate_to: "{{ wireguard_server_host }}"

  - ansible.builtin.debug:
      msg: "{{ ansible_local.wireguard_server_ipv4.wireguard_server_ipv4 }}"
PLAY [Deploy Wireguard] ***************************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************************************************************************************************************************************
Mardi 30 avril 2024  11:52:14 +0200 (0:00:00.007)       0:00:00.007 *********** 
ok: [wireguard-client-01.dev]

TASK [ansible.builtin.setup] **********************************************************************************************************************************************************************************************************************************************************************
Mardi 30 avril 2024  11:52:16 +0200 (0:00:01.169)       0:00:01.176 *********** 
ok: [wireguard-client-01.dev -> wireguard-server.dev(192.168.67.16)]

TASK [ansible.builtin.debug] **********************************************************************************************************************************************************************************************************************************************************************
Mardi 30 avril 2024  11:52:16 +0200 (0:00:00.875)       0:00:02.052 *********** 
ok: [wireguard-client-01.dev] => 
  msg: 10.8.0.1

PLAY RECAP ****************************************************************************************************************************************************************************************************************************************************************************************
wireguard-client-01.dev    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook run took 0 days, 0 hours, 0 minutes, 2 seconds
Mardi 30 avril 2024  11:52:16 +0200 (0:00:00.019)       0:00:02.072 *********** 
=============================================================================== 
Gathering Facts ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1.17s
ansible.builtin.setup ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 0.88s
ansible.builtin.debug ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 0.02s

but with syntax:

  - ansible.builtin.debug:
      msg: "{{ ansible_local[wireguard_server_ipv4][wireguard_server_ipv4] }}"

I got error!

And if I add delegate_facts: true I got error too.

So, what is the difference between,
ansible_local[wireguard_server_ipv4][wireguard_server_ipv4
and
ansible_local.wireguard_server_ipv4.wireguard_server_ipv4 ?

Just to understand if you have any explaination

ansible --version
ansible [core 2.16.5]
  config file = /Users/fred/labo/devopsotheque/ansible.cfg
  python version = 3.11.8 (main, Feb  6 2024, 21:21:21) [Clang 15.0.0 (clang-1500.1.0.2.5)] (/Users/fred/labo/venv/bin/python3.11)
  jinja version = 3.1.3
  libyaml = True

Thanks again @Denney-tech & @utoddl !

ansible_local[wireguard_server_ipv4][wireguard_server_ipv4] is trying to use the value of the variable wireguard_server_ipv4 (which doesn’t exist) as the index into or key within ansible_local.

To rewrite the equivalent of your second expression in the form of the first, you would spell it thus:

ansible_local["wireguard_server_ipv4"]["wireguard_server_ipv4"]
3 Likes