diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 16:04:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 16:04:21 +0000 |
commit | 8a754e0858d922e955e71b253c139e071ecec432 (patch) | |
tree | 527d16e74bfd1840c85efd675fdecad056c54107 /lib/ansible/plugins/test | |
parent | Initial commit. (diff) | |
download | ansible-core-upstream/2.14.3.tar.xz ansible-core-upstream/2.14.3.zip |
Adding upstream version 2.14.3.upstream/2.14.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/ansible/plugins/test')
52 files changed, 1709 insertions, 0 deletions
diff --git a/lib/ansible/plugins/test/__init__.py b/lib/ansible/plugins/test/__init__.py new file mode 100644 index 0000000..1400316 --- /dev/null +++ b/lib/ansible/plugins/test/__init__.py @@ -0,0 +1,13 @@ +# (c) Ansible Project +# 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) +__metaclass__ = type + +from ansible.plugins import AnsibleJinja2Plugin + + +class AnsibleJinja2Test(AnsibleJinja2Plugin): + + def _no_options(self, *args, **kwargs): + raise NotImplementedError("Jinaj2 test plugins do not support option functions, they use direct arguments instead.") diff --git a/lib/ansible/plugins/test/abs.yml b/lib/ansible/plugins/test/abs.yml new file mode 100644 index 0000000..46f7f70 --- /dev/null +++ b/lib/ansible/plugins/test/abs.yml @@ -0,0 +1,23 @@ +DOCUMENTATION: + name: abs + author: Ansible Core + version_added: "2.5" + short_description: is the path absolute + aliases: [is_abs] + description: + - Check if the provided path is absolute, not relative. + - An absolute path expresses the location of a filesystem object starting at the filesystem root and requires no context. + - A relative path does not start at the filesystem root and requires a 'current' directory as a context to resolve. + options: + _input: + description: A path. + type: path + +EXAMPLES: | + is_path_absolute: "{{ '/etc/hosts' is abs }}}" + relative_paths: "{{ all_paths | reject('abs') }}" + +RETURN: + _value: + description: Returns C(True) if the path is absolute, C(False) if it is relative. + type: boolean diff --git a/lib/ansible/plugins/test/all.yml b/lib/ansible/plugins/test/all.yml new file mode 100644 index 0000000..e227d6e --- /dev/null +++ b/lib/ansible/plugins/test/all.yml @@ -0,0 +1,23 @@ +DOCUMENTATION: + name: all + author: Ansible Core + version_added: "2.4" + short_description: are all conditions in a list true + description: + - This test checks each condition in a list for truthiness. + - Same as the C(all) Python function. + options: + _input: + description: List of conditions, each can be a boolean or conditional expression that results in a boolean value. + type: list + elements: raw + required: True +EXAMPLES: | + varexpression: "{{ 3 == 3 }}" + # are all statements true? + {{ [true, booleanvar, varexpression] is all }} + +RETURN: + _value: + description: Returns C(True) if all elements of the list were True, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/any.yml b/lib/ansible/plugins/test/any.yml new file mode 100644 index 0000000..0ce9e48 --- /dev/null +++ b/lib/ansible/plugins/test/any.yml @@ -0,0 +1,23 @@ +DOCUMENTATION: + name: any + author: Ansible Core + version_added: "2.4" + short_description: is any conditions in a list true + description: + - This test checks each condition in a list for truthiness. + - Same as the C(any) Python function. + options: + _input: + description: List of conditions, each can be a boolean or conditional expression that results in a boolean value. + type: list + elements: raw + required: True +EXAMPLES: | + varexpression: "{{ 3 == 3 }}" + # are all statements true? + {{ [false, booleanvar, varexpression] is any}} + +RETURN: + _value: + description: Returns C(True) if any element of the list was true, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/change.yml b/lib/ansible/plugins/test/change.yml new file mode 100644 index 0000000..1fb1e5e --- /dev/null +++ b/lib/ansible/plugins/test/change.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: changed + author: Ansible Core + version_added: "1.9" + short_description: did the task require changes + aliases: [change] + description: + - Tests if task required changes to complete + - This test checks for the existance of a C(changed) key in the input dictionary and that it is C(True) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is changed }} + +RETURN: + _value: + description: Returns C(True) if the task was required changes, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/changed.yml b/lib/ansible/plugins/test/changed.yml new file mode 100644 index 0000000..1fb1e5e --- /dev/null +++ b/lib/ansible/plugins/test/changed.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: changed + author: Ansible Core + version_added: "1.9" + short_description: did the task require changes + aliases: [change] + description: + - Tests if task required changes to complete + - This test checks for the existance of a C(changed) key in the input dictionary and that it is C(True) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is changed }} + +RETURN: + _value: + description: Returns C(True) if the task was required changes, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/contains.yml b/lib/ansible/plugins/test/contains.yml new file mode 100644 index 0000000..68741da --- /dev/null +++ b/lib/ansible/plugins/test/contains.yml @@ -0,0 +1,49 @@ +DOCUMENTATION: + name: contains + author: Ansible Core + version_added: "2.4" + short_description: does the list contain this element + description: + - Checks the supplied element against the input list to see if it exists within it. + options: + _input: + description: List of elements to compare. + type: list + elements: raw + required: True + _contained: + description: Element to test for. + type: raw + required: True +EXAMPLES: | + # simple expression + {{ listofthings is contains('this') }} + + # as a selector + - action: module=doessomething + when: lacp_groups|selectattr('interfaces', 'contains', 'em1')|first).master + vars: + lacp_groups: + - master: lacp0 + network: 10.65.100.0/24 + gateway: 10.65.100.1 + dns4: + - 10.65.100.10 + - 10.65.100.11 + interfaces: + - em1 + - em2 + + - master: lacp1 + network: 10.65.120.0/24 + gateway: 10.65.120.1 + dns4: + - 10.65.100.10 + - 10.65.100.11 + interfaces: + - em3 + - em4 +RETURN: + _value: + description: Returns C(True) if the specified element is contained in the supplied sequence, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/core.py b/lib/ansible/plugins/test/core.py new file mode 100644 index 0000000..d9e7e8b --- /dev/null +++ b/lib/ansible/plugins/test/core.py @@ -0,0 +1,287 @@ +# (c) 2012, Jeroen Hoekx <jeroen@hoekx.be> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import re +import operator as py_operator + +from collections.abc import MutableMapping, MutableSequence + +from ansible.module_utils.compat.version import LooseVersion, StrictVersion + +from ansible import errors +from ansible.module_utils._text import to_native, to_text +from ansible.module_utils.parsing.convert_bool import boolean +from ansible.utils.display import Display +from ansible.utils.version import SemanticVersion + +try: + from packaging.version import Version as PEP440Version + HAS_PACKAGING = True +except ImportError: + HAS_PACKAGING = False + +display = Display() + + +def failed(result): + ''' Test if task result yields failed ''' + if not isinstance(result, MutableMapping): + raise errors.AnsibleFilterError("The 'failed' test expects a dictionary") + return result.get('failed', False) + + +def success(result): + ''' Test if task result yields success ''' + return not failed(result) + + +def unreachable(result): + ''' Test if task result yields unreachable ''' + if not isinstance(result, MutableMapping): + raise errors.AnsibleFilterError("The 'unreachable' test expects a dictionary") + return result.get('unreachable', False) + + +def reachable(result): + ''' Test if task result yields reachable ''' + return not unreachable(result) + + +def changed(result): + ''' Test if task result yields changed ''' + if not isinstance(result, MutableMapping): + raise errors.AnsibleFilterError("The 'changed' test expects a dictionary") + if 'changed' not in result: + changed = False + if ( + 'results' in result and # some modules return a 'results' key + isinstance(result['results'], MutableSequence) and + isinstance(result['results'][0], MutableMapping) + ): + for res in result['results']: + if res.get('changed', False): + changed = True + break + else: + changed = result.get('changed', False) + return changed + + +def skipped(result): + ''' Test if task result yields skipped ''' + if not isinstance(result, MutableMapping): + raise errors.AnsibleFilterError("The 'skipped' test expects a dictionary") + return result.get('skipped', False) + + +def started(result): + ''' Test if async task has started ''' + if not isinstance(result, MutableMapping): + raise errors.AnsibleFilterError("The 'started' test expects a dictionary") + if 'started' in result: + # For async tasks, return status + # NOTE: The value of started is 0 or 1, not False or True :-/ + return result.get('started', 0) == 1 + else: + # For non-async tasks, warn user, but return as if started + display.warning("The 'started' test expects an async task, but a non-async task was tested") + return True + + +def finished(result): + ''' Test if async task has finished ''' + if not isinstance(result, MutableMapping): + raise errors.AnsibleFilterError("The 'finished' test expects a dictionary") + if 'finished' in result: + # For async tasks, return status + # NOTE: The value of finished is 0 or 1, not False or True :-/ + return result.get('finished', 0) == 1 + else: + # For non-async tasks, warn user, but return as if finished + display.warning("The 'finished' test expects an async task, but a non-async task was tested") + return True + + +def regex(value='', pattern='', ignorecase=False, multiline=False, match_type='search'): + ''' Expose `re` as a boolean filter using the `search` method by default. + This is likely only useful for `search` and `match` which already + have their own filters. + ''' + # In addition to ensuring the correct type, to_text here will ensure + # _fail_with_undefined_error happens if the value is Undefined + value = to_text(value, errors='surrogate_or_strict') + flags = 0 + if ignorecase: + flags |= re.I + if multiline: + flags |= re.M + _re = re.compile(pattern, flags=flags) + return bool(getattr(_re, match_type, 'search')(value)) + + +def vault_encrypted(value): + """Evaulate whether a variable is a single vault encrypted value + + .. versionadded:: 2.10 + """ + return getattr(value, '__ENCRYPTED__', False) and value.is_encrypted() + + +def match(value, pattern='', ignorecase=False, multiline=False): + ''' Perform a `re.match` returning a boolean ''' + return regex(value, pattern, ignorecase, multiline, 'match') + + +def search(value, pattern='', ignorecase=False, multiline=False): + ''' Perform a `re.search` returning a boolean ''' + return regex(value, pattern, ignorecase, multiline, 'search') + + +def version_compare(value, version, operator='eq', strict=None, version_type=None): + ''' Perform a version comparison on a value ''' + op_map = { + '==': 'eq', '=': 'eq', 'eq': 'eq', + '<': 'lt', 'lt': 'lt', + '<=': 'le', 'le': 'le', + '>': 'gt', 'gt': 'gt', + '>=': 'ge', 'ge': 'ge', + '!=': 'ne', '<>': 'ne', 'ne': 'ne' + } + + type_map = { + 'loose': LooseVersion, + 'strict': StrictVersion, + 'semver': SemanticVersion, + 'semantic': SemanticVersion, + 'pep440': PEP440Version, + } + + if strict is not None and version_type is not None: + raise errors.AnsibleFilterError("Cannot specify both 'strict' and 'version_type'") + + if not value: + raise errors.AnsibleFilterError("Input version value cannot be empty") + + if not version: + raise errors.AnsibleFilterError("Version parameter to compare against cannot be empty") + + if version_type == 'pep440' and not HAS_PACKAGING: + raise errors.AnsibleFilterError("The pep440 version_type requires the Python 'packaging' library") + + Version = LooseVersion + if strict: + Version = StrictVersion + elif version_type: + try: + Version = type_map[version_type] + except KeyError: + raise errors.AnsibleFilterError( + "Invalid version type (%s). Must be one of %s" % (version_type, ', '.join(map(repr, type_map))) + ) + + if operator in op_map: + operator = op_map[operator] + else: + raise errors.AnsibleFilterError( + 'Invalid operator type (%s). Must be one of %s' % (operator, ', '.join(map(repr, op_map))) + ) + + try: + method = getattr(py_operator, operator) + return method(Version(to_text(value)), Version(to_text(version))) + except Exception as e: + raise errors.AnsibleFilterError('Version comparison failed: %s' % to_native(e)) + + +def truthy(value, convert_bool=False): + """Evaluate as value for truthiness using python ``bool`` + + Optionally, attempt to do a conversion to bool from boolean like values + such as ``"false"``, ``"true"``, ``"yes"``, ``"no"``, ``"on"``, ``"off"``, etc. + + .. versionadded:: 2.10 + """ + if convert_bool: + try: + value = boolean(value) + except TypeError: + pass + + return bool(value) + + +def falsy(value, convert_bool=False): + """Evaluate as value for falsiness using python ``bool`` + + Optionally, attempt to do a conversion to bool from boolean like values + such as ``"false"``, ``"true"``, ``"yes"``, ``"no"``, ``"on"``, ``"off"``, etc. + + .. versionadded:: 2.10 + """ + return not truthy(value, convert_bool=convert_bool) + + +class TestModule(object): + ''' Ansible core jinja2 tests ''' + + def tests(self): + return { + # failure testing + 'failed': failed, + 'failure': failed, + 'succeeded': success, + 'success': success, + 'successful': success, + 'reachable': reachable, + 'unreachable': unreachable, + + # changed testing + 'changed': changed, + 'change': changed, + + # skip testing + 'skipped': skipped, + 'skip': skipped, + + # async testing + 'finished': finished, + 'started': started, + + # regex + 'match': match, + 'search': search, + 'regex': regex, + + # version comparison + 'version_compare': version_compare, + 'version': version_compare, + + # lists + 'any': any, + 'all': all, + + # truthiness + 'truthy': truthy, + 'falsy': falsy, + + # vault + 'vault_encrypted': vault_encrypted, + } diff --git a/lib/ansible/plugins/test/directory.yml b/lib/ansible/plugins/test/directory.yml new file mode 100644 index 0000000..5d7fa78 --- /dev/null +++ b/lib/ansible/plugins/test/directory.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: directory + author: Ansible Core + version_added: "2.5" + short_description: does the path resolve to an existing directory + description: + - Check if the provided path maps to an existing directory on the controller's filesystem (localhost). + options: + _input: + description: A path. + type: path + +EXAMPLES: | + vars: + my_etc_hosts_not_a_dir: "{{ '/etc/hosts' is directory}}" + list_of_files: "{{ list_of_paths | reject('directory') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing directory on the filesystem on the controller, c(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/exists.yml b/lib/ansible/plugins/test/exists.yml new file mode 100644 index 0000000..85f9108 --- /dev/null +++ b/lib/ansible/plugins/test/exists.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: exists + author: Ansible Core + version_added: "2.5" + short_description: does the path exist, follow symlinks + description: + - Check if the provided path maps to an existing filesystem object on the controller (localhost). + - Follows symlinks and checks the target of the symlink instead of the link itself, use the C(link) or C(link_exists) tests to check on the link. + options: + _input: + description: a path + type: path + +EXAMPLES: | + vars: + my_etc_hosts_exists: "{{ '/etc/hosts' is exist }}" + list_of_local_files_to_copy_to_remote: "{{ list_of_all_possible_files | select('exists') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing filesystem object on the controller (after following symlinks), C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/failed.yml b/lib/ansible/plugins/test/failed.yml new file mode 100644 index 0000000..b8a9b3e --- /dev/null +++ b/lib/ansible/plugins/test/failed.yml @@ -0,0 +1,23 @@ +DOCUMENTATION: + name: failed + author: Ansible Core + version_added: "1.9" + short_description: did the task fail + aliases: [failure] + description: + - Tests if task finished in failure, opposite of C(succeeded). + - This test checks for the existance of a C(failed) key in the input dictionary and that it is C(True) if present. + - Tasks that get skipped or not executed due to other failures (syntax, templating, unreachable host, etc) do not return a 'failed' status. + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ taskresults is failed }} + +RETURN: + _value: + description: Returns C(True) if the task was failed, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/failure.yml b/lib/ansible/plugins/test/failure.yml new file mode 100644 index 0000000..b8a9b3e --- /dev/null +++ b/lib/ansible/plugins/test/failure.yml @@ -0,0 +1,23 @@ +DOCUMENTATION: + name: failed + author: Ansible Core + version_added: "1.9" + short_description: did the task fail + aliases: [failure] + description: + - Tests if task finished in failure, opposite of C(succeeded). + - This test checks for the existance of a C(failed) key in the input dictionary and that it is C(True) if present. + - Tasks that get skipped or not executed due to other failures (syntax, templating, unreachable host, etc) do not return a 'failed' status. + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ taskresults is failed }} + +RETURN: + _value: + description: Returns C(True) if the task was failed, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/falsy.yml b/lib/ansible/plugins/test/falsy.yml new file mode 100644 index 0000000..49a198f --- /dev/null +++ b/lib/ansible/plugins/test/falsy.yml @@ -0,0 +1,24 @@ +DOCUMENTATION: + name: falsy + author: Ansible Core + version_added: "2.10" + short_description: Pythonic false + description: + - This check is a more Python version of what is 'false'. + - It is the opposite of 'truthy'. + options: + _input: + description: An expression that can be expressed in a boolean context. + type: string + required: True + convert_bool: + description: Attempts to convert the result to a strict Python boolean vs normally acceptable values (C(yes)/C(no), C(on)/C(off), C(0)/C(1), etc). + type: bool + default: false +EXAMPLES: | + thisisfalse: '{{ "any string" is falsy }}' + thisistrue: '{{ "" is falsy }}' +RETURN: + _value: + description: Returns C(False) if the condition is not "Python truthy", C(True) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/file.yml b/lib/ansible/plugins/test/file.yml new file mode 100644 index 0000000..8b79c07 --- /dev/null +++ b/lib/ansible/plugins/test/file.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: file + author: Ansible Core + version_added: "2.5" + short_description: does the path resolve to an existing file + description: + - Check if the provided path maps to an existing file on the controller's filesystem (localhost) + aliases: [is_file] + options: + _input: + description: A path. + type: path + +EXAMPLES: | + vars: + my_etc_hosts_is_a_file: "{{ '/etc/hosts' is file }}" + list_of_files: "{{ list_of_paths | select('file') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing file on the filesystem on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/files.py b/lib/ansible/plugins/test/files.py new file mode 100644 index 0000000..35761a4 --- /dev/null +++ b/lib/ansible/plugins/test/files.py @@ -0,0 +1,48 @@ +# (c) 2015, Ansible, Inc +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from os.path import isdir, isfile, isabs, exists, lexists, islink, samefile, ismount +from ansible import errors + + +class TestModule(object): + ''' Ansible file jinja2 tests ''' + + def tests(self): + return { + # file testing + 'directory': isdir, + 'is_dir': isdir, + 'file': isfile, + 'is_file': isfile, + 'link': islink, + 'is_link': islink, + 'exists': exists, + 'link_exists': lexists, + + # path testing + 'abs': isabs, + 'is_abs': isabs, + 'same_file': samefile, + 'is_same_file': samefile, + 'mount': ismount, + 'is_mount': ismount, + } diff --git a/lib/ansible/plugins/test/finished.yml b/lib/ansible/plugins/test/finished.yml new file mode 100644 index 0000000..b01b132 --- /dev/null +++ b/lib/ansible/plugins/test/finished.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: finished + author: Ansible Core + version_added: "1.9" + short_description: Did async task finish + description: + - Used to test if an async task has finished, it will aslo work with normal tasks but will issue a warning. + - This test checks for the existance of a C(finished) key in the input dictionary and that it is C(1) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (asynctaskpoll is finished}} + +RETURN: + _value: + description: Returns C(True) if the aysnc task has finished, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/is_abs.yml b/lib/ansible/plugins/test/is_abs.yml new file mode 100644 index 0000000..46f7f70 --- /dev/null +++ b/lib/ansible/plugins/test/is_abs.yml @@ -0,0 +1,23 @@ +DOCUMENTATION: + name: abs + author: Ansible Core + version_added: "2.5" + short_description: is the path absolute + aliases: [is_abs] + description: + - Check if the provided path is absolute, not relative. + - An absolute path expresses the location of a filesystem object starting at the filesystem root and requires no context. + - A relative path does not start at the filesystem root and requires a 'current' directory as a context to resolve. + options: + _input: + description: A path. + type: path + +EXAMPLES: | + is_path_absolute: "{{ '/etc/hosts' is abs }}}" + relative_paths: "{{ all_paths | reject('abs') }}" + +RETURN: + _value: + description: Returns C(True) if the path is absolute, C(False) if it is relative. + type: boolean diff --git a/lib/ansible/plugins/test/is_dir.yml b/lib/ansible/plugins/test/is_dir.yml new file mode 100644 index 0000000..5d7fa78 --- /dev/null +++ b/lib/ansible/plugins/test/is_dir.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: directory + author: Ansible Core + version_added: "2.5" + short_description: does the path resolve to an existing directory + description: + - Check if the provided path maps to an existing directory on the controller's filesystem (localhost). + options: + _input: + description: A path. + type: path + +EXAMPLES: | + vars: + my_etc_hosts_not_a_dir: "{{ '/etc/hosts' is directory}}" + list_of_files: "{{ list_of_paths | reject('directory') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing directory on the filesystem on the controller, c(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/is_file.yml b/lib/ansible/plugins/test/is_file.yml new file mode 100644 index 0000000..8b79c07 --- /dev/null +++ b/lib/ansible/plugins/test/is_file.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: file + author: Ansible Core + version_added: "2.5" + short_description: does the path resolve to an existing file + description: + - Check if the provided path maps to an existing file on the controller's filesystem (localhost) + aliases: [is_file] + options: + _input: + description: A path. + type: path + +EXAMPLES: | + vars: + my_etc_hosts_is_a_file: "{{ '/etc/hosts' is file }}" + list_of_files: "{{ list_of_paths | select('file') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing file on the filesystem on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/is_link.yml b/lib/ansible/plugins/test/is_link.yml new file mode 100644 index 0000000..27af41f --- /dev/null +++ b/lib/ansible/plugins/test/is_link.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: link + author: Ansible Core + version_added: "2.5" + short_description: does the path reference existing symbolic link + aliases: [islink] + description: + - Check if the provided path maps to an existing symlink on the controller's filesystem (localhost). + options: + _input: + description: A path. + type: path + +EXAMPLES: | + ismyhostsalink: "{{ '/etc/hosts' is link}}" + list_of_symlinks: "{{ list_of_paths | select('link') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing symlink on the filesystem on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/is_mount.yml b/lib/ansible/plugins/test/is_mount.yml new file mode 100644 index 0000000..23f19b6 --- /dev/null +++ b/lib/ansible/plugins/test/is_mount.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: mount + author: Ansible Core + version_added: "2.5" + short_description: does the path resolve to mount point + description: + - Check if the provided path maps to a filesystem mount point on the controller (localhost). + aliases: [is_mount] + options: + _input: + description: A path. + type: path + +EXAMPLES: | + vars: + ihopefalse: "{{ '/etc/hosts' is mount }}" + normallytrue: "{{ '/tmp' is mount }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to a mount point on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/is_same_file.yml b/lib/ansible/plugins/test/is_same_file.yml new file mode 100644 index 0000000..a10a36a --- /dev/null +++ b/lib/ansible/plugins/test/is_same_file.yml @@ -0,0 +1,24 @@ +DOCUMENTATION: + name: same_file + author: Ansible Core + version_added: "2.5" + short_description: compares two paths to see if they resolve to the same filesystem object + description: Check if the provided paths map to the same location on the controller's filesystem (localhost). + aliases: [is_file] + options: + _input: + description: A path. + type: path + required: true + _path2: + description: Another path. + type: path + required: true + +EXAMPLES: | + amionelevelfromroot: "{{ '/etc/hosts' is same_file('../etc/hosts') }}" + +RETURN: + _value: + description: Returns C(True) if the paths correspond to the same location on the filesystem on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/isnan.yml b/lib/ansible/plugins/test/isnan.yml new file mode 100644 index 0000000..3c1055b --- /dev/null +++ b/lib/ansible/plugins/test/isnan.yml @@ -0,0 +1,20 @@ +DOCUMENTATION: + name: nan + author: Ansible Core + version_added: "2.5" + short_description: is this not a number (NaN) + description: + - Whether the input is a special floating point number called L(not a number, https://en.wikipedia.org/wiki/NaN). + aliases: [is_file] + options: + _input: + description: Possible number representation or string that can be converted into one. + type: raw + required: true +EXAMPLES: | + isnan: "{{ '42' is nan }}" + +RETURN: + _value: + description: Returns C(True) if the input is NaN, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/issubset.yml b/lib/ansible/plugins/test/issubset.yml new file mode 100644 index 0000000..d57d05b --- /dev/null +++ b/lib/ansible/plugins/test/issubset.yml @@ -0,0 +1,28 @@ +DOCUMENTATION: + name: subset + author: Ansible Core + version_added: "2.4" + aliases: [issubset] + short_description: is the list a subset of this other list + description: + - Validate if the first list is a sub set (is included) of the second list. + - Same as the C(all) Python function. + options: + _input: + description: List. + type: list + elements: raw + required: True + _superset: + description: List to test against. + type: list + elements: raw + required: True +EXAMPLES: | + big: [1,2,3,4,5] + sml: [3,4] + issmallinbig: '{{ small is subset(big) }}' +RETURN: + _value: + description: Returns C(True) if the specified list is a subset of the provided list, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/issuperset.yml b/lib/ansible/plugins/test/issuperset.yml new file mode 100644 index 0000000..72be3d5 --- /dev/null +++ b/lib/ansible/plugins/test/issuperset.yml @@ -0,0 +1,28 @@ +DOCUMENTATION: + name: superset + author: Ansible Core + version_added: "2.4" + short_description: is the list a superset of this other list + aliases: [issuperset] + description: + - Validate if the first list is a super set (includes) the second list. + - Same as the C(all) Python function. + options: + _input: + description: List. + type: list + elements: raw + required: True + _subset: + description: List to test against. + type: list + elements: raw + required: True +EXAMPLES: | + big: [1,2,3,4,5] + sml: [3,4] + issmallinbig: '{{ big is superset(small) }}' +RETURN: + _value: + description: Returns C(True) if the specified list is a superset of the provided list, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/link.yml b/lib/ansible/plugins/test/link.yml new file mode 100644 index 0000000..27af41f --- /dev/null +++ b/lib/ansible/plugins/test/link.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: link + author: Ansible Core + version_added: "2.5" + short_description: does the path reference existing symbolic link + aliases: [islink] + description: + - Check if the provided path maps to an existing symlink on the controller's filesystem (localhost). + options: + _input: + description: A path. + type: path + +EXAMPLES: | + ismyhostsalink: "{{ '/etc/hosts' is link}}" + list_of_symlinks: "{{ list_of_paths | select('link') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing symlink on the filesystem on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/link_exists.yml b/lib/ansible/plugins/test/link_exists.yml new file mode 100644 index 0000000..f75a699 --- /dev/null +++ b/lib/ansible/plugins/test/link_exists.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: link_exists + author: Ansible Core + version_added: "2.5" + short_description: does the path exist, no follow + description: + - Check if the provided path maps to an existing symlink on the controller's filesystem (localhost). + - Does not follow symlinks, so it only verifies that the link itself exists. + options: + _input: + description: A path. + type: path + +EXAMPLES: | + ismyhostsalink: "{{ '/etc/hosts' is link_exists}}" + list_of_symlinks: "{{ list_of_paths | select('link_exists') }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to an existing filesystem object on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/match.yml b/lib/ansible/plugins/test/match.yml new file mode 100644 index 0000000..ecb4ae6 --- /dev/null +++ b/lib/ansible/plugins/test/match.yml @@ -0,0 +1,32 @@ +DOCUMENTATION: + name: match + author: Ansible Core + short_description: Does string match regular expression from the start + description: + - Compare string against regular expression using Python's match function, + this means the regex is automatically anchored at the start of the string. + options: + _input: + description: String to match. + type: string + required: True + pattern: + description: Regex to match against. + type: string + required: True + ignorecase: + description: Use case insenstive matching. + type: boolean + default: False + multiline: + description: Match against mulitple lines in string. + type: boolean + default: False +EXAMPLES: | + url: "https://example.com/users/foo/resources/bar" + foundmatch: url is match("https://example.com/users/.*/resources") + nomatch: url is match("/users/.*/resources") +RETURN: + _value: + description: Returns C(True) if there is a match, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/mathstuff.py b/lib/ansible/plugins/test/mathstuff.py new file mode 100644 index 0000000..9a3f467 --- /dev/null +++ b/lib/ansible/plugins/test/mathstuff.py @@ -0,0 +1,62 @@ +# (c) 2016, Ansible, Inc +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import math + + +def issubset(a, b): + return set(a) <= set(b) + + +def issuperset(a, b): + return set(a) >= set(b) + + +def isnotanumber(x): + try: + return math.isnan(x) + except TypeError: + return False + + +def contains(seq, value): + '''Opposite of the ``in`` test, allowing use as a test in filters like ``selectattr`` + + .. versionadded:: 2.8 + ''' + return value in seq + + +class TestModule: + ''' Ansible math jinja2 tests ''' + + def tests(self): + return { + # set theory + 'subset': issubset, + 'issubset': issubset, + 'superset': issuperset, + 'issuperset': issuperset, + 'contains': contains, + + # numbers + 'nan': isnotanumber, + 'isnan': isnotanumber, + } diff --git a/lib/ansible/plugins/test/mount.yml b/lib/ansible/plugins/test/mount.yml new file mode 100644 index 0000000..23f19b6 --- /dev/null +++ b/lib/ansible/plugins/test/mount.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: mount + author: Ansible Core + version_added: "2.5" + short_description: does the path resolve to mount point + description: + - Check if the provided path maps to a filesystem mount point on the controller (localhost). + aliases: [is_mount] + options: + _input: + description: A path. + type: path + +EXAMPLES: | + vars: + ihopefalse: "{{ '/etc/hosts' is mount }}" + normallytrue: "{{ '/tmp' is mount }}" + +RETURN: + _value: + description: Returns C(True) if the path corresponds to a mount point on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/nan.yml b/lib/ansible/plugins/test/nan.yml new file mode 100644 index 0000000..3c1055b --- /dev/null +++ b/lib/ansible/plugins/test/nan.yml @@ -0,0 +1,20 @@ +DOCUMENTATION: + name: nan + author: Ansible Core + version_added: "2.5" + short_description: is this not a number (NaN) + description: + - Whether the input is a special floating point number called L(not a number, https://en.wikipedia.org/wiki/NaN). + aliases: [is_file] + options: + _input: + description: Possible number representation or string that can be converted into one. + type: raw + required: true +EXAMPLES: | + isnan: "{{ '42' is nan }}" + +RETURN: + _value: + description: Returns C(True) if the input is NaN, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/reachable.yml b/lib/ansible/plugins/test/reachable.yml new file mode 100644 index 0000000..8cb1ce3 --- /dev/null +++ b/lib/ansible/plugins/test/reachable.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: reachable + author: Ansible Core + version_added: "1.9" + short_description: Task did not end due to unreachable host + description: + - Tests if task was able to reach the host for execution + - This test checks for the existance of a C(unreachable) key in the input dictionary and that it is C(False) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is reachable }} + +RETURN: + _value: + description: Returns C(True) if the task did not flag the host as unreachable, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/regex.yml b/lib/ansible/plugins/test/regex.yml new file mode 100644 index 0000000..90ca786 --- /dev/null +++ b/lib/ansible/plugins/test/regex.yml @@ -0,0 +1,37 @@ +DOCUMENTATION: + name: regex + author: Ansible Core + short_description: Does string match regular expression from the start + description: + - Compare string against regular expression using Python's match or search functions. + options: + _input: + description: String to match. + type: string + required: True + pattern: + description: Regex to match against. + type: string + required: True + ignorecase: + description: Use case insenstive matching. + type: boolean + default: False + multiline: + description: Match against multiple lines in string. + type: boolean + default: False + match_type: + description: Decide which function to be used to do the matching. + type: string + choices: [match, search] + default: search + +EXAMPLES: | + url: "https://example.com/users/foo/resources/bar" + foundmatch: url is regex("example\.com/\w+/foo") + +RETURN: + _value: + description: Returns C(True) if there is a match, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/same_file.yml b/lib/ansible/plugins/test/same_file.yml new file mode 100644 index 0000000..a10a36a --- /dev/null +++ b/lib/ansible/plugins/test/same_file.yml @@ -0,0 +1,24 @@ +DOCUMENTATION: + name: same_file + author: Ansible Core + version_added: "2.5" + short_description: compares two paths to see if they resolve to the same filesystem object + description: Check if the provided paths map to the same location on the controller's filesystem (localhost). + aliases: [is_file] + options: + _input: + description: A path. + type: path + required: true + _path2: + description: Another path. + type: path + required: true + +EXAMPLES: | + amionelevelfromroot: "{{ '/etc/hosts' is same_file('../etc/hosts') }}" + +RETURN: + _value: + description: Returns C(True) if the paths correspond to the same location on the filesystem on the controller, C(False) if otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/search.yml b/lib/ansible/plugins/test/search.yml new file mode 100644 index 0000000..4578bde --- /dev/null +++ b/lib/ansible/plugins/test/search.yml @@ -0,0 +1,33 @@ +DOCUMENTATION: + name: search + author: Ansible Core + short_description: Does string match a regular expression + description: + - Compare string against regular expression using Python's C(search) function. + options: + _input: + description: String to match. + type: string + required: True + pattern: + description: Regex to match against. + type: string + required: True + ignorecase: + description: Use case insenstive matching. + type: boolean + default: False + multiline: + description: Match against mulitple lines in string. + type: boolean + default: False + +EXAMPLES: | + url: "https://example.com/users/foo/resources/bar" + foundmatch: url is search("https://example.com/users/.*/resources") + alsomatch: url is search("users/.*/resources") + +RETURN: + _value: + description: Returns C(True) if there is a match, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/skip.yml b/lib/ansible/plugins/test/skip.yml new file mode 100644 index 0000000..9727172 --- /dev/null +++ b/lib/ansible/plugins/test/skip.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: skipped + author: Ansible Core + version_added: "1.9" + short_description: Was task skipped + aliases: [skip] + description: + - Tests if task was skipped + - This test checks for the existance of a C(skipped) key in the input dictionary and that it is C(True) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is skipped}} + +RETURN: + _value: + description: Returns C(True) if the task was skipped, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/skipped.yml b/lib/ansible/plugins/test/skipped.yml new file mode 100644 index 0000000..9727172 --- /dev/null +++ b/lib/ansible/plugins/test/skipped.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: skipped + author: Ansible Core + version_added: "1.9" + short_description: Was task skipped + aliases: [skip] + description: + - Tests if task was skipped + - This test checks for the existance of a C(skipped) key in the input dictionary and that it is C(True) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is skipped}} + +RETURN: + _value: + description: Returns C(True) if the task was skipped, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/started.yml b/lib/ansible/plugins/test/started.yml new file mode 100644 index 0000000..0cb0602 --- /dev/null +++ b/lib/ansible/plugins/test/started.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: started + author: Ansible Core + version_added: "1.9" + short_description: Was async task started + description: + - Used to check if an async task has started, will also work with non async tasks but will issue a warning. + - This test checks for the existance of a C(started) key in the input dictionary and that it is C(1) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (asynctaskpoll is started}} + +RETURN: + _value: + description: Returns C(True) if the task has started, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/subset.yml b/lib/ansible/plugins/test/subset.yml new file mode 100644 index 0000000..d57d05b --- /dev/null +++ b/lib/ansible/plugins/test/subset.yml @@ -0,0 +1,28 @@ +DOCUMENTATION: + name: subset + author: Ansible Core + version_added: "2.4" + aliases: [issubset] + short_description: is the list a subset of this other list + description: + - Validate if the first list is a sub set (is included) of the second list. + - Same as the C(all) Python function. + options: + _input: + description: List. + type: list + elements: raw + required: True + _superset: + description: List to test against. + type: list + elements: raw + required: True +EXAMPLES: | + big: [1,2,3,4,5] + sml: [3,4] + issmallinbig: '{{ small is subset(big) }}' +RETURN: + _value: + description: Returns C(True) if the specified list is a subset of the provided list, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/succeeded.yml b/lib/ansible/plugins/test/succeeded.yml new file mode 100644 index 0000000..4626f9f --- /dev/null +++ b/lib/ansible/plugins/test/succeeded.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: success + author: Ansible Core + version_added: "1.9" + short_description: check task success + aliases: [succeeded, successful] + description: + - Tests if task finished successfully, opposite of C(failed). + - This test checks for the existance of a C(failed) key in the input dictionary and that it is C(False) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is success }} + +RETURN: + _value: + description: Returns C(True) if the task was successfully completed, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/success.yml b/lib/ansible/plugins/test/success.yml new file mode 100644 index 0000000..4626f9f --- /dev/null +++ b/lib/ansible/plugins/test/success.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: success + author: Ansible Core + version_added: "1.9" + short_description: check task success + aliases: [succeeded, successful] + description: + - Tests if task finished successfully, opposite of C(failed). + - This test checks for the existance of a C(failed) key in the input dictionary and that it is C(False) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is success }} + +RETURN: + _value: + description: Returns C(True) if the task was successfully completed, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/successful.yml b/lib/ansible/plugins/test/successful.yml new file mode 100644 index 0000000..4626f9f --- /dev/null +++ b/lib/ansible/plugins/test/successful.yml @@ -0,0 +1,22 @@ +DOCUMENTATION: + name: success + author: Ansible Core + version_added: "1.9" + short_description: check task success + aliases: [succeeded, successful] + description: + - Tests if task finished successfully, opposite of C(failed). + - This test checks for the existance of a C(failed) key in the input dictionary and that it is C(False) if present + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is success }} + +RETURN: + _value: + description: Returns C(True) if the task was successfully completed, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/superset.yml b/lib/ansible/plugins/test/superset.yml new file mode 100644 index 0000000..72be3d5 --- /dev/null +++ b/lib/ansible/plugins/test/superset.yml @@ -0,0 +1,28 @@ +DOCUMENTATION: + name: superset + author: Ansible Core + version_added: "2.4" + short_description: is the list a superset of this other list + aliases: [issuperset] + description: + - Validate if the first list is a super set (includes) the second list. + - Same as the C(all) Python function. + options: + _input: + description: List. + type: list + elements: raw + required: True + _subset: + description: List to test against. + type: list + elements: raw + required: True +EXAMPLES: | + big: [1,2,3,4,5] + sml: [3,4] + issmallinbig: '{{ big is superset(small) }}' +RETURN: + _value: + description: Returns C(True) if the specified list is a superset of the provided list, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/truthy.yml b/lib/ansible/plugins/test/truthy.yml new file mode 100644 index 0000000..01d5255 --- /dev/null +++ b/lib/ansible/plugins/test/truthy.yml @@ -0,0 +1,24 @@ +DOCUMENTATION: + name: truthy + author: Ansible Core + version_added: "2.10" + short_description: Pythonic true + description: + - This check is a more Python version of what is 'true'. + - It is the opposite of C(falsy). + options: + _input: + description: An expression that can be expressed in a boolean context. + type: string + required: True + convert_bool: + description: Attempts to convert to strict python boolean vs normally acceptable values (C(yes)/C(no), C(on)/C(off), C(0)/C(1), etc). + type: bool + default: false +EXAMPLES: | + thisistrue: '{{ "any string" is truthy }}' + thisisfalse: '{{ "" is truthy }}' +RETURN: + _value: + description: Returns C(True) if the condition is not "Python truthy", C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/unreachable.yml b/lib/ansible/plugins/test/unreachable.yml new file mode 100644 index 0000000..ed6c17e --- /dev/null +++ b/lib/ansible/plugins/test/unreachable.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: unreachable + author: Ansible Core + version_added: "1.9" + short_description: Did task end due to the host was unreachable + description: + - Tests if task was not able to reach the host for execution + - This test checks for the existance of a C(unreachable) key in the input dictionary and that it's value is C(True) + options: + _input: + description: registered result from an Ansible task + type: dictionary + required: True +EXAMPLES: | + # test 'status' to know how to respond + {{ (taskresults is unreachable }} + +RETURN: + _value: + description: Returns C(True) if the task flagged the host as unreachable, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/uri.py b/lib/ansible/plugins/test/uri.py new file mode 100644 index 0000000..7ef3381 --- /dev/null +++ b/lib/ansible/plugins/test/uri.py @@ -0,0 +1,46 @@ +# (c) Ansible Project + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from urllib.parse import urlparse + + +def is_uri(value, schemes=None): + ''' Will verify that the string passed is a valid 'URI', if given a list of valid schemes it will match those ''' + try: + x = urlparse(value) + isit = all([x.scheme is not None, x.path is not None, not schemes or x.scheme in schemes]) + except Exception as e: + isit = False + return isit + + +def is_url(value, schemes=None): + ''' Will verify that the string passed is a valid 'URL' ''' + + isit = is_uri(value, schemes) + if isit: + try: + x = urlparse(value) + isit = bool(x.netloc or x.scheme == 'file') + except Exception as e: + isit = False + return isit + + +def is_urn(value): + return is_uri(value, ['urn']) + + +class TestModule(object): + ''' Ansible URI jinja2 test ''' + + def tests(self): + return { + # file testing + 'uri': is_uri, + 'url': is_url, + 'urn': is_urn, + } diff --git a/lib/ansible/plugins/test/uri.yml b/lib/ansible/plugins/test/uri.yml new file mode 100644 index 0000000..bb3b8bd --- /dev/null +++ b/lib/ansible/plugins/test/uri.yml @@ -0,0 +1,30 @@ +DOCUMENTATION: + name: uri + author: Ansible Core + version_added: "2.14" + short_description: is the string a valid URI + description: + - Validates that the input string conforms to the URI standard, optionally that is also in the list of schemas provided. + options: + _input: + description: Possible URI. + type: string + required: True + schemes: + description: Subset of URI schemas to validate against, otherwise B(any) scheme is considered valid. + type: list + elements: string + required: False +EXAMPLES: | + # URLs are URIs + {{ 'http://example.com' is uri }} + # but not all URIs are URLs + {{ 'mailto://nowone@example.com' is uri }} + # looking only for file transfers URIs + {{ 'mailto://nowone@example.com' is not uri(schemes=['ftp', 'ftps', 'sftp', 'file']) }} + # make sure URL conforms to the 'special schemas' + {{ 'http://nobody:secret@example.com' is uri(['ftp', 'ftps', 'http', 'https', 'ws', 'wss']) }} +RETURN: + _value: + description: Returns C(false) if the string is not a URI or the schema extracted does not match the supplied list. + type: boolean diff --git a/lib/ansible/plugins/test/url.yml b/lib/ansible/plugins/test/url.yml new file mode 100644 index 0000000..36b6c77 --- /dev/null +++ b/lib/ansible/plugins/test/url.yml @@ -0,0 +1,29 @@ +DOCUMENTATION: + name: url + author: Ansible Core + version_added: "2.14" + short_description: is the string a valid URL + description: + - Validates a string to conform to the URL standard. + options: + _input: + description: Possible URL. + type: string + required: True + schemes: + description: Subset of URI schemas to validate against, otherwise B(any) scheme is considered valid. + type: list + elements: string +EXAMPLES: | + # simple URL + {{ 'http://example.com' is url }} + # looking only for file transfers URIs + {{ 'mailto://nowone@example.com' is not uri(schemes=['ftp', 'ftps', 'sftp', 'file']) }} + # but it is according to standard + {{ 'mailto://nowone@example.com' is not uri }} + # more complex URL + {{ 'ftp://admin:secret@example.com/path/to/myfile.yml' is url }} +RETURN: + _value: + description: Returns C(false) if the string is not a URL, C(true) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/urn.yml b/lib/ansible/plugins/test/urn.yml new file mode 100644 index 0000000..81a6686 --- /dev/null +++ b/lib/ansible/plugins/test/urn.yml @@ -0,0 +1,21 @@ +DOCUMENTATION: + name: urn + author: Ansible Core + version_added: "2.14" + short_description: is the string a valid URN + description: + - Validates that the input string conforms to the URN standard. + options: + _input: + description: Possible URN. + type: string + required: True +EXAMPLES: | + # ISBN in URN format + {{ 'urn:isbn:9780302376463' is urn }} + # this is URL/URI but not URN + {{ 'mailto://nowone@example.com' is not urn }} +RETURN: + _value: + description: Returns C(true) if the string is a URN and C(false) if it is not. + type: boolean diff --git a/lib/ansible/plugins/test/vault_encrypted.yml b/lib/ansible/plugins/test/vault_encrypted.yml new file mode 100644 index 0000000..58d79f1 --- /dev/null +++ b/lib/ansible/plugins/test/vault_encrypted.yml @@ -0,0 +1,19 @@ +DOCUMENTATION: + name: truthy + author: Ansible Core + version_added: "2.10" + short_description: Is this an encrypted vault + description: + - Verifies if the input is an Ansible vault. + options: + _input: + description: The possible vault. + type: string + required: True +EXAMPLES: | + thisisfalse: '{{ "any string" is ansible_vault }}' + thisistrue: '{{ "$ANSIBLE_VAULT;1.2;AES256;dev...." is ansible_vault }}' +RETURN: + _value: + description: Returns C(True) if the input is a valid ansible vault, C(False) otherwise. + type: boolean diff --git a/lib/ansible/plugins/test/version.yml b/lib/ansible/plugins/test/version.yml new file mode 100644 index 0000000..92b6048 --- /dev/null +++ b/lib/ansible/plugins/test/version.yml @@ -0,0 +1,82 @@ +DOCUMENTATION: + name: version + author: Ansible Core + version_added: "1.6" + short_description: compare version strings + aliases: [version_compare] + description: + - Compare version strings using various versioning schemes + options: + _input: + description: Left hand version to compare + type: string + required: True + version: + description: Right hand version to compare + type: string + required: True + operator: + description: Comparison operator + type: string + required: False + choices: + - == + - '=' + - eq + - < + - lt + - <= + - le + - '>' + - gt + - '>=' + - ge + - '!=' + - <> + - ne + default: eq + strict: + description: Whether to use strict version scheme. Mutually exclusive with C(version_type) + type: boolean + required: False + default: False + version_type: + description: Version scheme to use for comparison. Mutually exclusive with C(strict). See C(notes) for descriptions on the version types. + type: string + required: False + choices: + - loose + - strict + - semver + - semantic + - pep440 + default: loose + notes: + - C(loose) - This type corresponds to the Python C(distutils.version.LooseVersion) class. All version formats are valid for this type. The rules for comparison are simple and predictable, but may not always give expected results. + - C(strict) - This type corresponds to the Python C(distutils.version.StrictVersion) class. A version number consists of two or three dot-separated numeric components, with an optional "pre-release" tag on the end. The pre-release tag consists of a single letter C(a) or C(b) followed by a number. If the numeric components of two version numbers are equal, then one with a pre-release tag will always be deemed earlier (lesser) than one without. + - C(semver)/C(semantic) - This type implements the L(Semantic Version,https://semver.org) scheme for version comparison. + - C(pep440) - This type implements the Python L(PEP-440,https://peps.python.org/pep-0440/) versioning rules for version comparison. Added in version 2.14. +EXAMPLES: | + - name: version test examples + assert: + that: + - "'1.0' is version_compare('1.0', '==')" # old name + - "'1.0' is version('1.0', '==')" + - "'1.0' is version('2.0', '!=')" + - "'1.0' is version('2.0', '<')" + - "'2.0' is version('1.0', '>')" + - "'1.0' is version('1.0', '<=')" + - "'1.0' is version('1.0', '>=')" + - "'1.0' is version_compare('1.0', '==', strict=true)" # old name + - "'1.0' is version('1.0', '==', strict=true)" + - "'1.0' is version('2.0', '!=', strict=true)" + - "'1.0' is version('2.0', '<', strict=true)" + - "'2.0' is version('1.0', '>', strict=true)" + - "'1.0' is version('1.0', '<=', strict=true)" + - "'1.0' is version('1.0', '>=', strict=true)" + - "'1.2.3' is version('2.0.0', 'lt', version_type='semver')" + - "'2.14.0rc1' is version('2.14.0', 'lt', version_type='pep440')" +RETURN: + _value: + description: Returns C(True) or C(False) depending on the outcome of the comparison. + type: boolean diff --git a/lib/ansible/plugins/test/version_compare.yml b/lib/ansible/plugins/test/version_compare.yml new file mode 100644 index 0000000..92b6048 --- /dev/null +++ b/lib/ansible/plugins/test/version_compare.yml @@ -0,0 +1,82 @@ +DOCUMENTATION: + name: version + author: Ansible Core + version_added: "1.6" + short_description: compare version strings + aliases: [version_compare] + description: + - Compare version strings using various versioning schemes + options: + _input: + description: Left hand version to compare + type: string + required: True + version: + description: Right hand version to compare + type: string + required: True + operator: + description: Comparison operator + type: string + required: False + choices: + - == + - '=' + - eq + - < + - lt + - <= + - le + - '>' + - gt + - '>=' + - ge + - '!=' + - <> + - ne + default: eq + strict: + description: Whether to use strict version scheme. Mutually exclusive with C(version_type) + type: boolean + required: False + default: False + version_type: + description: Version scheme to use for comparison. Mutually exclusive with C(strict). See C(notes) for descriptions on the version types. + type: string + required: False + choices: + - loose + - strict + - semver + - semantic + - pep440 + default: loose + notes: + - C(loose) - This type corresponds to the Python C(distutils.version.LooseVersion) class. All version formats are valid for this type. The rules for comparison are simple and predictable, but may not always give expected results. + - C(strict) - This type corresponds to the Python C(distutils.version.StrictVersion) class. A version number consists of two or three dot-separated numeric components, with an optional "pre-release" tag on the end. The pre-release tag consists of a single letter C(a) or C(b) followed by a number. If the numeric components of two version numbers are equal, then one with a pre-release tag will always be deemed earlier (lesser) than one without. + - C(semver)/C(semantic) - This type implements the L(Semantic Version,https://semver.org) scheme for version comparison. + - C(pep440) - This type implements the Python L(PEP-440,https://peps.python.org/pep-0440/) versioning rules for version comparison. Added in version 2.14. +EXAMPLES: | + - name: version test examples + assert: + that: + - "'1.0' is version_compare('1.0', '==')" # old name + - "'1.0' is version('1.0', '==')" + - "'1.0' is version('2.0', '!=')" + - "'1.0' is version('2.0', '<')" + - "'2.0' is version('1.0', '>')" + - "'1.0' is version('1.0', '<=')" + - "'1.0' is version('1.0', '>=')" + - "'1.0' is version_compare('1.0', '==', strict=true)" # old name + - "'1.0' is version('1.0', '==', strict=true)" + - "'1.0' is version('2.0', '!=', strict=true)" + - "'1.0' is version('2.0', '<', strict=true)" + - "'2.0' is version('1.0', '>', strict=true)" + - "'1.0' is version('1.0', '<=', strict=true)" + - "'1.0' is version('1.0', '>=', strict=true)" + - "'1.2.3' is version('2.0.0', 'lt', version_type='semver')" + - "'2.14.0rc1' is version('2.14.0', 'lt', version_type='pep440')" +RETURN: + _value: + description: Returns C(True) or C(False) depending on the outcome of the comparison. + type: boolean |