Repository: ansible/ansible

Issue:
config doesn't honor required
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
lib/ansible/config/

##### ANSIBLE VERSION
<!--- Paste, BELOW THIS COMMENT, verbatim output from "ansible --version" between quotes below -->
```
2.4
2.5
2.6
```

##### CONFIGURATION
<!--- If using Ansible 2.4 or above, paste, BELOW THIS COMMENT, the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).-->

##### OS / ENVIRONMENT
<!--- Mention, BELOW THIS COMMENT, the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.-->

##### SUMMARY

1. Config manager does not honor `required` config entries
1. Plugins consuming a config from `vars` do not fail on `ensure_type` when typing fails. The value is added to `UNABLE` which is only used from the CLI on config parsing, so a plugin using vars is silently not typed

##### 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. -->

```
$ ANSIBLE_CALLBACK_WHITELIST=cgroup_memory_recap ansible-playbook -vvv playbook.yml
```

Run the above without configuring any of the required config entries.

I don't have a reproducer for the `vars` version as of yet.

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```

```


Discussion:
Files identified in the description:
* [lib/ansible/cli/config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/cli/config.py)
* [lib/ansible/config/__init__.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/config/__init__.py)
* [lib/ansible/config/base.yml](https://github.com/ansible/ansible/blob/devel/lib/ansible/config/base.yml)
* [lib/ansible/config/data.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/config/data.py)
* [lib/ansible/config/manager.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/config/manager.py)
* [lib/ansible/module_utils/network/common/config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/network/common/config.py)
* [lib/ansible/plugins/lookup/config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/lookup/config.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @Qalthos @ganeshrn @gdpak @gundalow @privateip @rcarrillocruz @trishnaguha
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py
--- a/lib/ansible/config/manager.py
+++ b/lib/ansible/config/manager.py
@@ -343,11 +343,20 @@ def get_config_value_and_origin(self, config, cfile=None, plugin_type=None, plug
 
             # set default if we got here w/o a value
             if value is None:
-                value = defs[config].get('default')
-                origin = 'default'
-                # skip typing as this is a temlated default that will be resolved later in constants, which has needed vars
-                if plugin_type is None and isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')):
-                    return value, origin
+                if defs[config].get('required', False):
+                    entry = ''
+                    if plugin_type:
+                        entry += 'plugin_type: %s ' % plugin_type
+                        if plugin_name:
+                            entry += 'plugin: %s ' % plugin_name
+                    entry += 'setting: %s ' % config
+                    raise AnsibleError("No setting was provided for required configuration %s" % (entry))
+                else:
+                    value = defs[config].get('default')
+                    origin = 'default'
+                    # skip typing as this is a temlated default that will be resolved later in constants, which has needed vars
+                    if plugin_type is None and isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')):
+                        return value, origin
 
             # ensure correct type
             try:
diff --git a/lib/ansible/plugins/lookup/vars.py b/lib/ansible/plugins/lookup/vars.py
--- a/lib/ansible/plugins/lookup/vars.py
+++ b/lib/ansible/plugins/lookup/vars.py
@@ -11,7 +11,7 @@
     description:
       - Retrieves the value of an Ansible variable.
     options:
-      _term:
+      _terms:
         description: The variable names to look up.
         required: True
       default:
@@ -69,6 +69,7 @@ def run(self, terms, variables=None, **kwargs):
             self._templar.set_available_variables(variables)
         myvars = getattr(self._templar, '_available_variables', {})
 
+        self.set_option('_terms', terms)
         self.set_options(direct=kwargs)
         default = self.get_option('default')
 


Test patch: