Add porting guide and documentation for changes to argument spec validation (#74268)
* Add ArgumentSpecValidator to docs * Improve docs for ArgumentSpecValidator * Document removal of private methods * Update module_utils documentation - Add docs for argument spec classes as well as validation and parameters files. - preserve the order in the source for errors.py - document DEFAULT_TYPE_VALIDATORS so it can be referenced elsewhere - fix automodule directive for validation.py * Update docs in arg_spec and paremeters - This improves the generated documentation. * Document breaking changes in porting guide. * Update formatting in porting guide and add a Deprecated section * Fine tune module_utils documentation * Move instance docstring to the __init__ method Remove optional description since it fails the sanity test and I am not 100% it is valid anyway. * Remoe incorrect parameter from docstring This was changed a while ago but wasn't removed from the docstring. * Use attr rather than attribute The py:attribute: domain only exists in newer Sphinx >= 3.1. * Improve documentation on exceptions * Final pass - use args/kwargs instead of param - fix formatting errors that didn't display examples correctly - format TypeErrors so they are referenced as classes - specify complex types
This commit is contained in:
parent
6e56e72d99
commit
2cbfd1e350
6 changed files with 284 additions and 126 deletions
|
@ -29,22 +29,71 @@ Command Line
|
|||
* The ``ansible-galaxy login`` command has been removed, as the underlying API it used for GitHub auth has been shut down. Publishing roles or collections to Galaxy with ``ansible-galaxy`` now requires that a Galaxy API token be passed to the CLI using a token file (default location ``~/.ansible/galaxy_token``) or (insecurely) with the ``--token`` argument to ``ansible-galaxy``.
|
||||
|
||||
|
||||
Other:
|
||||
Deprecated
|
||||
==========
|
||||
|
||||
The constant ``ansible.module_utils.basic._CHECK_ARGUMENT_TYPES_DISPATCHER`` is deprecated. Use :const:`ansible.module_utils.common.parameters.DEFAULT_TYPE_VALIDATORS` instead.
|
||||
|
||||
|
||||
Breaking Changes
|
||||
================
|
||||
|
||||
Changes to ``AnsibleModule``
|
||||
----------------------------
|
||||
|
||||
With the move to :class:`ArgumentSpecValidator <ansible.module_utils.common.arg_spec.ArgumentSpecValidator>` for performing argument spec validation, the following private methods in :class:`AnsibleModule <ansible.module_utils.basic.AnsibleModule>` have been removed:
|
||||
|
||||
- ``_check_argument_types()``
|
||||
- ``_check_argument_values()``
|
||||
- ``_check_arguments()``
|
||||
- ``_check_mutually_exclusive()`` --> :func:`ansible.module_utils.common.validation.check_mutually_exclusive`
|
||||
- ``_check_required_arguments()`` --> :func:`ansible.module_utils.common.validation.check_required_arguments`
|
||||
- ``_check_required_by()`` --> :func:`ansible.module_utils.common.validation.check_required_by`
|
||||
- ``_check_required_if()`` --> :func:`ansible.module_utils.common.validation.check_required_if`
|
||||
- ``_check_required_one_of()`` --> :func:`ansible.module_utils.common.validation.check_required_one_of`
|
||||
- ``_check_required_together()`` --> :func:`ansible.module_utils.common.validation.check_required_together`
|
||||
- ``_check_type_bits()`` --> :func:`ansible.module_utils.common.validation.check_type_bits`
|
||||
- ``_check_type_bool()`` --> :func:`ansible.module_utils.common.validation.check_type_bool`
|
||||
- ``_check_type_bytes()`` --> :func:`ansible.module_utils.common.validation.check_type_bytes`
|
||||
- ``_check_type_dict()`` --> :func:`ansible.module_utils.common.validation.check_type_dict`
|
||||
- ``_check_type_float()`` --> :func:`ansible.module_utils.common.validation.check_type_float`
|
||||
- ``_check_type_int()`` --> :func:`ansible.module_utils.common.validation.check_type_int`
|
||||
- ``_check_type_jsonarg()`` --> :func:`ansible.module_utils.common.validation.check_type_jsonarg`
|
||||
- ``_check_type_list()`` --> :func:`ansible.module_utils.common.validation.check_type_list`
|
||||
- ``_check_type_path()`` --> :func:`ansible.module_utils.common.validation.check_type_path`
|
||||
- ``_check_type_raw()`` --> :func:`ansible.module_utils.common.validation.check_type_raw`
|
||||
- ``_check_type_str()`` --> :func:`ansible.module_utils.common.validation.check_type_str`
|
||||
- ``_count_terms()`` --> :func:`ansible.module_utils.common.validation.count_terms`
|
||||
- ``_get_wanted_type()``
|
||||
- ``_handle_aliases()``
|
||||
- ``_handle_no_log_values()``
|
||||
- ``_handle_options()``
|
||||
- ``_set_defaults()``
|
||||
- ``_set_fallbacks()``
|
||||
|
||||
Modules or plugins using these private methods should use the public functions in :mod:`ansible.module_utils.common.validation` or :meth:`ArgumentSpecValidator.validate() <ansible.module_utils.common.arg_spec.ArgumentSpecValidator.validate>` if no public function was listed above.
|
||||
|
||||
|
||||
Changes to :mod:`ansible.module_utils.common.parameters`
|
||||
--------------------------------------------------------
|
||||
|
||||
The following functions in :mod:`ansible.module_utils.common.parameters` are now private and should not be used directly. Use :meth:`ArgumentSpecValidator.validate() <ansible.module_utils.common.arg_spec.ArgumentSpecValidator.validate>` instead.
|
||||
|
||||
- ``list_no_log_values``
|
||||
- ``list_deprecations``
|
||||
- ``handle_aliases``
|
||||
|
||||
|
||||
Other
|
||||
======
|
||||
|
||||
* **Upgrading**: If upgrading from ``ansible < 2.10`` or from ``ansible-base`` and using pip, you must ``pip uninstall ansible`` or ``pip uninstall ansible-base`` before installing ``ansible-core`` to avoid conflicts.
|
||||
* Python 3.8 on the controller node is a soft requirement for this release. ``ansible-core`` 2.11 still works with the same versions of Python that ``ansible-base`` 2.10 worked with, however 2.11 emits a warning when running on a controller node with a Python version less than 3.8. This warning can be disabled by setting ``ANSIBLE_CONTROLLER_PYTHON_WARNING=False`` in your environment. ``ansible-core`` 2.12 will require Python 3.8 or greater.
|
||||
* The configuration system now validates the ``choices`` field, so any settings that violate it and were ignored in 2.10 cause an error in 2.11. For example, `ANSIBLE_COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH=0` now causes an error (valid choices are ``ignore``, ``warn`` or ``error``).
|
||||
* The configuration system now validates the ``choices`` field, so any settings that violate it and were ignored in 2.10 cause an error in 2.11. For example, ``ANSIBLE_COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH=0`` now causes an error (valid choices are ``ignore``, ``warn`` or ``error``).
|
||||
* The ``ansible-galaxy`` command now uses ``resolvelib`` for resolving dependencies. In most cases this should not make a user-facing difference beyond being more performant, but we note it here for posterity and completeness.
|
||||
* If you import Python ``module_utils`` into any modules you maintain, you may now mark the import as optional during the module payload build by wrapping the ``import`` statement in a ``try`` or ``if`` block. This allows modules to use ``module_utils`` that may not be present in all versions of Ansible or a collection, and to perform arbitrary recovery or fallback actions during module runtime.
|
||||
|
||||
|
||||
Deprecated
|
||||
==========
|
||||
|
||||
No notable changes
|
||||
|
||||
|
||||
Modules
|
||||
=======
|
||||
|
||||
|
|
|
@ -25,3 +25,50 @@ To use this functionality, include ``import ansible.module_utils.basic`` in your
|
|||
|
||||
.. automodule:: ansible.module_utils.basic
|
||||
:members:
|
||||
|
||||
|
||||
Argument Spec
|
||||
---------------------
|
||||
|
||||
Classes and functions for validating parameters against an argument spec.
|
||||
|
||||
ArgumentSpecValidator
|
||||
=====================
|
||||
|
||||
.. autoclass:: ansible.module_utils.common.arg_spec.ArgumentSpecValidator
|
||||
:members:
|
||||
|
||||
ValidationResult
|
||||
================
|
||||
|
||||
.. autoclass:: ansible.module_utils.common.arg_spec.ValidationResult
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:private-members: _no_log_values # This only works in sphinx >= 3.2. Otherwise it shows all private members with doc strings.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
.. automodule:: ansible.module_utils.common.parameters
|
||||
:members:
|
||||
|
||||
.. py:data:: DEFAULT_TYPE_VALIDATORS
|
||||
|
||||
:class:`dict` of type names, such as ``'str'``, and the default function
|
||||
used to check that type, :func:`~ansible.module_utils.common.validation.check_type_str` in this case.
|
||||
|
||||
Validation
|
||||
==========
|
||||
|
||||
Standalone functions for validating various parameter types.
|
||||
|
||||
.. automodule:: ansible.module_utils.common.validation
|
||||
:members:
|
||||
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
.. automodule:: ansible.module_utils.errors
|
||||
:members:
|
||||
:member-order: bysource
|
||||
|
|
|
@ -50,29 +50,45 @@ from ansible.module_utils.errors import (
|
|||
class ValidationResult:
|
||||
"""Result of argument spec validation.
|
||||
|
||||
:param parameters: Terms to be validated and coerced to the correct type.
|
||||
:type parameters: dict
|
||||
|
||||
This is the object returned by :func:`ArgumentSpecValidator.validate()
|
||||
<ansible.module_utils.common.arg_spec.ArgumentSpecValidator.validate()>`
|
||||
containing the validated parameters and any errors.
|
||||
"""
|
||||
|
||||
def __init__(self, parameters):
|
||||
"""
|
||||
:arg parameters: Terms to be validated and coerced to the correct type.
|
||||
:type parameters: dict
|
||||
"""
|
||||
self._no_log_values = set()
|
||||
""":class:`set` of values marked as ``no_log`` in the argument spec. This
|
||||
is a temporary holding place for these values and may move in the future.
|
||||
"""
|
||||
|
||||
self._unsupported_parameters = set()
|
||||
self._validated_parameters = deepcopy(parameters)
|
||||
self._deprecations = []
|
||||
self._warnings = []
|
||||
self.errors = AnsibleValidationErrorMultiple()
|
||||
"""
|
||||
:class:`~ansible.module_utils.errors.AnsibleValidationErrorMultiple` containing all
|
||||
:class:`~ansible.module_utils.errors.AnsibleValidationError` objects if there were
|
||||
any failures during validation.
|
||||
"""
|
||||
|
||||
@property
|
||||
def validated_parameters(self):
|
||||
"""Validated and coerced parameters."""
|
||||
return self._validated_parameters
|
||||
|
||||
@property
|
||||
def unsupported_parameters(self):
|
||||
""":class:`set` of unsupported parameter names."""
|
||||
return self._unsupported_parameters
|
||||
|
||||
@property
|
||||
def error_messages(self):
|
||||
""":class:`list` of all error messages from each exception in :attr:`errors`."""
|
||||
return self.errors.messages
|
||||
|
||||
|
||||
|
@ -80,30 +96,7 @@ class ArgumentSpecValidator:
|
|||
"""Argument spec validation class
|
||||
|
||||
Creates a validator based on the ``argument_spec`` that can be used to
|
||||
validate a number of parameters using the ``validate()`` method.
|
||||
|
||||
:param argument_spec: Specification of valid parameters and their type. May
|
||||
include nested argument specs.
|
||||
:type argument_spec: dict
|
||||
|
||||
:param mutually_exclusive: List or list of lists of terms that should not
|
||||
be provided together.
|
||||
:type mutually_exclusive: list, optional
|
||||
|
||||
:param required_together: List of lists of terms that are required together.
|
||||
:type required_together: list, optional
|
||||
|
||||
:param required_one_of: List of lists of terms, one of which in each list
|
||||
is required.
|
||||
:type required_one_of: list, optional
|
||||
|
||||
:param required_if: List of lists of ``[parameter, value, [parameters]]`` where
|
||||
one of [parameters] is required if ``parameter`` == ``value``.
|
||||
:type required_if: list, optional
|
||||
|
||||
:param required_by: Dictionary of parameter names that contain a list of
|
||||
parameters required by each key in the dictionary.
|
||||
:type required_by: dict, optional
|
||||
validate a number of parameters using the :meth:`validate` method.
|
||||
"""
|
||||
|
||||
def __init__(self, argument_spec,
|
||||
|
@ -114,6 +107,31 @@ class ArgumentSpecValidator:
|
|||
required_by=None,
|
||||
):
|
||||
|
||||
"""
|
||||
:arg argument_spec: Specification of valid parameters and their type. May
|
||||
include nested argument specs.
|
||||
:type argument_spec: dict[str, dict]
|
||||
|
||||
:kwarg mutually_exclusive: List or list of lists of terms that should not
|
||||
be provided together.
|
||||
:type mutually_exclusive: list[str] or list[list[str]]
|
||||
|
||||
:kwarg required_together: List of lists of terms that are required together.
|
||||
:type required_together: list[list[str]]
|
||||
|
||||
:kwarg required_one_of: List of lists of terms, one of which in each list
|
||||
is required.
|
||||
:type required_one_of: list[list[str]]
|
||||
|
||||
:kwarg required_if: List of lists of ``[parameter, value, [parameters]]`` where
|
||||
one of ``[parameters]`` is required if ``parameter == value``.
|
||||
:type required_if: list
|
||||
|
||||
:kwarg required_by: Dictionary of parameter names that contain a list of
|
||||
parameters required by each key in the dictionary.
|
||||
:type required_by: dict[str, list[str]]
|
||||
"""
|
||||
|
||||
self._mutually_exclusive = mutually_exclusive
|
||||
self._required_together = required_together
|
||||
self._required_one_of = required_one_of
|
||||
|
@ -130,30 +148,37 @@ class ArgumentSpecValidator:
|
|||
self._valid_parameter_names.update([key])
|
||||
|
||||
def validate(self, parameters, *args, **kwargs):
|
||||
"""Validate module parameters against argument spec. Returns a
|
||||
ValidationResult object.
|
||||
"""Validate ``parameters`` against argument spec.
|
||||
|
||||
Error messages in the ValidationResult may contain no_log values and should be
|
||||
sanitized before logging or displaying.
|
||||
Error messages in the :class:`ValidationResult` may contain no_log values and should be
|
||||
sanitized with :func:`~ansible.module_utils.common.parameters.sanitize_keys` before logging or displaying.
|
||||
|
||||
:Example:
|
||||
:arg parameters: Parameters to validate against the argument spec
|
||||
:type parameters: dict[str, dict]
|
||||
|
||||
validator = ArgumentSpecValidator(argument_spec)
|
||||
result = validator.validate(parameters)
|
||||
:return: :class:`ValidationResult` containing validated parameters.
|
||||
|
||||
if result.error_messages:
|
||||
sys.exit("Validation failed: {0}".format(", ".join(result.error_messages))
|
||||
:Simple Example:
|
||||
|
||||
valid_params = result.validated_parameters
|
||||
.. code-block:: text
|
||||
|
||||
:param argument_spec: Specification of parameters, type, and valid values
|
||||
:type argument_spec: dict
|
||||
argument_spec = {
|
||||
'name': {'type': 'str'},
|
||||
'age': {'type': 'int'},
|
||||
}
|
||||
|
||||
:param parameters: Parameters provided to the role
|
||||
:type parameters: dict
|
||||
parameters = {
|
||||
'name': 'bo',
|
||||
'age': '42',
|
||||
}
|
||||
|
||||
:return: Object containing validated parameters.
|
||||
:rtype: ValidationResult
|
||||
validator = ArgumentSpecValidator(argument_spec)
|
||||
result = validator.validate(parameters)
|
||||
|
||||
if result.error_messages:
|
||||
sys.exit("Validation failed: {0}".format(", ".join(result.error_messages))
|
||||
|
||||
valid_params = result.validated_parameters
|
||||
"""
|
||||
|
||||
result = ValidationResult(parameters)
|
||||
|
@ -238,6 +263,12 @@ class ArgumentSpecValidator:
|
|||
|
||||
|
||||
class ModuleArgumentSpecValidator(ArgumentSpecValidator):
|
||||
"""Argument spec validation class used by :class:`AnsibleModule`.
|
||||
|
||||
This is not meant to be used outside of :class:`AnsibleModule`. Use
|
||||
:class:`ArgumentSpecValidator` instead.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ModuleArgumentSpecValidator, self).__init__(*args, **kwargs)
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ def _get_type_validator(wanted):
|
|||
of the wanted type.
|
||||
"""
|
||||
|
||||
# Use one our our builtin validators.
|
||||
# Use one of our builtin validators.
|
||||
if not callable(wanted):
|
||||
if wanted is None:
|
||||
# Default type for parameters
|
||||
|
@ -249,9 +249,18 @@ def _list_deprecations(argument_spec, parameters, prefix=''):
|
|||
:arg parameters: Dictionary of parameters
|
||||
|
||||
:returns: List of dictionaries containing a message and version in which
|
||||
the deprecated parameter will be removed, or an empty list::
|
||||
the deprecated parameter will be removed, or an empty list.
|
||||
|
||||
[{'msg': "Param 'deptest' is deprecated. See the module docs for more information", 'version': '2.9'}]
|
||||
:Example return:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
[
|
||||
{
|
||||
'msg': "Param 'deptest' is deprecated. See the module docs for more information",
|
||||
'version': '2.9'
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
||||
deprecations = []
|
||||
|
@ -293,9 +302,7 @@ def _list_no_log_values(argument_spec, params):
|
|||
:arg argument_spec: An argument spec dictionary
|
||||
:arg params: Dictionary of all parameters
|
||||
|
||||
:returns: Set of strings that should be hidden from output::
|
||||
|
||||
{'secret_dict_value', 'secret_list_item_one', 'secret_list_item_two', 'secret_string'}
|
||||
:returns: :class:`set` of strings that should be hidden from output:
|
||||
"""
|
||||
|
||||
no_log_values = set()
|
||||
|
@ -374,10 +381,13 @@ def _remove_values_conditions(value, no_log_strings, deferred_removals):
|
|||
a container type. The format of each entry is a 2-tuple where the first
|
||||
element is the ``value`` parameter and the second value is a new
|
||||
container to copy the elements of ``value`` into once iterated.
|
||||
|
||||
:returns: if ``value`` is a scalar, returns ``value`` with two exceptions:
|
||||
|
||||
1. :class:`~datetime.datetime` objects which are changed into a string representation.
|
||||
2. objects which are in no_log_strings are replaced with a placeholder
|
||||
so that no sensitive data is leaked.
|
||||
2. objects which are in ``no_log_strings`` are replaced with a placeholder
|
||||
so that no sensitive data is leaked.
|
||||
|
||||
If ``value`` is a container type, returns a new empty container.
|
||||
|
||||
``deferred_removals`` is added to as a side-effect of this function.
|
||||
|
@ -458,13 +468,13 @@ def _set_defaults(argument_spec, parameters, set_default=True):
|
|||
|
||||
Modifies parameters directly.
|
||||
|
||||
:param argument_spec: Argument spec
|
||||
:arg argument_spec: Argument spec
|
||||
:type argument_spec: dict
|
||||
|
||||
:param parameters: Parameters to evaluate
|
||||
:arg parameters: Parameters to evaluate
|
||||
:type parameters: dict
|
||||
|
||||
:param set_default: Whether or not to set the default values
|
||||
:kwarg set_default: Whether or not to set the default values
|
||||
:type set_default: bool
|
||||
|
||||
:returns: Set of strings that should not be logged.
|
||||
|
@ -491,7 +501,7 @@ def _set_defaults(argument_spec, parameters, set_default=True):
|
|||
|
||||
|
||||
def _sanitize_keys_conditions(value, no_log_strings, ignore_keys, deferred_removals):
|
||||
""" Helper method to sanitize_keys() to build deferred_removals and avoid deep recursion. """
|
||||
""" Helper method to :func:`sanitize_keys` to build ``deferred_removals`` and avoid deep recursion. """
|
||||
if isinstance(value, (text_type, binary_type)):
|
||||
return value
|
||||
|
||||
|
@ -564,16 +574,16 @@ def _validate_argument_types(argument_spec, parameters, prefix='', options_conte
|
|||
functions are returned. If any parameter fails to validate, it will not
|
||||
be in the returned parameters.
|
||||
|
||||
:param argument_spec: Argument spec
|
||||
:arg argument_spec: Argument spec
|
||||
:type argument_spec: dict
|
||||
|
||||
:param parameters: Parameters
|
||||
:arg parameters: Parameters
|
||||
:type parameters: dict
|
||||
|
||||
:param prefix: Name of the parent key that contains the spec. Used in the error message
|
||||
:kwarg prefix: Name of the parent key that contains the spec. Used in the error message
|
||||
:type prefix: str
|
||||
|
||||
:param options_context: List of contexts?
|
||||
:kwarg options_context: List of contexts?
|
||||
:type options_context: list
|
||||
|
||||
:returns: Two item tuple containing validated and coerced parameters
|
||||
|
@ -680,7 +690,10 @@ def _validate_argument_values(argument_spec, parameters, options_context=None, e
|
|||
|
||||
|
||||
def _validate_sub_spec(argument_spec, parameters, prefix='', options_context=None, errors=None, no_log_values=None, unsupported_parameters=None):
|
||||
"""Validate sub argument spec. This function is recursive."""
|
||||
"""Validate sub argument spec.
|
||||
|
||||
This function is recursive.
|
||||
"""
|
||||
|
||||
if options_context is None:
|
||||
options_context = []
|
||||
|
@ -811,15 +824,15 @@ def set_fallbacks(argument_spec, parameters):
|
|||
|
||||
|
||||
def sanitize_keys(obj, no_log_strings, ignore_keys=frozenset()):
|
||||
""" Sanitize the keys in a container object by removing no_log values from key names.
|
||||
"""Sanitize the keys in a container object by removing ``no_log`` values from key names.
|
||||
|
||||
This is a companion function to the `remove_values()` function. Similar to that function,
|
||||
we make use of deferred_removals to avoid hitting maximum recursion depth in cases of
|
||||
This is a companion function to the :func:`remove_values` function. Similar to that function,
|
||||
we make use of ``deferred_removals`` to avoid hitting maximum recursion depth in cases of
|
||||
large data structures.
|
||||
|
||||
:param obj: The container object to sanitize. Non-container objects are returned unmodified.
|
||||
:param no_log_strings: A set of string values we do not want logged.
|
||||
:param ignore_keys: A set of string values of keys to not sanitize.
|
||||
:arg obj: The container object to sanitize. Non-container objects are returned unmodified.
|
||||
:arg no_log_strings: A set of string values we do not want logged.
|
||||
:kwarg ignore_keys: A set of string values of keys to not sanitize.
|
||||
|
||||
:returns: An object with sanitized keys.
|
||||
"""
|
||||
|
@ -855,12 +868,13 @@ def sanitize_keys(obj, no_log_strings, ignore_keys=frozenset()):
|
|||
|
||||
|
||||
def remove_values(value, no_log_strings):
|
||||
""" Remove strings in no_log_strings from value. If value is a container
|
||||
type, then remove a lot more.
|
||||
"""Remove strings in ``no_log_strings`` from value.
|
||||
|
||||
Use of deferred_removals exists, rather than a pure recursive solution,
|
||||
If value is a container type, then remove a lot more.
|
||||
|
||||
Use of ``deferred_removals`` exists, rather than a pure recursive solution,
|
||||
because of the potential to hit the maximum recursion depth when dealing with
|
||||
large amounts of data (see issue #24560).
|
||||
large amounts of data (see `issue #24560 <https://github.com/ansible/ansible/issues/24560>`_).
|
||||
"""
|
||||
|
||||
deferred_removals = deque()
|
||||
|
|
|
@ -76,7 +76,7 @@ def check_mutually_exclusive(terms, parameters, options_context=None):
|
|||
:arg terms: List of mutually exclusive parameters
|
||||
:arg parameters: Dictionary of parameters
|
||||
|
||||
:returns: Empty list or raises TypeError if the check fails.
|
||||
:returns: Empty list or raises :class:`TypeError` if the check fails.
|
||||
"""
|
||||
|
||||
results = []
|
||||
|
@ -107,8 +107,10 @@ def check_required_one_of(terms, parameters, options_context=None):
|
|||
:arg terms: List of lists of terms to check. For each list of terms, at
|
||||
least one is required.
|
||||
:arg parameters: Dictionary of parameters
|
||||
:kwarg options_context: List of strings of parent key names if ``terms`` are
|
||||
in a sub spec.
|
||||
|
||||
:returns: Empty list or raises TypeError if the check fails.
|
||||
:returns: Empty list or raises :class:`TypeError` if the check fails.
|
||||
"""
|
||||
|
||||
results = []
|
||||
|
@ -132,16 +134,16 @@ def check_required_one_of(terms, parameters, options_context=None):
|
|||
|
||||
def check_required_together(terms, parameters, options_context=None):
|
||||
"""Check each list of terms to ensure every parameter in each list exists
|
||||
in the given parameters
|
||||
in the given parameters.
|
||||
|
||||
Accepts a list of lists or tuples
|
||||
Accepts a list of lists or tuples.
|
||||
|
||||
:arg terms: List of lists of terms to check. Each list should include
|
||||
parameters that are all required when at least one is specified
|
||||
in the parameters.
|
||||
:arg parameters: Dictionary of parameters
|
||||
|
||||
:returns: Empty list or raises TypeError if the check fails.
|
||||
:returns: Empty list or raises :class:`TypeError` if the check fails.
|
||||
"""
|
||||
|
||||
results = []
|
||||
|
@ -166,14 +168,14 @@ def check_required_together(terms, parameters, options_context=None):
|
|||
|
||||
def check_required_by(requirements, parameters, options_context=None):
|
||||
"""For each key in requirements, check the corresponding list to see if they
|
||||
exist in parameters
|
||||
exist in parameters.
|
||||
|
||||
Accepts a single string or list of values for each key
|
||||
Accepts a single string or list of values for each key.
|
||||
|
||||
:arg requirements: Dictionary of requirements
|
||||
:arg parameters: Dictionary of parameters
|
||||
|
||||
:returns: Empty dictionary or raises TypeError if the
|
||||
:returns: Empty dictionary or raises :class:`TypeError` if the
|
||||
"""
|
||||
|
||||
result = {}
|
||||
|
@ -203,16 +205,16 @@ def check_required_by(requirements, parameters, options_context=None):
|
|||
|
||||
|
||||
def check_required_arguments(argument_spec, parameters, options_context=None):
|
||||
"""Check all paramaters in argument_spec and return a list of parameters
|
||||
that are required but not present in parameters
|
||||
"""Check all parameters in argument_spec and return a list of parameters
|
||||
that are required but not present in parameters.
|
||||
|
||||
Raises TypeError if the check fails
|
||||
Raises :class:`TypeError` if the check fails
|
||||
|
||||
:arg argument_spec: Argument spec dicitionary containing all parameters
|
||||
:arg argument_spec: Argument spec dictionary containing all parameters
|
||||
and their specification
|
||||
:arg module_paramaters: Dictionary of parameters
|
||||
:arg parameters: Dictionary of parameters
|
||||
|
||||
:returns: Empty list or raises TypeError if the check fails.
|
||||
:returns: Empty list or raises :class:`TypeError` if the check fails.
|
||||
"""
|
||||
|
||||
missing = []
|
||||
|
@ -236,32 +238,38 @@ def check_required_arguments(argument_spec, parameters, options_context=None):
|
|||
def check_required_if(requirements, parameters, options_context=None):
|
||||
"""Check parameters that are conditionally required
|
||||
|
||||
Raises TypeError if the check fails
|
||||
Raises :class:`TypeError` if the check fails
|
||||
|
||||
:arg requirements: List of lists specifying a parameter, value, parameters
|
||||
required when the given parameter is the specified value, and optionally
|
||||
a boolean indicating any or all parameters are required.
|
||||
|
||||
Example:
|
||||
required_if=[
|
||||
['state', 'present', ('path',), True],
|
||||
['someint', 99, ('bool_param', 'string_param')],
|
||||
]
|
||||
:Example:
|
||||
|
||||
:arg module_paramaters: Dictionary of parameters
|
||||
.. code-block:: python
|
||||
|
||||
:returns: Empty list or raises TypeError if the check fails.
|
||||
required_if=[
|
||||
['state', 'present', ('path',), True],
|
||||
['someint', 99, ('bool_param', 'string_param')],
|
||||
]
|
||||
|
||||
:arg parameters: Dictionary of parameters
|
||||
|
||||
:returns: Empty list or raises :class:`TypeError` if the check fails.
|
||||
The results attribute of the exception contains a list of dictionaries.
|
||||
Each dictionary is the result of evaluting each item in requirements.
|
||||
Each dictionary is the result of evaluating each item in requirements.
|
||||
Each return dictionary contains the following keys:
|
||||
|
||||
:key missing: List of parameters that are required but missing
|
||||
:key requires: 'any' or 'all'
|
||||
:key paramater: Parameter name that has the requirement
|
||||
:key value: Original value of the paramater
|
||||
:key parameter: Parameter name that has the requirement
|
||||
:key value: Original value of the parameter
|
||||
:key requirements: Original required parameters
|
||||
|
||||
Example:
|
||||
:Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
[
|
||||
{
|
||||
'parameter': 'someint',
|
||||
|
@ -321,13 +329,12 @@ def check_missing_parameters(parameters, required_parameters=None):
|
|||
"""This is for checking for required params when we can not check via
|
||||
argspec because we need more information than is simply given in the argspec.
|
||||
|
||||
Raises TypeError if any required parameters are missing
|
||||
Raises :class:`TypeError` if any required parameters are missing
|
||||
|
||||
:arg module_paramaters: Dictionary of parameters
|
||||
:arg required_parameters: List of parameters to look for in the given module
|
||||
parameters
|
||||
:arg parameters: Dictionary of parameters
|
||||
:arg required_parameters: List of parameters to look for in the given parameters.
|
||||
|
||||
:returns: Empty list or raises TypeError if the check fails.
|
||||
:returns: Empty list or raises :class:`TypeError` if the check fails.
|
||||
"""
|
||||
missing_params = []
|
||||
if required_parameters is None:
|
||||
|
@ -374,13 +381,13 @@ def check_type_str(value, allow_conversion=True, param=None, prefix=''):
|
|||
def check_type_list(value):
|
||||
"""Verify that the value is a list or convert to a list
|
||||
|
||||
A comma separated string will be split into a list. Rases a TypeError if
|
||||
unable to convert to a list.
|
||||
A comma separated string will be split into a list. Raises a :class:`TypeError`
|
||||
if unable to convert to a list.
|
||||
|
||||
:arg value: Value to validate or convert to a list
|
||||
|
||||
:returns: Original value if it is already a list, single item list if a
|
||||
float, int or string without commas, or a multi-item list if a
|
||||
float, int, or string without commas, or a multi-item list if a
|
||||
comma-delimited string.
|
||||
"""
|
||||
if isinstance(value, list):
|
||||
|
@ -397,9 +404,9 @@ def check_type_list(value):
|
|||
def check_type_dict(value):
|
||||
"""Verify that value is a dict or convert it to a dict and return it.
|
||||
|
||||
Raises TypeError if unable to convert to a dict
|
||||
Raises :class:`TypeError` if unable to convert to a dict
|
||||
|
||||
:arg value: Dict or string to convert to a dict. Accepts 'k1=v2, k2=v2'.
|
||||
:arg value: Dict or string to convert to a dict. Accepts ``k1=v2, k2=v2``.
|
||||
|
||||
:returns: value converted to a dictionary
|
||||
"""
|
||||
|
@ -451,7 +458,7 @@ def check_type_dict(value):
|
|||
def check_type_bool(value):
|
||||
"""Verify that the value is a bool or convert it to a bool and return it.
|
||||
|
||||
Raises TypeError if unable to convert to a bool
|
||||
Raises :class:`TypeError` if unable to convert to a bool
|
||||
|
||||
:arg value: String, int, or float to convert to bool. Valid booleans include:
|
||||
'1', 'on', 1, '0', 0, 'n', 'f', 'false', 'true', 'y', 't', 'yes', 'no', 'off'
|
||||
|
@ -471,11 +478,11 @@ def check_type_int(value):
|
|||
"""Verify that the value is an integer and return it or convert the value
|
||||
to an integer and return it
|
||||
|
||||
Raises TypeError if unable to convert to an int
|
||||
Raises :class:`TypeError` if unable to convert to an int
|
||||
|
||||
:arg value: String or int to convert of verify
|
||||
|
||||
:return: Int of given value
|
||||
:return: int of given value
|
||||
"""
|
||||
if isinstance(value, integer_types):
|
||||
return value
|
||||
|
@ -492,11 +499,11 @@ def check_type_int(value):
|
|||
def check_type_float(value):
|
||||
"""Verify that value is a float or convert it to a float and return it
|
||||
|
||||
Raises TypeError if unable to convert to a float
|
||||
Raises :class:`TypeError` if unable to convert to a float
|
||||
|
||||
:arg value: Float, int, str, or bytes to verify or convert and return.
|
||||
:arg value: float, int, str, or bytes to verify or convert and return.
|
||||
|
||||
:returns: Float of given value.
|
||||
:returns: float of given value.
|
||||
"""
|
||||
if isinstance(value, float):
|
||||
return value
|
||||
|
@ -519,15 +526,14 @@ def check_type_path(value,):
|
|||
|
||||
|
||||
def check_type_raw(value):
|
||||
"""Returns the raw value
|
||||
"""
|
||||
"""Returns the raw value"""
|
||||
return value
|
||||
|
||||
|
||||
def check_type_bytes(value):
|
||||
"""Convert a human-readable string value to bytes
|
||||
|
||||
Raises TypeError if unable to covert the value
|
||||
Raises :class:`TypeError` if unable to covert the value
|
||||
"""
|
||||
try:
|
||||
return human_to_bytes(value)
|
||||
|
@ -538,9 +544,9 @@ def check_type_bytes(value):
|
|||
def check_type_bits(value):
|
||||
"""Convert a human-readable string bits value to bits in integer.
|
||||
|
||||
Example: check_type_bits('1Mb') returns integer 1048576.
|
||||
Example: ``check_type_bits('1Mb')`` returns integer 1048576.
|
||||
|
||||
Raises TypeError if unable to covert the value.
|
||||
Raises :class:`TypeError` if unable to covert the value.
|
||||
"""
|
||||
try:
|
||||
return human_to_bytes(value, isbits=True)
|
||||
|
@ -552,7 +558,7 @@ def check_type_jsonarg(value):
|
|||
"""Return a jsonified string. Sometimes the controller turns a json string
|
||||
into a dict/list so transform it back into json here
|
||||
|
||||
Raises TypeError if unable to covert the value
|
||||
Raises :class:`TypeError` if unable to covert the value
|
||||
|
||||
"""
|
||||
if isinstance(value, (text_type, binary_type)):
|
||||
|
|
|
@ -16,9 +16,11 @@ class AnsibleValidationError(Exception):
|
|||
def __init__(self, message):
|
||||
super(AnsibleValidationError, self).__init__(message)
|
||||
self.error_message = message
|
||||
"""The error message passed in when the exception was raised."""
|
||||
|
||||
@property
|
||||
def msg(self):
|
||||
"""The error message passed in when the exception was raised."""
|
||||
return self.args[0]
|
||||
|
||||
|
||||
|
@ -27,6 +29,7 @@ class AnsibleValidationErrorMultiple(AnsibleValidationError):
|
|||
|
||||
def __init__(self, errors=None):
|
||||
self.errors = errors[:] if errors else []
|
||||
""":class:`list` of :class:`AnsibleValidationError` objects"""
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.errors[key]
|
||||
|
@ -39,16 +42,24 @@ class AnsibleValidationErrorMultiple(AnsibleValidationError):
|
|||
|
||||
@property
|
||||
def msg(self):
|
||||
"""The first message from the first error in ``errors``."""
|
||||
return self.errors[0].args[0]
|
||||
|
||||
@property
|
||||
def messages(self):
|
||||
""":class:`list` of each error message in ``errors``."""
|
||||
return [err.msg for err in self.errors]
|
||||
|
||||
def append(self, error):
|
||||
"""Append a new error to ``self.errors``.
|
||||
|
||||
Only :class:`AnsibleValidationError` should be added.
|
||||
"""
|
||||
|
||||
self.errors.append(error)
|
||||
|
||||
def extend(self, errors):
|
||||
"""Append each item in ``errors`` to ``self.errors``. Only :class:`AnsibleValidationError` should be added."""
|
||||
self.errors.extend(errors)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue