diff --git a/plugins/module_utils/mh/mixins/deprecate_attrs.py b/plugins/module_utils/mh/mixins/deprecate_attrs.py new file mode 100644 index 0000000000..fb440aba4c --- /dev/null +++ b/plugins/module_utils/mh/mixins/deprecate_attrs.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# (c) 2020, Alexei Znamensky +# Copyright: (c) 2020, Ansible Project +# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +from ansible.module_utils.basic import AnsibleModule + + +class DeprecateAttrsMixin(object): + + def _deprecate_setup(self, attr, target, module): + if target is None: + target = self + if not hasattr(target, attr): + raise ValueError("Target {0} has no attribute {1}".format(target, attr)) + if module is None: + if isinstance(target, AnsibleModule): + module = target + elif hasattr(target, "module") and isinstance(target.module, AnsibleModule): + module = target.module + else: + raise ValueError("Failed to automatically discover the AnsibleModule instance. Pass 'module' parameter explicitly.") + + # setup internal state dicts + value_attr = "__deprecated_attr_value" + trigger_attr = "__deprecated_attr_trigger" + if not hasattr(target, value_attr): + setattr(target, value_attr, {}) + if not hasattr(target, trigger_attr): + setattr(target, trigger_attr, {}) + value_dict = getattr(target, value_attr) + trigger_dict = getattr(target, trigger_attr) + return target, module, value_dict, trigger_dict + + def _deprecate_attr(self, attr, msg, version=None, date=None, collection_name=None, target=None, value=None, module=None): + target, module, value_dict, trigger_dict = self._deprecate_setup(attr, target, module) + + value_dict[attr] = getattr(target, attr, value) + trigger_dict[attr] = False + + def _trigger(): + if not trigger_dict[attr]: + module.deprecate(msg, version=version, date=date, collection_name=collection_name) + trigger_dict[attr] = True + + def _getter(_self): + _trigger() + return value_dict[attr] + + def _setter(_self, new_value): + _trigger() + value_dict[attr] = new_value + + # override attribute + prop = property(_getter) + setattr(target, attr, prop) + setattr(target, "_{0}_setter".format(attr), prop.setter(_setter)) diff --git a/tests/integration/targets/module_helper/library/msimpleda.py b/tests/integration/targets/module_helper/library/msimpleda.py new file mode 100644 index 0000000000..117de079d5 --- /dev/null +++ b/tests/integration/targets/module_helper/library/msimpleda.py @@ -0,0 +1,64 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# (c) 2021, Alexei Znamensky +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +import collections +__metaclass__ = type + +DOCUMENTATION = ''' +module: msimpleda +author: "Alexei Znamensky (@russoz)" +short_description: Simple module for testing DeprecationAttrsMixin +description: + - Simple module test description. +options: + a: + description: aaaa + type: int +''' + +EXAMPLES = "" + +RETURN = "" + +from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper +from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin + + +class MSimpleDA(DeprecateAttrsMixin, ModuleHelper): + output_params = ('a',) + module = dict( + argument_spec=dict( + a=dict(type='int'), + ), + ) + + attr1 = "abc" + attr2 = "def" + + def __init_module__(self): + self._deprecate_attr( + "attr2", + msg="Attribute attr2 is deprecated", + version="9.9.9", + collection_name="community.general", + target=self.__class__, + module=self.module, + ) + + def __run__(self): + if self.vars.a == 1: + self.vars.attr1 = self.attr1 + if self.vars.a == 2: + self.vars.attr2 = self.attr2 + + +def main(): + MSimpleDA.execute() + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/module_helper/tasks/main.yml b/tests/integration/targets/module_helper/tasks/main.yml index 8ac7c8ae60..f7e36537a6 100644 --- a/tests/integration/targets/module_helper/tasks/main.yml +++ b/tests/integration/targets/module_helper/tasks/main.yml @@ -4,3 +4,4 @@ - include_tasks: msimple.yml - include_tasks: mdepfail.yml - include_tasks: mstate.yml +- include_tasks: msimpleda.yml diff --git a/tests/integration/targets/module_helper/tasks/msimpleda.yml b/tests/integration/targets/module_helper/tasks/msimpleda.yml new file mode 100644 index 0000000000..a3c5bae422 --- /dev/null +++ b/tests/integration/targets/module_helper/tasks/msimpleda.yml @@ -0,0 +1,37 @@ +# (c) 2021, Alexei Znamensky +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: test msimpleda 1 + msimpleda: + a: 1 + register: simple1 + +- name: assert simple1 + assert: + that: + - simple1.a == 1 + - simple1.attr1 == "abc" + +- name: test msimpleda 2 + msimpleda: + a: 2 + register: simple2 + +- set_fact: + attr2_d: + msg: Attribute attr2 is deprecated + version: 9.9.9 + collection_name: community.general + attr2_d_29: + msg: Attribute attr2 is deprecated + version: 9.9.9 + +- name: assert simple2 + assert: + that: + - simple2.a == 2 + - simple2.attr2 == "def" + - '"deprecations" in simple2' + - attr2_depr_dict in simple2.deprecations + vars: + attr2_depr_dict: "{{ ((ansible_version.major, ansible_version.minor) < (2, 10))|ternary(attr2_d_29, attr2_d) }}"