diff options
Diffstat (limited to 'lib/ansible/plugins/filter/core.py')
-rw-r--r-- | lib/ansible/plugins/filter/core.py | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index b7e2c11e..eee43e62 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -27,14 +27,14 @@ from jinja2.filters import pass_environment from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleFilterTypeError from ansible.module_utils.six import string_types, integer_types, reraise, text_type -from ansible.module_utils._text import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.yaml import yaml_load, yaml_load_all from ansible.parsing.ajson import AnsibleJSONEncoder from ansible.parsing.yaml.dumper import AnsibleDumper from ansible.template import recursive_check_defined from ansible.utils.display import Display -from ansible.utils.encrypt import passlib_or_crypt +from ansible.utils.encrypt import do_encrypt, PASSLIB_AVAILABLE from ansible.utils.hashing import md5s, checksum_s from ansible.utils.unicode import unicode_wrap from ansible.utils.unsafe_proxy import _is_unsafe @@ -193,8 +193,8 @@ def ternary(value, true_val, false_val, none_val=None): def regex_escape(string, re_type='python'): + """Escape all regular expressions special characters from STRING.""" string = to_text(string, errors='surrogate_or_strict', nonstring='simplerepr') - '''Escape all regular expressions special characters from STRING.''' if re_type == 'python': return re.escape(string) elif re_type == 'posix_basic': @@ -286,10 +286,27 @@ def get_encrypted_password(password, hashtype='sha512', salt=None, salt_size=Non } hashtype = passlib_mapping.get(hashtype, hashtype) + + unknown_passlib_hashtype = False + if PASSLIB_AVAILABLE and hashtype not in passlib_mapping and hashtype not in passlib_mapping.values(): + unknown_passlib_hashtype = True + display.deprecated( + f"Checking for unsupported password_hash passlib hashtype '{hashtype}'. " + "This will be an error in the future as all supported hashtypes must be documented.", + version='2.19' + ) + try: - return passlib_or_crypt(password, hashtype, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident) + return do_encrypt(password, hashtype, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident) except AnsibleError as e: reraise(AnsibleFilterError, AnsibleFilterError(to_native(e), orig_exc=e), sys.exc_info()[2]) + except Exception as e: + if unknown_passlib_hashtype: + # This can occur if passlib.hash has the hashtype attribute, but it has a different signature than the valid choices. + # In 2.19 this will replace the deprecation warning above and the extra exception handling can be deleted. + choices = ', '.join(passlib_mapping) + raise AnsibleFilterError(f"{hashtype} is not in the list of supported passlib algorithms: {choices}") from e + raise def to_uuid(string, namespace=UUID_NAMESPACE_ANSIBLE): @@ -304,9 +321,9 @@ def to_uuid(string, namespace=UUID_NAMESPACE_ANSIBLE): def mandatory(a, msg=None): + """Make a variable mandatory.""" from jinja2.runtime import Undefined - ''' Make a variable mandatory ''' if isinstance(a, Undefined): if a._undefined_name is not None: name = "'%s' " % to_text(a._undefined_name) @@ -315,8 +332,7 @@ def mandatory(a, msg=None): if msg is not None: raise AnsibleFilterError(to_native(msg)) - else: - raise AnsibleFilterError("Mandatory variable %s not defined." % name) + raise AnsibleFilterError("Mandatory variable %s not defined." % name) return a @@ -564,10 +580,24 @@ def path_join(paths): of the different members ''' if isinstance(paths, string_types): return os.path.join(paths) - elif is_sequence(paths): + if is_sequence(paths): return os.path.join(*paths) - else: - raise AnsibleFilterTypeError("|path_join expects string or sequence, got %s instead." % type(paths)) + raise AnsibleFilterTypeError("|path_join expects string or sequence, got %s instead." % type(paths)) + + +def commonpath(paths): + """ + Retrieve the longest common path from the given list. + + :param paths: A list of file system paths. + :type paths: List[str] + :returns: The longest common path. + :rtype: str + """ + if not is_sequence(paths): + raise AnsibleFilterTypeError("|path_join expects sequence, got %s instead." % type(paths)) + + return os.path.commonpath(paths) class FilterModule(object): @@ -605,6 +635,8 @@ class FilterModule(object): 'win_basename': partial(unicode_wrap, ntpath.basename), 'win_dirname': partial(unicode_wrap, ntpath.dirname), 'win_splitdrive': partial(unicode_wrap, ntpath.splitdrive), + 'commonpath': commonpath, + 'normpath': partial(unicode_wrap, os.path.normpath), # file glob 'fileglob': fileglob, |