Skip to content

Commit c5a0984

Browse files
committed
test: ensure role gathers the facts it uses by having test clear_facts before include_role
The role gathers the facts it uses. For example, if the user uses `ANSIBLE_GATHERING=explicit`, the role uses the `setup` module with the facts and subsets it requires. This change allows us to test this. Before every role invocation, the test will use `meta: clear_facts` so that the role starts with no facts. However, since the tests use facts, we save and restore the facts used by the test. Create a task file tests/tasks/run_role_with_clear_facts.yml to do the tasks to save, clear, run the role, and restore the facts. This uses an action plugin merge_ansible_facts to merge the saved facts with any changes by the role. Any vars defined using `ansible_facts` have been changed to be defined with `set_fact` instead. This is because of the fact that `vars` are lazily evaluated - the var might be referenced when the facts have been cleared, and will issue an error like `ansible_facts["distribution"] is undefined`. Any blocks with a `when` condition that uses `ansible_facts` has been rewritten. This is because the `when` condition is evaluated every time a task is invoked in the block, and if the facts are cleared, this will raise an undefined variable error. Signed-off-by: Rich Megginson <rmeggins@redhat.com>
1 parent ded5545 commit c5a0984

121 files changed

Lines changed: 997 additions & 454 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Ansible action plugin merge_ansible_facts.
4+
# Merges saved facts with current Ansible facts on the controller and returns
5+
# ansible_facts (saved_ansible_facts with current_ansible_facts overlaid).
6+
#
7+
# Copyright: (c) 2026, Red Hat, Inc.
8+
# Code mostly written by Claude model claude-4.5-opus-high
9+
10+
from __future__ import absolute_import, division, print_function
11+
12+
__metaclass__ = type
13+
14+
from ansible.plugins.action import ActionBase
15+
16+
17+
class ActionModule(ActionBase):
18+
19+
TRANSFERS_FILES = False
20+
21+
def run(self, tmp=None, task_vars=None):
22+
if task_vars is None:
23+
task_vars = {}
24+
25+
result = super(ActionModule, self).run(tmp, task_vars)
26+
result["changed"] = False
27+
28+
current = self._task.args.get("current_ansible_facts")
29+
saved = self._task.args.get("saved_ansible_facts")
30+
31+
if current is None:
32+
result["failed"] = True
33+
result["msg"] = "current_ansible_facts is required"
34+
return result
35+
if saved is None:
36+
result["failed"] = True
37+
result["msg"] = "saved_ansible_facts is required"
38+
return result
39+
40+
# Template in case args were passed as raw Jinja
41+
current = self._templar.template(current)
42+
saved = self._templar.template(saved)
43+
44+
if not isinstance(current, dict):
45+
result["failed"] = True
46+
result["msg"] = "current_ansible_facts must be a dict"
47+
return result
48+
if not isinstance(saved, dict):
49+
result["failed"] = True
50+
result["msg"] = "saved_ansible_facts must be a dict"
51+
return result
52+
53+
# Merge: start with a copy of saved, overlay current (same behavior as module)
54+
merged = dict(saved)
55+
merged.update(current)
56+
result["ansible_facts"] = merged
57+
58+
return result

tests/ensure_provider_tests.py

Lines changed: 65 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
#!/usr/bin/env python3
22
# SPDX-License-Identifier: BSD-3-Clause
33
"""Check that there is a playbook to run all role tests with both providers"""
4+
45
# vim: fileencoding=utf8
56

67
import difflib
78
import glob
89
import os
910
import sys
1011

11-
1212
GET_NM_VERSION = """
1313
- name: Install NetworkManager and get NetworkManager version
1414
when:
15-
- ansible_facts['distribution_major_version'] != '6'
15+
- __network_distro_major_version != '6'
1616
tags:
1717
- always
1818
block:
@@ -30,8 +30,7 @@
3030
ansible_facts.packages['NetworkManager'][0]['version'] }}"
3131
"""
3232

