From d2c8520da04eae7398ff52f103f0d155ad02fca7 Mon Sep 17 00:00:00 2001 From: s-hertel <19572925+s-hertel@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:43:00 -0400 Subject: [PATCH] fix clearing unreachable hosts --- lib/ansible/plugins/strategy/__init__.py | 5 ++ .../targets/meta_tasks/inventory.yml | 2 + test/integration/targets/meta_tasks/runme.sh | 31 ++++++++ .../meta_tasks/test_clear_host_errors.yml | 75 +++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 test/integration/targets/meta_tasks/test_clear_host_errors.yml diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index efd69efe9b4..ad928358395 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -1003,6 +1003,11 @@ class StrategyBase: self._tqm._failed_hosts.pop(host.name, False) self._tqm._unreachable_hosts.pop(host.name, False) iterator.clear_host_errors(host) + if host.name in iterator._play._removed_hosts: + # the host failed a previous play + iterator._play._removed_hosts.remove(host.name) + # update the host state to here + iterator._host_states[host.name] = iterator._host_states[target_host.name].copy() msg = "cleared host errors" else: skipped = True diff --git a/test/integration/targets/meta_tasks/inventory.yml b/test/integration/targets/meta_tasks/inventory.yml index 5fb39e5fb88..d823d4d9ed7 100644 --- a/test/integration/targets/meta_tasks/inventory.yml +++ b/test/integration/targets/meta_tasks/inventory.yml @@ -4,6 +4,8 @@ local: host_var_role_name: role3 testhost2: host_var_role_name: role2 + testhost3: + host_var_role_name: role1 vars: ansible_connection: local ansible_python_interpreter: "{{ ansible_playbook_python }}" diff --git a/test/integration/targets/meta_tasks/runme.sh b/test/integration/targets/meta_tasks/runme.sh index f7d8d8973f4..c4c7cdbda2e 100755 --- a/test/integration/targets/meta_tasks/runme.sh +++ b/test/integration/targets/meta_tasks/runme.sh @@ -73,6 +73,37 @@ for test_strategy in linear free; do grep -qv 'Failed to end_batch' <<< "$out" done +# test clear_host_errors meta task +for test_strategy in linear free; do + out="$(ansible-playbook test_clear_host_errors.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")" + + for initial_hosts in testhost testhost2 testhost3; do + grep -q "starting play for $initial_hosts" <<< "$out" + done + + for host_left in testhost testhost3; do + grep -q "post-failure and pre-recovery for $host_left" <<< "$out" + grep -q "second post-failure and pre-recovery for $host_left" <<< "$out" + grep -q "block post-failure and pre-recovery for $host_left" <<< "$out" + grep -q "second in block post-failure and pre-recovery for $host_left" <<< "$out" + grep -q "next play pre-recovery for $host_left" <<< "$out" + done + + grep -qv "post-failure and pre-recovery for testhost2" <<< "$out" + grep -qv "second post-failure and pre-recovery for testhost2" <<< "$out" + grep -qv "block post-failure and pre-recovery for testhost2" <<< "$out" + grep -qv "second in block post-failure and pre-recovery for testhost2" <<< "$out" + grep -qv "next play pre-recovery for testhost2" <<< "$out" + + for host in testhost testhost2 testhost3; do + grep -q "$host in block" <<< "$out" + grep -q "post-recovery for $host" <<< "$out" + grep -q "second post-recovery for $host" <<< "$out" + grep -q "next play post-recovery for $host" <<< "$out" + grep -q "post-recovery in rescue for $host" <<< "$out" + done +done + # test refresh ansible-playbook -i inventory_refresh.yml refresh.yml "$@" ansible-playbook -i inventory_refresh.yml refresh_preserve_dynamic.yml "$@" diff --git a/test/integration/targets/meta_tasks/test_clear_host_errors.yml b/test/integration/targets/meta_tasks/test_clear_host_errors.yml new file mode 100644 index 00000000000..4b0092063ad --- /dev/null +++ b/test/integration/targets/meta_tasks/test_clear_host_errors.yml @@ -0,0 +1,75 @@ +- name: "Testing clear_host_errors with strategy={{ test_strategy | default('linear') }}" + hosts: + - testhost + - testhost2 + - testhost3 + gather_facts: no + strategy: "{{ test_strategy | default('linear') }}" + tasks: + + - name: run all three hosts + debug: msg='starting play for {{ inventory_hostname }}' + + - name: fail testhost2 (EXPECTED FAILURE) + fail: + when: "host_var_role_name == 'role2'" + + - debug: msg='post-failure and pre-recovery for {{ inventory_hostname }}' + + - debug: msg='second post-failure and pre-recovery for {{ inventory_hostname }}' + + - meta: clear_host_errors + + - name: run all three hosts + debug: msg='post-recovery for {{ inventory_hostname }}' + + - block: + - block: + - debug: msg="{{ inventory_hostname }} in block" + + - debug: msg="{{ inventory_hostname }} in block2" + + - name: fail testhost2 again (EXPECTED FAILURE) + fail: + when: "host_var_role_name == 'role2'" + + - debug: msg='block post-failure and pre-recovery for {{ inventory_hostname }}' + + - debug: msg='second in block post-failure and pre-recovery for {{ inventory_hostname }}' + + - block: + + - meta: clear_host_errors + + - debug: msg='third in block post-recovery {{ inventory_hostname }}' + + - debug: msg='second post-recovery for {{ inventory_hostname }}' + + - name: fail testhost2 (EXPECTED FAILURE) + fail: + when: "host_var_role_name == 'role2'" + +- name: "Testing clear_host_errors across plays with strategy={{ test_strategy | default('linear') }}" + hosts: + - testhost + - testhost2 + - testhost3 + gather_facts: no + strategy: "{{ test_strategy | default('linear') }}" + pre_tasks: + - debug: msg="next play pre-recovery for {{ inventory_hostname }}" + + - meta: clear_host_errors + + - debug: msg="next play post-recovery for {{ inventory_hostname }}" + +- hosts: testhost,testhost2,testhost3 + gather_facts: no + tasks: + - block: + - name: fail testhost2 (EXPECTED FAILURE) + fail: + when: "inventory_hostname == 'testhost2'" + rescue: + - meta: clear_host_errors + - debug: msg="post-recovery in rescue for {{ inventory_hostname }}"