Repository: ansible/ansible
Pull request: add any_errors_fatal global config
##### SUMMARY
<!--- Describe the change, including rationale and design decisions -->
fixes #22340

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Feature Pull Request
 

##### COMPONENT NAME
<!--- Name of the module/plugin/module/task -->
plays

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
2.4
```

Problem statement:
Feature Idea: globally configurable any_errors_fatal in ansible.cfg
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Feature Idea

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
ansible.cfg

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
n/a
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
`any_errors_fatal: true`

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->

##### SUMMARY
<!--- Explain the problem briefly -->
It would nice to be able to configure any_errors_fatal: true/false on a global level instead of putting it on every single play. I don't know the most common use cases, but given playbooks are generally idempotent, it seems ok to keep running until all hosts pass. 

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
ansible.cfg set any_errors_fatal globally

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```

```

Hints from issue discussion:
I just wanted to say that this is a brilliant idea and I would have much more faith in my CD pipelines with this implemented.
I'd prefer to be able to set the default value of `any_errors_fatal` in ansible.cfg as well. It can be false for compatibility and to match existing behavior. 

We use ansible inside tooling containers and have a unified ansible.cfg where this makes a lot of sense and keeps us from having to bloat each playbook.

Commit message: add any_errors_fatal global config

Patch to review:
diff --git a/examples/ansible.cfg b/examples/ansible.cfg
index dc8d8b7443a380..674c5d3333c848 100644
--- a/examples/ansible.cfg
+++ b/examples/ansible.cfg
@@ -310,6 +310,9 @@
 # ENABLING THIS COULD BE A SECURITY RISK
 #allow_unsafe_lookups = False
 
+# set default errors for all plays
+#any_errors_fatal = False
+
 [privilege_escalation]
 #become=True
 #become_method=sudo
diff --git a/lib/ansible/config/data/config.yml b/lib/ansible/config/data/config.yml
index 68deb5eb117432..ea8893b33b46ed 100644
--- a/lib/ansible/config/data/config.yml
+++ b/lib/ansible/config/data/config.yml
@@ -180,6 +180,16 @@ ANSIBLE_SSH_RETRIES:
   value_type: integer
   vars: []
   yaml: {key: ssh_connection.retries}
+ANY_ERRORS_FATAL:
+    default: False
+    env:
+      - name: ANSIBLE_ANY_ERRORS_FATAL
+    ini:
+      - section:  defauls
+        key: any_errors_fatal
+    value_type: boolean
+    vars: []
+    yaml: {key: errors.anyerrors_fatal}
 BECOME_ALLOW_SAME_USER:
   default: False
   desc: 'TODO: write it'
diff --git a/lib/ansible/playbook/base.py b/lib/ansible/playbook/base.py
index 07236a0f0636af..9a424c19d3d12c 100644
--- a/lib/ansible/playbook/base.py
+++ b/lib/ansible/playbook/base.py
@@ -27,12 +27,13 @@
 
 from jinja2.exceptions import UndefinedError
 
+from ansible import constants as C
+from ansible.constants import mk_boolean as boolean
 from ansible.module_utils.six import iteritems, string_types, with_metaclass
 from ansible.errors import AnsibleParserError, AnsibleUndefinedVariable
 from ansible.module_utils._text import to_text
 from ansible.playbook.attribute import Attribute, FieldAttribute
 from ansible.parsing.dataloader import DataLoader
-from ansible.constants import mk_boolean as boolean
 from ansible.utils.vars import combine_vars, isidentifier, get_unique_id
 
 try:
@@ -157,13 +158,13 @@ class Base(with_metaclass(BaseMeta, object)):
     _vars = FieldAttribute(isa='dict', priority=100, inherit=False)
 
     # flags and misc. settings
-    _environment      = FieldAttribute(isa='list')
-    _no_log           = FieldAttribute(isa='bool')
-    _always_run       = FieldAttribute(isa='bool')
-    _run_once         = FieldAttribute(isa='bool')
-    _ignore_errors    = FieldAttribute(isa='bool')
-    _check_mode       = FieldAttribute(isa='bool')
-    _any_errors_fatal = FieldAttribute(isa='bool', always_post_validate=True)
+    _environment         = FieldAttribute(isa='list')
+    _no_log              = FieldAttribute(isa='bool')
+    _always_run          = FieldAttribute(isa='bool')
+    _run_once            = FieldAttribute(isa='bool')
+    _ignore_errors       = FieldAttribute(isa='bool')
+    _check_mode          = FieldAttribute(isa='bool')
+    _any_errors_fatal     = FieldAttribute(isa='bool', default=C.ANY_ERRORS_FATAL, always_post_validate=True)
 
     # param names which have been deprecated/removed
     DEPRECATED_ATTRIBUTES = [


Code review comments:
diff_hunk: @@ -180,6 +180,16 @@ ANSIBLE_SSH_RETRIES:
   value_type: integer
   vars: []
   yaml: {key: ssh_connection.retries}
+ANY_ERRORS_FATAL:
+    default: False
+    env:
+      - name: ANSIBLE_ANY_ERRORS_FATAL
+    ini:
+      - section:  defauls
path: lib/ansible/config/data/config.yml
text: @user1:
You spelled `defaults` wrong

@author:
no ... its new 'defauls' section ... special ...