33-
MINIMUM_NM_VERSION_CHECK = """
34-
- networkmanager_version is version({minimum_nm_version}, '>=')
33+
MINIMUM_NM_VERSION_CHECK = """ - networkmanager_version is version({minimum_nm_version}, '>=')
3534
"""
3635

3736
EXTRA_RUN_CONDITION_PREFIX = " - "
@@ -51,31 +50,72 @@
5150
network_provider: nm
5251
tags:
5352
- always
53+
- name: Include distro variables
54+
include_vars: vars/rh_distros_vars.yml
55+
- name: Set platform facts
56+
set_fact:
57+
__network_distro_major_version: "{{{{ ansible_facts['distribution_major_version'] }}}}"
58+
__network_is_rhel: "{{{{ ansible_facts['distribution'] == 'RedHat' }}}}"
59+
__network_is_fedora: "{{{{ ansible_facts['distribution'] == 'Fedora' }}}}"
60+
__network_is_centos: "{{{{ ansible_facts['distribution'] == 'CentOS' }}}}"
61+
__network_is_os_family_rhel: "{{{{ ansible_facts['os_family'] == 'RedHat' }}}}"
5462
{get_nm_version}
5563
5664
# The test requires or should run with NetworkManager, therefore it cannot run
5765
# on RHEL/CentOS 6
5866
{comment}- name: Import the playbook '{test_playbook}'
5967
import_playbook: {test_playbook}
6068
when:
61-
- ansible_facts['distribution_major_version'] != '6'
69+
- __network_distro_major_version != '6'
6270
{minimum_nm_version_check}{extra_run_condition}"""
6371

