Repository: ansible/ansible

Issue:
implement module params deprecation warnings
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Feature Pull Request
##### COMPONENT NAME

module_utils
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
2.3
```
##### SUMMARY

implemented a simple way to deprecate a module param by adding `deprecated_version=2.4` 

Test module
~~~python
#!/usr/bin/python

from ansible.module_utils.basic import *
def main():
    module = AnsibleModule(dict(
        foo=dict(deprecated_version=2.4),
        )
    )
    module.exit_json(msg="ok")

if __name__ == '__main__':
    main()
~~~

output:
~~~
 $ ansible-playbook test.yml
 [WARNING]: Host file not found: /etc/ansible/hosts

 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [localhost] ******************************************************************************************************************************************************************************************************************************

TASK [foobar] *********************************************************************************************************************************************************************************************************************************
ok: [localhost]
[DEPRECATION WARNING]: Param 'foo' is deprecated. See the module docs for more information.
This feature will be removed in version 2.4. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

PLAY RECAP ************************************************************************************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0   
~~~


Discussion:
i'm thinking (sorry) that deprecated_version implies deprecated already, simpler interface?

It does actually imply already.  see `foo=dict(deprecated_version=2.4),` 

```
TASK [foobar] *********************************************************************************************************************************************************************************************************************************
ok: [localhost]
[DEPRECATION WARNING]: Param 'foo' is deprecated. See the module docs for more information.
This feature will be removed in version 2.4. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
```

or do you mean we should only provide `deprecation_version`? 

i liked your method so much i implemented similar for warnings #18517 (but had to be backwards compat)

rebased
@resmo, I merged the PR that deals with warnings/deprecation keys, can you revise this one to generate the warnings based on the argument's deprecation field?

Resolving patch:
diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py
--- a/lib/ansible/module_utils/basic.py
+++ b/lib/ansible/module_utils/basic.py
@@ -718,6 +718,12 @@ def __init__(self, argument_spec, bypass_checks=False, no_log=False,
                 if no_log_object:
                     self.no_log_values.update(return_values(no_log_object))
 
+            if arg_opts.get('removed_in_version') is not None and arg_name in self.params:
+                self._deprecations.append({
+                    'msg': "Param '%s' is deprecated. See the module docs for more information" % arg_name,
+                    'version': arg_opts.get('removed_in_version')
+                })
+
         # check the locale as set by the current environment, and reset to
         # a known valid (LANG=C) if it's an invalid/unavailable locale
         self._check_locale()
@@ -768,13 +774,15 @@ def warn(self, warning):
         else:
             raise TypeError("warn requires a string not a %s" % type(warning))
 
-    def deprecate(self, deprecate):
-
-        if isinstance(deprecate, string_types):
-            self._deprecations.append(deprecate)
-            self.log('[DEPRECATION WARNING] %s' % deprecate)
+    def deprecate(self, msg, version=None):
+        if isinstance(msg, string_types):
+            self._deprecations.append({
+                'msg': msg,
+                'version': version
+            })
+            self.log('[DEPRECATION WARNING] %s %s' % (msg, version))
         else:
-            raise TypeError("deprecate requires a string not a %s" % type(deprecate))
+            raise TypeError("deprecate requires a string not a %s" % type(msg))
 
     def load_file_common_arguments(self, params):
         '''
diff --git a/lib/ansible/plugins/callback/__init__.py b/lib/ansible/plugins/callback/__init__.py
--- a/lib/ansible/plugins/callback/__init__.py
+++ b/lib/ansible/plugins/callback/__init__.py
@@ -105,7 +105,7 @@ def _handle_warnings(self, res):
                     self._display.warning(warning)
             if 'deprecations' in res and res['deprecations']:
                 for warning in res['deprecations']:
-                    self._display.deprecated(warning)
+                    self._display.deprecated(**warning)
 
     def _get_diff(self, difflist):
 


Test patch: