Skip to content

Commit

Permalink
Make action_module plugin utils compatible with latest changes in ans…
Browse files Browse the repository at this point in the history
…ible-core 2.11.0b3
  • Loading branch information
felixfontein committed Mar 21, 2021
1 parent 22bc995 commit 1c8106d
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bugfixes:
- "action_module plugin helper - make compatible with latest changes in ansible-core 2.11.0b3 (https://github.com/ansible-collections/community.sops/pull/58)."
- "community.sops.load_vars - make compatible with latest changes in ansible-core 2.11.0b3 (https://github.com/ansible-collections/community.sops/pull/58)."
185 changes: 104 additions & 81 deletions plugins/plugin_utils/action_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
# Copyright (c) 2016 Toshio Kuratomi <[email protected]>
# Copyright (c) 2019 Ansible Project
# Copyright (c) 2020 Felix Fontein <[email protected]>
# Copyright (c) 2021 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

# Parts taken from ansible.module_utils.basic and ansible.module_utils.common.warnings.

# NOTE: THIS MUST NOT BE USED BY A MODULE! THIS IS ONLY FOR ACTION PLUGINS!
# NOTE: THIS IS ONLY FOR ACTION PLUGINS!

from __future__ import absolute_import, division, print_function
__metaclass__ = type
Expand All @@ -26,9 +27,6 @@
Mapping
)
from ansible.module_utils.common.parameters import (
handle_aliases,
list_deprecations,
list_no_log_values,
PASS_VARS,
PASS_BOOLS,
)
Expand Down Expand Up @@ -66,6 +64,26 @@
from ansible.plugins.action import ActionBase


try:
# For ansible-core 2.11, we can use the ArgumentSpecValidator. We also import
# ModuleArgumentSpecValidator since that indicates that the 'classical' approach
# will no longer work.
from ansible.module_utils.common.arg_spec import (
ArgumentSpecValidator,
ModuleArgumentSpecValidator, # noqa
)
from ansible.module_utils.errors import UnsupportedError
HAS_ARGSPEC_VALIDATOR = True
except ImportError:
# For ansible-base 2.10 and Ansible 2.9, we need to use the 'classical' approach
from ansible.module_utils.common.parameters import (
handle_aliases,
list_deprecations,
list_no_log_values,
)
HAS_ARGSPEC_VALIDATOR = False