72+
73+
RUN_PLAYBOOK_WITH_INITSCRIPTS = """# SPDX-License-Identifier: BSD-3-Clause
74+
# This file was generated by ensure_provider_tests.py
75+
---
76+
# yamllint disable rule:line-length
77+
- name: Run playbook '{test_playbook}' with initscripts as provider
78+
hosts: all
79+
tasks:
80+
- name: Include the task 'el_repo_setup.yml'
81+
include_tasks: tasks/el_repo_setup.yml
82+
- name: Set network provider to 'initscripts'
83+
set_fact:
84+
network_provider: initscripts
85+
tags:
86+
- always
87+
- name: Include distro variables
88+
include_vars: vars/rh_distros_vars.yml
89+
- name: Set platform facts
90+
set_fact:
91+
__network_distro_major_version: "{{{{ ansible_facts['distribution_major_version'] }}}}"
92+
__network_is_rhel: "{{{{ ansible_facts['distribution'] == 'RedHat' }}}}"
93+
__network_is_fedora: "{{{{ ansible_facts['distribution'] == 'Fedora' }}}}"
94+
__network_is_centos: "{{{{ ansible_facts['distribution'] == 'CentOS' }}}}"
95+
__network_is_os_family_rhel: "{{{{ ansible_facts['os_family'] == 'RedHat' }}}}"
96+
- name: Import the playbook '{test_playbook}'
97+
import_playbook: {test_playbook}
98+
when:
99+
- __network_is_rh_distro
100+
- __network_distro_major_version | int < 9
101+
"""
102+
103+
64104
MINIMUM_VERSION = "minimum_version"
65105
EXTRA_RUN_CONDITION = "extra_run_condition"
66106
NM_ONLY_TESTS = {
67107
"playbooks/tests_802_1x_updated.yml": {
68108
EXTRA_RUN_CONDITION: (
69-
"(ansible_facts['distribution'] != 'RedHat' and\n"
70-
" ansible_facts['distribution_major_version'] | int > 7) or\n"
71-
" ansible_facts['distribution_major_version'] | int == 8"
109+
"(not __network_is_rhel and\n"
110+
" __network_distro_major_version | int > 7) or\n"
111+
" __network_distro_major_version | int == 8"
72112
),
73113
},
74114
"playbooks/tests_802_1x.yml": {
75115
EXTRA_RUN_CONDITION: (
76-
"(ansible_facts['distribution'] != 'RedHat' and\n"
77-
" ansible_facts['distribution_major_version'] | int > 7) or\n"
78-
" ansible_facts['distribution_major_version'] | int == 8"
116+
"(not __network_is_rhel and\n"
117+
" __network_distro_major_version | int > 7) or\n"
118+
" __network_distro_major_version | int == 8"
79119
),
80120
},
81121
"playbooks/tests_ignore_auto_dns.yml": {},
@@ -92,20 +132,20 @@
92132
},
93133
"playbooks/tests_provider.yml": {
94134
MINIMUM_VERSION: "'1.20.0'",
95-
"comment": "# NetworKmanager 1.20.0 added support for forgetting profiles",
135+
"comment": "# NetworkManager 1.20.0 added support for forgetting profiles",
96136
EXTRA_RUN_CONDITION: (
97-
"(ansible_facts['distribution'] == 'Fedora'\n"
98-
" and ansible_facts['distribution_major_version'] | int < 41)\n"
99-
" or ansible_facts['distribution'] not in ['RedHat', 'CentOS', 'Fedora']\n"
100-
" or ansible_facts['distribution_major_version'] | int < 9"
137+
"(__network_is_fedora and\n"
138+
" __network_distro_major_version | int < 41)\n"
139+
" or not __network_is_os_family_rhel\n"
140+
" or __network_distro_major_version | int < 9"
101141
),
102142
},
103143
"playbooks/tests_eth_pci_address_match.yml": {
104144
MINIMUM_VERSION: "'1.26.0'",
105145
"comment": "# NetworkManager 1.26.0 added support for match.path setting",
106146
},
107147
"playbooks/tests_network_state.yml": {
108-
EXTRA_RUN_CONDITION: "ansible_facts['distribution_major_version'] | int > 7",
148+
EXTRA_RUN_CONDITION: "__network_distro_major_version | int > 7",
109149
},
110150
"playbooks/tests_reapply.yml": {},
111151
"playbooks/tests_route_table.yml": {},
@@ -117,30 +157,30 @@
117157
"playbooks/tests_routing_rules.yml": {},
118158
# teaming support dropped in EL10
119159
"playbooks/tests_team.yml": {
120-
EXTRA_RUN_CONDITION: "ansible_facts['distribution'] not in ['RedHat', 'CentOS'] or\n ansible_facts['distribution_major_version'] | int < 10",
160+
EXTRA_RUN_CONDITION: "not __network_is_rh_distro or\n __network_distro_major_version | int < 10",
121161
},
122162
"playbooks/tests_team_plugin_installation.yml": {
123-
EXTRA_RUN_CONDITION: "ansible_facts['distribution'] not in ['RedHat', 'CentOS'] or\n ansible_facts['distribution_major_version'] | int < 10",
163+
EXTRA_RUN_CONDITION: "not __network_is_rh_distro or\n __network_distro_major_version | int < 10",
124164
},
125165
# mac80211_hwsim (used for tests_wireless) only seems to be available
126166
# and working on RHEL/CentOS 7
127167
"playbooks/tests_wireless.yml": {
128-
EXTRA_RUN_CONDITION: "ansible_facts['distribution_major_version'] == '7'",
168+
EXTRA_RUN_CONDITION: "__network_distro_major_version == '7'",
129169
},
130170
"playbooks/tests_wireless_and_network_restart.yml": {},
131171
"playbooks/tests_wireless_plugin_installation.yml": {},
132172
"playbooks/tests_wireless_wpa3_owe.yml": {
133173
"comment": "# OWE has not been supported by NetworkManager 1.18.8 on \
134174
RHEL 7(dist-tag). Failed in setting up mock wifi on RHEL 8",
135-
EXTRA_RUN_CONDITION: "ansible_facts['distribution_major_version'] > '7' and \
136-
ansible_facts['distribution'] == 'CentOS' or\n ansible_facts['distribution_major_version'] > '32' \
137-
and ansible_facts['distribution'] == 'Fedora'",
175+
EXTRA_RUN_CONDITION: "__network_distro_major_version | int > 7 and \
176+
__network_is_centos or\n __network_distro_major_version | int > 32 \
177+
and __network_is_fedora",
138178
},
139179
"playbooks/tests_wireless_wpa3_sae.yml": {
140180
"comment": "# SAE has not been supported by NetworkManager 1.18.8 on \
141181
RHEL 7. Failed in setting up mock wifi on RHEL 8",
142-
EXTRA_RUN_CONDITION: "ansible_facts['distribution_major_version'] != '7' and \
143-
ansible_facts['distribution'] != 'RedHat'",
182+
EXTRA_RUN_CONDITION: "__network_distro_major_version != '7' and \
183+
not __network_is_rhel",
144184
},
145185
}
146186
# NM_CONDITIONAL_TESTS is used to store the test playbooks which are demanding for NM
@@ -168,27 +208,6 @@
168208
"playbooks/tests_switch_provider.yml",
169209
]
170210

