summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ansible/executor/playbook_executor.py7
-rw-r--r--lib/ansible/executor/task_queue_manager.py7
-rw-r--r--lib/ansible/plugins/strategy/__init__.py18
-rw-r--r--lib/ansible/plugins/strategy/linear.py12
-rw-r--r--test/units/plugins/strategies/test_strategy_base.py13
5 files changed, 40 insertions, 17 deletions
diff --git a/lib/ansible/executor/playbook_executor.py b/lib/ansible/executor/playbook_executor.py
index 041f51bf70..6f38e8e8bc 100644
--- a/lib/ansible/executor/playbook_executor.py
+++ b/lib/ansible/executor/playbook_executor.py
@@ -141,6 +141,11 @@ class PlaybookExecutor:
# and run it...
result = self._tqm.run(play=play)
+ # break the play if the result equals the special return code
+ if result == self._tqm.RUN_FAILED_BREAK_PLAY:
+ result = self._tqm.RUN_FAILED_HOSTS
+ break_play = True
+
# check the number of failures here, to see if they're above the maximum
# failure percentage allowed, or if any errors are fatal. If either of those
# conditions are met, we break out, otherwise we only break out if the entire
@@ -159,7 +164,7 @@ class PlaybookExecutor:
# if the last result wasn't zero or 3 (some hosts were unreachable),
# break out of the serial batch loop
- if result not in (0, 3):
+ if result not in (self._tqm.RUN_OK, self._tqm.RUN_UNREACHABLE_HOSTS):
break
if break_play:
diff --git a/lib/ansible/executor/task_queue_manager.py b/lib/ansible/executor/task_queue_manager.py
index 8373264ef1..8fe7404328 100644
--- a/lib/ansible/executor/task_queue_manager.py
+++ b/lib/ansible/executor/task_queue_manager.py
@@ -58,6 +58,13 @@ class TaskQueueManager:
which dispatches the Play's tasks to hosts.
'''
+ RUN_OK = 0
+ RUN_ERROR = 1
+ RUN_FAILED_HOSTS = 2
+ RUN_UNREACHABLE_HOSTS = 3
+ RUN_FAILED_BREAK_PLAY = 4
+ RUN_UNKNOWN_ERROR = 255
+
def __init__(self, inventory, variable_manager, loader, options, passwords, stdout_callback=None, run_additional_callbacks=True, run_tree=False):
self._inventory = inventory
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index e3bc2ac747..2881bf419e 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -120,7 +120,7 @@ class StrategyBase:
def run(self, iterator, play_context, result=True):
# save the failed/unreachable hosts, as the run_handlers()
# method will clear that information during its execution
- failed_hosts = self._tqm._failed_hosts.keys()
+ failed_hosts = iterator.get_failed_hosts()
unreachable_hosts = self._tqm._unreachable_hosts.keys()
display.debug("running handlers")
@@ -128,18 +128,20 @@ class StrategyBase:
# now update with the hosts (if any) that failed or were
# unreachable during the handler execution phase
- failed_hosts = set(failed_hosts).union(self._tqm._failed_hosts.keys())
+ failed_hosts = set(failed_hosts).union(iterator.get_failed_hosts())
unreachable_hosts = set(unreachable_hosts).union(self._tqm._unreachable_hosts.keys())
# return the appropriate code, depending on the status hosts after the run
- if len(unreachable_hosts) > 0:
- return 3
+ if not isinstance(result, bool) and result != self._tqm.RUN_OK:
+ return result
+ elif len(unreachable_hosts) > 0:
+ return self._tqm.RUN_UNREACHABLE_HOSTS
elif len(failed_hosts) > 0:
- return 2
- elif not result:
- return 1
+ return self._tqm.RUN_FAILED_HOSTS
+ elif isinstance(result, bool) and not result:
+ return self._tqm.RUN_ERROR
else:
- return 0
+ return self._tqm.RUN_OK
def get_hosts_remaining(self, play):
return [host for host in self._inventory.get_hosts(play.hosts)
diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py
index 2d3396a3b2..b0ba34cae1 100644
--- a/lib/ansible/plugins/strategy/linear.py
+++ b/lib/ansible/plugins/strategy/linear.py
@@ -271,7 +271,7 @@ class StrategyModule(StrategyBase):
if not work_to_do and len(iterator.get_failed_hosts()) > 0:
display.debug("out of hosts to run on")
self._tqm.send_callback('v2_playbook_on_no_hosts_remaining')
- result = False
+ result = self._tqm.RUN_ERROR
break
try:
@@ -284,7 +284,7 @@ class StrategyModule(StrategyBase):
variable_manager=self._variable_manager
)
except AnsibleError as e:
- return False
+ return self._tqm.RUN_ERROR
include_failure = False
if len(included_files) > 0:
@@ -354,13 +354,15 @@ class StrategyModule(StrategyBase):
failed_hosts.append(res._host.name)
# if any_errors_fatal and we had an error, mark all hosts as failed
- if any_errors_fatal and len(failed_hosts) > 0:
+ if any_errors_fatal and (len(failed_hosts) > 0 or len(self._tqm._unreachable_hosts.keys()) > 0):
for host in hosts_left:
# don't double-mark hosts, or the iterator will potentially
# fail them out of the rescue/always states
if host.name not in failed_hosts:
self._tqm._failed_hosts[host.name] = True
iterator.mark_host_failed(host)
+ self._tqm.send_callback('v2_playbook_on_no_hosts_remaining')
+ return self._tqm.RUN_FAILED_BREAK_PLAY
display.debug("done checking for any_errors_fatal")
display.debug("checking for max_fail_percentage")
@@ -374,12 +376,14 @@ class StrategyModule(StrategyBase):
if host.name not in failed_hosts:
self._tqm._failed_hosts[host.name] = True
iterator.mark_host_failed(host)
+ self._tqm.send_callback('v2_playbook_on_no_hosts_remaining')
+ return self._tqm.RUN_FAILED_BREAK_PLAY
display.debug("done checking for max_fail_percentage")
except (IOError, EOFError) as e:
display.debug("got IOError/EOFError in task loop: %s" % e)
# most likely an abort, return failed
- return False
+ return self._tqm.RUN_UNKNOWN_ERROR
# run the base class run() method, which executes the cleanup function
# and runs any outstanding handlers which have been triggered
diff --git a/test/units/plugins/strategies/test_strategy_base.py b/test/units/plugins/strategies/test_strategy_base.py
index 9ea944a2a1..338bcc1fd6 100644
--- a/test/units/plugins/strategies/test_strategy_base.py
+++ b/test/units/plugins/strategies/test_strategy_base.py
@@ -64,12 +64,17 @@ class TestStrategyBase(unittest.TestCase):
mock_tqm._options = MagicMock()
strategy_base = StrategyBase(tqm=mock_tqm)
- self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context), 0)
- self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), 1)
+ mock_host = MagicMock()
+ mock_host.name = 'host1'
+
+ self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context), mock_tqm.RUN_OK)
+ self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), mock_tqm.RUN_ERROR)
mock_tqm._failed_hosts = dict(host1=True)
- self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), 2)
+ mock_iterator.get_failed_hosts.return_value = [mock_host]
+ self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), mock_tqm.RUN_FAILED_HOSTS)
mock_tqm._unreachable_hosts = dict(host1=True)
- self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), 3)
+ mock_iterator.get_failed_hosts.return_value = []
+ self.assertEqual(strategy_base.run(iterator=mock_iterator, play_context=mock_play_context, result=False), mock_tqm.RUN_UNREACHABLE_HOSTS)
def test_strategy_base_get_hosts(self):
mock_hosts = []