class _ModuleExitException(Exception):
def __init__(self, result):
super(_ModuleExitException, self).__init__()
Expand Down Expand Up @@ -104,54 +122,91 @@ def __init__(self, action_plugin, argument_spec, bypass_checks=False,
self._options_context = list()

self.params = copy.deepcopy(action_plugin._task.args)
self._set_fallbacks()

# append to legal_inputs and then possibly check against them
try:
self.aliases = self._handle_aliases()
except (ValueError, TypeError) as e:
# Use exceptions here because it isn't safe to call fail_json until no_log is processed
raise _ModuleExitException(dict(failed=True, msg="Module alias error: %s" % to_native(e)))

# Save parameter values that should never be logged
self.no_log_values = set()
self._handle_no_log_values()

self._check_arguments()

# check exclusive early
if not bypass_checks:
self._check_mutually_exclusive(mutually_exclusive)

self._set_defaults(pre=True)

self._CHECK_ARGUMENT_TYPES_DISPATCHER = {
'str': self._check_type_str,
'list': self._check_type_list,
'dict': self._check_type_dict,
'bool': self._check_type_bool,
'int': self._check_type_int,
'float': self._check_type_float,
'path': self._check_type_path,
'raw': self._check_type_raw,
'jsonarg': self._check_type_jsonarg,
'json': self._check_type_jsonarg,
'bytes': self._check_type_bytes,
'bits': self._check_type_bits,
}
if not bypass_checks:
self._check_required_arguments()
self._check_argument_types()
self._check_argument_values()
self._check_required_together(required_together)
self._check_required_one_of(required_one_of)
self._check_required_if(required_if)
self._check_required_by(required_by)
if HAS_ARGSPEC_VALIDATOR:
self._validator = ArgumentSpecValidator(
self.argument_spec,
self.mutually_exclusive,
self.required_together,
self.required_one_of,
self.required_if,
self.required_by,
)
self._validation_result = self._validator.validate(self.params)
self.params.update(self._validation_result.validated_parameters)
self.no_log_values.update(self._validation_result._no_log_values)

self._set_defaults(pre=False)
try:
error = self._validation_result.errors[0]
except IndexError:
error = None

# We cannot use ModuleArgumentSpecValidator directly since it uses mechanisms for reporting
# warnings and deprecations that do not work in plugins. This is a copy of that code adjusted
# for our use-case:
for d in self._validation_result._deprecations:
self.deprecate(
"Alias '{name}' is deprecated. See the module docs for more information".format(name=d['name']),
version=d.get('version'), date=d.get('date'), collection_name=d.get('collection_name'))

for w in self._validation_result._warnings:
self.warn('Both option {option} and its alias {alias} are set.'.format(option=w['option'], alias=w['alias']))

# Fail for validation errors, even in check mode
if error:
msg = self._validation_result.errors.msg
if isinstance(error, UnsupportedError):
msg = "Unsupported parameters for ({name}) {kind}: {msg}".format(name=self._name, kind='module', msg=msg)

# deal with options sub-spec
self._handle_options()
self.fail_json(msg=msg)
else:
self._set_fallbacks()

# append to legal_inputs and then possibly check against them
try:
self.aliases = self._handle_aliases()
except (ValueError, TypeError) as e:
# Use exceptions here because it isn't safe to call fail_json until no_log is processed
raise _ModuleExitException(dict(failed=True, msg="Module alias error: %s" % to_native(e)))

# Save parameter values that should never be logged
self._handle_no_log_values()

self._check_arguments()

# check exclusive early
if not bypass_checks:
self._check_mutually_exclusive(mutually_exclusive)

self._set_defaults(pre=True)

self._CHECK_ARGUMENT_TYPES_DISPATCHER = {
'str': self._check_type_str,
'list': check_type_list,
'dict': check_type_dict,
'bool': check_type_bool,
'int': check_type_int,
'float': check_type_float,
'path': check_type_path,
'raw': check_type_raw,
'jsonarg': check_type_jsonarg,
'json': check_type_jsonarg,
'bytes': check_type_bytes,
'bits': check_type_bits,
}
if not bypass_checks:
self._check_required_arguments()
self._check_argument_types()
self._check_argument_values()
self._check_required_together(required_together)
self._check_required_one_of(required_one_of)
self._check_required_if(required_if)
self._check_required_by(required_by)

self._set_defaults(pre=False)

# deal with options sub-spec
self._handle_options()

def _handle_aliases(self, spec=None, param=None, option_prefix=''):
if spec is None:
Expand Down Expand Up @@ -413,36 +468,6 @@ def _check_type_str(self, value, param=None, prefix=''):
self.warn(to_native(msg))
return to_native(value, errors='surrogate_or_strict')

def _check_type_list(self, value):
return check_type_list(value)

def _check_type_dict(self, value):
return check_type_dict(value)

def _check_type_bool(self, value):
return check_type_bool(value)

def _check_type_int(self, value):
return check_type_int(value)

def _check_type_float(self, value):
return check_type_float(value)

def _check_type_path(self, value):
return check_type_path(value)

def _check_type_jsonarg(self, value):
return check_type_jsonarg(value)

def _check_type_raw(self, value):
return check_type_raw(value)

def _check_type_bytes(self, value):
return check_type_bytes(value)

def _check_type_bits(self, value):
return check_type_bits(value)

def _handle_options(self, argument_spec=None, params=None, prefix=''):
''' deal with options to create sub spec '''
if argument_spec is None:
Expand Down Expand Up @@ -728,8 +753,6 @@ def run(self, tmp=None, task_vars=None):
except _ModuleExitException as mee:
result.update(mee.result)
return result
except AnsibleError as dummy:
raise
except Exception as dummy:
result['failed'] = True
result['msg'] = 'MODULE FAILURE'
Expand Down

0 comments on commit 1c8106d

Please sign in to comment.