171-
RUN_PLAYBOOK_WITH_INITSCRIPTS = """# SPDX-License-Identifier: BSD-3-Clause
172-
# This file was generated by ensure_provider_tests.py
173-
---
174-
# yamllint disable rule:line-length
175-
- name: Run playbook '{test_playbook}' with initscripts as provider
176-
hosts: all
177-
tasks:
178-
- name: Include the task 'el_repo_setup.yml'
179-
include_tasks: tasks/el_repo_setup.yml
180-
- name: Set network provider to 'initscripts'
181-
set_fact:
182-
network_provider: initscripts
183-
tags:
184-
- always
185-
186-
- name: Import the playbook '{test_playbook}'
187-
import_playbook: {test_playbook}
188-
when: (ansible_facts['distribution'] in ['CentOS','RedHat'] and\n \
189-
ansible_facts['distribution_major_version'] | int < 9)
190-
"""
191-
192211

193212
def create_nm_playbook(test_playbook):
194213
fileroot = os.path.splitext(os.path.basename(test_playbook))[0]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../library/network_connections.py

tests/playbooks/manual_test_ethtool_coalesce.yml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
register: original_ethtool_coalesce
3535
changed_when: false
3636
- name: Import network role
37-
import_role:
38-
name: linux-system-roles.network
37+
include_tasks: tasks/run_role_with_clear_facts.yml
3938
vars:
4039
network_connections:
4140
- name: "{{ interface }}"
@@ -57,8 +56,7 @@
5756
debug:
5857
msg: "##################################################"
5958
- name: Import network role
60-
import_role:
61-
name: linux-system-roles.network
59+
include_tasks: tasks/run_role_with_clear_facts.yml
6260
vars:
6361
network_connections:
6462
- name: "{{ interface }}"
@@ -91,8 +89,7 @@
9189
debug:
9290
msg: "##################################################"
9391
- name: Import network role
94-
import_role:
95-
name: linux-system-roles.network
92+
include_tasks: tasks/run_role_with_clear_facts.yml
9693
vars:
9794
network_connections:
9895
- name: "{{ interface }}"
@@ -118,14 +115,13 @@
118115
- "tests::cleanup"
119116
block:
120117
- name: Deactivate the connection and remove the connection profile
121-
import_role:
122-
name: linux-system-roles.network
118+
include_tasks: tasks/run_role_with_clear_facts.yml
123119
vars:
124120
network_connections:
125121
- name: "{{ interface }}"
126122
persistent_state: absent
127123
state: down
128-
failed_when: false
124+
__sr_failed_when: false
129125
- name: Include the task 'manage_test_interface.yml'
130126
include_tasks: tasks/manage_test_interface.yml
131127
vars:

tests/playbooks/tests_802_1x.yml

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
debug:
1717
msg: "##################################################"
1818
- name: Import network role
19-
import_role:
20-
name: linux-system-roles.network
19+
include_tasks: tasks/run_role_with_clear_facts.yml
2120
vars:
2221
network_connections:
2322
- name: "{{ interface }}"
@@ -48,8 +47,7 @@
4847
command: ping -c1 203.0.113.1
4948
changed_when: false
5049
- name: Import network role
51-
import_role:
52-
name: linux-system-roles.network
50+
include_tasks: tasks/run_role_with_clear_facts.yml
5351
vars:
5452
network_connections:
5553
- name: "{{ interface }}"
@@ -79,8 +77,7 @@
7977
executable: /bin/bash
8078
changed_when: false
8179
- name: Import network role
82-
import_role:
83-
name: linux-system-roles.network
80+
include_tasks: tasks/run_role_with_clear_facts.yml
8481
vars:
8582
network_connections:
8683
- name: "{{ interface }}"
@@ -105,8 +102,7 @@
105102
command: ping -c1 203.0.113.1
106103
changed_when: false
107104
- name: Import network role
108-
import_role:
109-
name: linux-system-roles.network
105+
include_tasks: tasks/run_role_with_clear_facts.yml
110106
vars:
111107
network_connections:
112108
- name: "{{ interface }}"
@@ -121,8 +117,7 @@
121117
- "tests::cleanup"
122118
block:
123119
- name: Deactivate the connection and remove the connection profile
124-
import_role:
125-
name: linux-system-roles.network
120+
include_tasks: tasks/run_role_with_clear_facts.yml
126121
vars:
127122
network_connections:
128123
- name: "{{ interface }}"
@@ -131,7 +126,7 @@
131126
- name: br1
132127
persistent_state: absent
133128
state: down
134-
failed_when: false
129+
__sr_failed_when: false
135130
- name: Include the task 'cleanup_802_1x_server.yml'
136131
include_tasks: tasks/cleanup_802_1x_server.yml
137132
- name: Remove test certificates

0 commit comments

Comments
 (0)