summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Shrewsbury <Shrews@users.noreply.github.com>2020-08-27 13:14:47 -0400
committerGitHub <noreply@github.com>2020-08-27 12:14:47 -0500
commitf563365f8e7db31831b7934191f6feb58a68c8e7 (patch)
treebbcb1116295361b100bcfe622dc746ccafe0e62e
parentb6c7598a200caf5d263798d482fe75bd7e175e46 (diff)
downloadansible-f563365f8e7db31831b7934191f6feb58a68c8e7.tar.gz
Fix play stats when rescue block is a child block (#70922) (#71335)
* check run state of current block only * Add changelog and test * Add test for issue 29047 (cherry picked from commit f2f6c3463234a59410e4d5bfe320dbff2490d9c4)
-rw-r--r--changelogs/fragments/70922-fix-block-in-rescue.yml2
-rw-r--r--lib/ansible/executor/play_iterator.py11
-rw-r--r--lib/ansible/plugins/strategy/__init__.py7
-rw-r--r--test/integration/targets/blocks/block_in_rescue.yml33
-rw-r--r--test/integration/targets/blocks/issue29047.yml4
-rw-r--r--test/integration/targets/blocks/issue29047_tasks.yml13
-rwxr-xr-xtest/integration/targets/blocks/runme.sh10
7 files changed, 79 insertions, 1 deletions
diff --git a/changelogs/fragments/70922-fix-block-in-rescue.yml b/changelogs/fragments/70922-fix-block-in-rescue.yml
new file mode 100644
index 0000000000..7900452977
--- /dev/null
+++ b/changelogs/fragments/70922-fix-block-in-rescue.yml
@@ -0,0 +1,2 @@
+bugfixes:
+ - Fix statistics reporting when rescue block contains another block (issue https://github.com/ansible/ansible/issues/61253).
diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py
index f67f709245..6ac17af336 100644
--- a/lib/ansible/executor/play_iterator.py
+++ b/lib/ansible/executor/play_iterator.py
@@ -514,6 +514,17 @@ class PlayIterator:
return self.get_active_state(state.always_child_state)
return state
+ def is_any_block_rescuing(self, state):
+ '''
+ Given the current HostState state, determines if the current block, or any child blocks,
+ are in rescue mode.
+ '''
+ if state.run_state == self.ITERATING_RESCUE:
+ return True
+ if state.tasks_child_state is not None:
+ return self.is_any_block_rescuing(state.tasks_child_state)
+ return False
+
def get_original_task(self, host, task):
# now a noop because we've changed the way we do caching
return (None, None)
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index 7e4e4fff64..ca3a16d3c3 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -552,7 +552,12 @@ class StrategyBase:
if iterator.is_failed(original_host) and state and state.run_state == iterator.ITERATING_COMPLETE:
self._tqm._failed_hosts[original_host.name] = True
- if state and iterator.get_active_state(state).run_state == iterator.ITERATING_RESCUE:
+ # Use of get_active_state() here helps detect proper state if, say, we are in a rescue
+ # block from an included file (include_tasks). In a non-included rescue case, a rescue
+ # that starts with a new 'block' will have an active state of ITERATING_TASKS, so we also
+ # check the current state block tree to see if any blocks are rescuing.
+ if state and (iterator.get_active_state(state).run_state == iterator.ITERATING_RESCUE or
+ iterator.is_any_block_rescuing(state)):
self._tqm._stats.increment('rescued', original_host.name)
self._variable_manager.set_nonpersistent_facts(
original_host.name,
diff --git a/test/integration/targets/blocks/block_in_rescue.yml b/test/integration/targets/blocks/block_in_rescue.yml
new file mode 100644
index 0000000000..15360304b5
--- /dev/null
+++ b/test/integration/targets/blocks/block_in_rescue.yml
@@ -0,0 +1,33 @@
+- hosts: localhost
+ gather_facts: no
+ tasks:
+ - block:
+ - name: "EXPECTED FAILURE"
+ fail:
+ msg: "fail to test single level block in rescue"
+ rescue:
+ - block:
+ - debug:
+ msg: Rescued!
+
+ - block:
+ - name: "EXPECTED FAILURE"
+ fail:
+ msg: "fail to test multi-level block in rescue"
+ rescue:
+ - block:
+ - block:
+ - debug:
+ msg: Rescued!
+
+ - name: "Outer block"
+ block:
+ - name: "Inner block"
+ block:
+ - name: "EXPECTED FAILURE"
+ fail:
+ msg: "fail to test multi-level block"
+ rescue:
+ - name: "Rescue block"
+ block:
+ - debug: msg="Inner block rescue"
diff --git a/test/integration/targets/blocks/issue29047.yml b/test/integration/targets/blocks/issue29047.yml
new file mode 100644
index 0000000000..9743773c8c
--- /dev/null
+++ b/test/integration/targets/blocks/issue29047.yml
@@ -0,0 +1,4 @@
+- hosts: localhost
+ gather_facts: no
+ tasks:
+ - include_tasks: issue29047_tasks.yml
diff --git a/test/integration/targets/blocks/issue29047_tasks.yml b/test/integration/targets/blocks/issue29047_tasks.yml
new file mode 100644
index 0000000000..3470d8672d
--- /dev/null
+++ b/test/integration/targets/blocks/issue29047_tasks.yml
@@ -0,0 +1,13 @@
+---
+- name: "EXPECTED FAILURE"
+ block:
+ - fail:
+ msg: "EXPECTED FAILURE"
+ rescue:
+ - name: Assert that ansible_failed_task is defined
+ assert:
+ that: ansible_failed_task is defined
+
+ - name: Assert that ansible_failed_result is defined
+ assert:
+ that: ansible_failed_result is defined
diff --git a/test/integration/targets/blocks/runme.sh b/test/integration/targets/blocks/runme.sh
index edba0c5275..4f3db1db75 100755
--- a/test/integration/targets/blocks/runme.sh
+++ b/test/integration/targets/blocks/runme.sh
@@ -83,3 +83,13 @@ set -e
cat rc_test.out
[ $exit_code -eq 0 ]
rm -f rc_test_out
+
+# https://github.com/ansible/ansible/issues/29047
+ansible-playbook -vv issue29047.yml -i ../../inventory
+
+# https://github.com/ansible/ansible/issues/61253
+ansible-playbook -vv block_in_rescue.yml -i ../../inventory > rc_test.out
+cat rc_test.out
+[ "$(grep -c 'rescued=3' rc_test.out)" -eq 1 ]
+[ "$(grep -c 'failed=0' rc_test.out)" -eq 1 ]
+rm -f rc_test.out