diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py index c47ac7a0756..7dd24d9fd34 100644 --- a/lib/ansible/playbook/__init__.py +++ b/lib/ansible/playbook/__init__.py @@ -63,7 +63,8 @@ class PlayBook(object): subset = C.DEFAULT_SUBSET, inventory = None, check = False, - diff = False): + diff = False, + any_errors_fatal = False): """ playbook: path to a playbook file @@ -113,6 +114,7 @@ class PlayBook(object): self.global_vars = {} self.private_key_file = private_key_file self.only_tags = only_tags + self.any_errors_fatal = any_errors_fatal self.callbacks.playbook = self self.runner_callbacks.playbook = self @@ -447,6 +449,7 @@ class PlayBook(object): self.inventory.also_restrict_to(on_hosts) for task in play.tasks(): + hosts_count = len(self._list_available_hosts(play.hosts)) # only run the task if the requested tags match should_run = False @@ -464,6 +467,9 @@ class PlayBook(object): host_list = self._list_available_hosts(play.hosts) + if task.any_errors_fatal and len(host_list) < hosts_count: + host_list = None + # if no hosts remain, drop out if not host_list: self.callbacks.on_no_hosts_remaining() diff --git a/lib/ansible/playbook/play.py b/lib/ansible/playbook/play.py index e59912c458c..3a8270d382e 100644 --- a/lib/ansible/playbook/play.py +++ b/lib/ansible/playbook/play.py @@ -30,7 +30,7 @@ class Play(object): 'handlers', 'remote_user', 'remote_port', 'sudo', 'sudo_user', 'transport', 'playbook', 'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks', - 'basedir' + 'basedir', 'any_errors_fatal' ] # to catch typos and so forth -- these are userland names @@ -38,7 +38,8 @@ class Play(object): VALID_KEYS = [ 'hosts', 'name', 'vars', 'vars_prompt', 'vars_files', 'tasks', 'handlers', 'user', 'port', 'include', - 'sudo', 'sudo_user', 'connection', 'tags', 'gather_facts', 'serial' + 'sudo', 'sudo_user', 'connection', 'tags', 'gather_facts', 'serial', + 'any_errors_fatal' ] # ************************************************* @@ -77,6 +78,7 @@ class Play(object): self.gather_facts = ds.get('gather_facts', None) self.serial = int(utils.template(basedir, ds.get('serial', 0), self.vars)) self.remote_port = utils.template(basedir, self.remote_port, self.vars) + self.any_errors_fatal = ds.get('any_errors_fatal', False) self._update_vars_files_for_host(None) diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index d40ca300b62..c8cb07afead 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -27,7 +27,8 @@ class Task(object): 'play', 'notified_by', 'tags', 'register', 'delegate_to', 'first_available_file', 'ignore_errors', 'local_action', 'transport', 'sudo', 'sudo_user', 'sudo_pass', - 'items_lookup_plugin', 'items_lookup_terms', 'environment', 'args' + 'items_lookup_plugin', 'items_lookup_terms', 'environment', 'args', + 'any_errors_fatal' ] # to prevent typos and such @@ -35,7 +36,8 @@ class Task(object): 'name', 'action', 'only_if', 'async', 'poll', 'notify', 'first_available_file', 'include', 'tags', 'register', 'ignore_errors', 'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user', - 'sudo_pass', 'when', 'connection', 'environment', 'args' + 'sudo_pass', 'when', 'connection', 'environment', 'args', + 'any_errors_fatal' ] def __init__(self, play, ds, module_vars=None, additional_conditions=None): @@ -151,6 +153,7 @@ class Task(object): self.ignore_errors = ds.get('ignore_errors', False) + self.any_errors_fatal = ds.get('any_errors_fatal', play.any_errors_fatal) # action should be a string if not isinstance(self.action, basestring):