Ansible, delegate_to and set_fact

Posted by ads' corner on Wednesday, 2020-04-22
Posted in [Ansible][Linux][Software]

Another Ansible upgrade, another Playbook failing.

I have a number Playbooks which run on virtual machines. Some tasks are “outsourced” to the physical machine where the VM is running on, using delegate_to. One of the tasks (which I haven’t used in a while, because I rarely touch this machine) stopped working, and instead throws a variable undefined error. But from the beginning, here is the VM Playbook:

1
2
3
4
- block:
  - include: server-part.yml
  delegate_to: "{{ ansible_host }}"
  delegate_facts: True

That’s the short form of it, and the $ansible_host variable holds the physical server address. That part is working. In server-part.yml I have the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# re-do the gather_facts task for the host
- action: setup

- name: Determine network interface name
  set_fact:
    main_interface: "{{ item }}"
  with_items:
    "{{ hostvars[physicalhost]['ansible_interfaces'] }}"
  when: item is match("^e[tn]")
  changed_when: false

- name: Verify interface name is set
  fail:
    msg: "Could not determine network interface name!"
  when: main_interface is not defined

The only physical network interface in this server is eth0, that’s still the case. There are a couple reasons why I still scan the list of interfaces, instead of just depending on eth0. The main reason however is that this part also works with the enumeration systemd is doing with network interfaces (they have en names, instead of eth). But suddenly $main_interface in the next step is no longer defined.

Digging deeper (aka: -vvvv) it shows that Ansible is setting the correct interface name in the set_fact task, but then the variable is no longer defined immediately after that. What? I’m not sure I had to use this Playbook since my host was upgraded to Ansible 2.8.3, but I couldn’t find any issues matching this problem either.

What happened? After more investigation it seems that Ansible is now attaching the variable from set_fact to the physical host, but is reading any variable from the virtual machine facts. Example:

1
2
3
- action: setup
- set_fact: testvar="Test"
- debug: msg="{{ testvar }}"

This fails with: The task includes an option with an undefined variable. The error was: testvar is undefined.

1
2
3
- action: setup
- set_fact: testvar="Test"
- debug: msg="{{ hostvars['physicalhost']['testvar'] }}"

This works. Or I can turn it around:

1
2
3
4
5
- action: setup
- set_fact: testvar="Test"
  delegate_to: "virtualvm"
  delegate_facts: True
- debug: msg="{{ testvar }}"

Assign the set_fact to the VM and then I can access the variable on the physical host.

Quite strange, and definitely didn’t work that way when I last used that Playbook. Now please excuse me, I have to check a couple more Playbooks sigh


Categories: [Ansible] [Linux] [Software]
Tags: [Ansible] [Bug] [Bugs] [Linux] [Software]