summaryrefslogtreecommitdiffstats
path: root/lib/ansible/plugins/filter
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/plugins/filter')
-rw-r--r--lib/ansible/plugins/filter/__init__.py14
-rw-r--r--lib/ansible/plugins/filter/b64decode.yml29
-rw-r--r--lib/ansible/plugins/filter/b64encode.yml25
-rw-r--r--lib/ansible/plugins/filter/basename.yml24
-rw-r--r--lib/ansible/plugins/filter/bool.yml28
-rw-r--r--lib/ansible/plugins/filter/checksum.yml21
-rw-r--r--lib/ansible/plugins/filter/combinations.yml26
-rw-r--r--lib/ansible/plugins/filter/combine.yml44
-rw-r--r--lib/ansible/plugins/filter/comment.yml60
-rw-r--r--lib/ansible/plugins/filter/core.py658
-rw-r--r--lib/ansible/plugins/filter/dict2items.yml45
-rw-r--r--lib/ansible/plugins/filter/difference.yml35
-rw-r--r--lib/ansible/plugins/filter/dirname.yml24
-rw-r--r--lib/ansible/plugins/filter/encryption.py82
-rw-r--r--lib/ansible/plugins/filter/expanduser.yml21
-rw-r--r--lib/ansible/plugins/filter/expandvars.yml21
-rw-r--r--lib/ansible/plugins/filter/extract.yml39
-rw-r--r--lib/ansible/plugins/filter/fileglob.yml22
-rw-r--r--lib/ansible/plugins/filter/flatten.yml32
-rw-r--r--lib/ansible/plugins/filter/from_json.yml25
-rw-r--r--lib/ansible/plugins/filter/from_yaml.yml25
-rw-r--r--lib/ansible/plugins/filter/from_yaml_all.yml28
-rw-r--r--lib/ansible/plugins/filter/hash.yml28
-rw-r--r--lib/ansible/plugins/filter/human_readable.yml35
-rw-r--r--lib/ansible/plugins/filter/human_to_bytes.yml34
-rw-r--r--lib/ansible/plugins/filter/intersect.yml35
-rw-r--r--lib/ansible/plugins/filter/items2dict.yml48
-rw-r--r--lib/ansible/plugins/filter/log.yml33
-rw-r--r--lib/ansible/plugins/filter/mandatory.yml21
-rw-r--r--lib/ansible/plugins/filter/mathstuff.py252
-rw-r--r--lib/ansible/plugins/filter/md5.yml24
-rw-r--r--lib/ansible/plugins/filter/password_hash.yml37
-rw-r--r--lib/ansible/plugins/filter/path_join.yml30
-rw-r--r--lib/ansible/plugins/filter/permutations.yml26
-rw-r--r--lib/ansible/plugins/filter/pow.yml34
-rw-r--r--lib/ansible/plugins/filter/product.yml42
-rw-r--r--lib/ansible/plugins/filter/quote.yml23
-rw-r--r--lib/ansible/plugins/filter/random.yml35
-rw-r--r--lib/ansible/plugins/filter/realpath.yml21
-rw-r--r--lib/ansible/plugins/filter/regex_escape.yml29
-rw-r--r--lib/ansible/plugins/filter/regex_findall.yml37
-rw-r--r--lib/ansible/plugins/filter/regex_replace.yml46
-rw-r--r--lib/ansible/plugins/filter/regex_search.yml38
-rw-r--r--lib/ansible/plugins/filter/rekey_on_member.yml30
-rw-r--r--lib/ansible/plugins/filter/relpath.yml28
-rw-r--r--lib/ansible/plugins/filter/root.yml32
-rw-r--r--lib/ansible/plugins/filter/sha1.yml24
-rw-r--r--lib/ansible/plugins/filter/shuffle.yml27
-rw-r--r--lib/ansible/plugins/filter/split.yml32
-rw-r--r--lib/ansible/plugins/filter/splitext.yml30
-rw-r--r--lib/ansible/plugins/filter/strftime.yml45
-rw-r--r--lib/ansible/plugins/filter/subelements.yml38
-rw-r--r--lib/ansible/plugins/filter/symmetric_difference.yml35
-rw-r--r--lib/ansible/plugins/filter/ternary.yml44
-rw-r--r--lib/ansible/plugins/filter/to_datetime.yml35
-rw-r--r--lib/ansible/plugins/filter/to_json.yml69
-rw-r--r--lib/ansible/plugins/filter/to_nice_json.yml54
-rw-r--r--lib/ansible/plugins/filter/to_nice_yaml.yml39
-rw-r--r--lib/ansible/plugins/filter/to_uuid.yml30
-rw-r--r--lib/ansible/plugins/filter/to_yaml.yml52
-rw-r--r--lib/ansible/plugins/filter/type_debug.yml20
-rw-r--r--lib/ansible/plugins/filter/union.yml35
-rw-r--r--lib/ansible/plugins/filter/unique.yml30
-rw-r--r--lib/ansible/plugins/filter/unvault.yml36
-rw-r--r--lib/ansible/plugins/filter/urldecode.yml48
-rw-r--r--lib/ansible/plugins/filter/urls.py20
-rw-r--r--lib/ansible/plugins/filter/urlsplit.py87
-rw-r--r--lib/ansible/plugins/filter/vault.yml48
-rw-r--r--lib/ansible/plugins/filter/win_basename.yml24
-rw-r--r--lib/ansible/plugins/filter/win_dirname.yml24
-rw-r--r--lib/ansible/plugins/filter/win_splitdrive.yml29
-rw-r--r--lib/ansible/plugins/filter/zip.yml43
-rw-r--r--lib/ansible/plugins/filter/zip_longest.yml36
73 files changed, 3360 insertions, 0 deletions
diff --git a/lib/ansible/plugins/filter/__init__.py b/lib/ansible/plugins/filter/__init__.py
new file mode 100644
index 0000000..5ae10da
--- /dev/null
+++ b/lib/ansible/plugins/filter/__init__.py
@@ -0,0 +1,14 @@
+# (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 import constants as C
+from ansible.plugins import AnsibleJinja2Plugin
+
+
+class AnsibleJinja2Filter(AnsibleJinja2Plugin):
+
+ def _no_options(self, *args, **kwargs):
+ raise NotImplementedError("Jinaj2 filter plugins do not support option functions, they use direct arguments instead.")
diff --git a/lib/ansible/plugins/filter/b64decode.yml b/lib/ansible/plugins/filter/b64decode.yml
new file mode 100644
index 0000000..30565fa
--- /dev/null
+++ b/lib/ansible/plugins/filter/b64decode.yml
@@ -0,0 +1,29 @@
+DOCUMENTATION:
+ name: b64decode
+ author: ansible core team
+ version_added: 'historical'
+ short_description: Decode a base64 string
+ description:
+ - Base64 decoding function.
+ - The return value is a string.
+ - Trying to store a binary blob in a string most likely corrupts the binary. To base64 decode a binary blob,
+ use the ``base64`` command and pipe the encoded data through standard input.
+ For example, in the ansible.builtin.shell`` module, ``cmd="base64 --decode > myfile.bin" stdin="{{ encoded }}"``.
+ positional: _input
+ options:
+ _input:
+ description: A base64 string to decode.
+ type: string
+ required: true
+
+EXAMPLES: |
+ # b64 decode a string
+ lola: "{{ 'bG9sYQ==' | b64decode }}"
+
+ # b64 decode the content of 'b64stuff' variable
+ stuff: "{{ b64stuff | b64encode }}"
+
+RETURN:
+ _value:
+ description: The contents of the base64 encoded string.
+ type: string
diff --git a/lib/ansible/plugins/filter/b64encode.yml b/lib/ansible/plugins/filter/b64encode.yml
new file mode 100644
index 0000000..14676e5
--- /dev/null
+++ b/lib/ansible/plugins/filter/b64encode.yml
@@ -0,0 +1,25 @@
+DOCUMENTATION:
+ name: b64encode
+ author: ansible core team
+ version_added: 'historical'
+ short_description: Encode a string as base64
+ description:
+ - Base64 encoding function.
+ positional: _input
+ options:
+ _input:
+ description: A string to encode.
+ type: string
+ required: true
+
+EXAMPLES: |
+ # b64 encode a string
+ b64lola: "{{ 'lola'|b64encode }}"
+
+ # b64 encode the content of 'stuff' variable
+ b64stuff: "{{ stuff|b64encode }}"
+
+RETURN:
+ _value:
+ description: A base64 encoded string.
+ type: string
diff --git a/lib/ansible/plugins/filter/basename.yml b/lib/ansible/plugins/filter/basename.yml
new file mode 100644
index 0000000..4e868df
--- /dev/null
+++ b/lib/ansible/plugins/filter/basename.yml
@@ -0,0 +1,24 @@
+DOCUMENTATION:
+ name: basename
+ author: ansible core team
+ version_added: "historical"
+ short_description: get a path's base name
+ description:
+ - Returns the last name component of a path, what is left in the string that is not 'dirname'.
+ options:
+ _input:
+ description: A path.
+ type: path
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.dirname
+EXAMPLES: |
+
+ # To get the last name of a file path, like 'foo.txt' out of '/etc/asdf/foo.txt'
+ {{ mypath | basename }}
+
+RETURN:
+ _value:
+ description: The base name from the path provided.
+ type: str
diff --git a/lib/ansible/plugins/filter/bool.yml b/lib/ansible/plugins/filter/bool.yml
new file mode 100644
index 0000000..86ba353
--- /dev/null
+++ b/lib/ansible/plugins/filter/bool.yml
@@ -0,0 +1,28 @@
+DOCUMENTATION:
+ name: bool
+ version_added: "historical"
+ short_description: cast into a boolean
+ description:
+ - Attempt to cast the input into a boolean (C(True) or C(False)) value.
+ positional: _input
+ options:
+ _input:
+ description: Data to cast.
+ type: raw
+ required: true
+
+EXAMPLES: |
+
+ # simply encrypt my key in a vault
+ vars:
+ isbool: "{{ (a == b)|bool }} "
+ otherbool: "{{ anothervar|bool }} "
+
+ # in a task
+ ...
+ when: some_string_value | bool
+
+RETURN:
+ _value:
+ description: The boolean resulting of casting the input expression into a C(True) or C(False) value.
+ type: bool
diff --git a/lib/ansible/plugins/filter/checksum.yml b/lib/ansible/plugins/filter/checksum.yml
new file mode 100644
index 0000000..2f8eadd
--- /dev/null
+++ b/lib/ansible/plugins/filter/checksum.yml
@@ -0,0 +1,21 @@
+DOCUMENTATION:
+ name: checksum
+ version_added: "1.9"
+ short_description: checksum of input data
+ description:
+ - Returns a checksum (L(SHA-1, https://en.wikipedia.org/wiki/SHA-1)) hash of the input data.
+ positional: _input
+ options:
+ _input:
+ description: Data to checksum.
+ type: raw
+ required: true
+
+EXAMPLES: |
+ # csum => "109f4b3c50d7b0df729d299bc6f8e9ef9066971f"
+ csum: "{{ 'test2' | checksum }}"
+
+RETURN:
+ _value:
+ description: The checksum (SHA-1) of the input.
+ type: string
diff --git a/lib/ansible/plugins/filter/combinations.yml b/lib/ansible/plugins/filter/combinations.yml
new file mode 100644
index 0000000..a46e51e
--- /dev/null
+++ b/lib/ansible/plugins/filter/combinations.yml
@@ -0,0 +1,26 @@
+DOCUMENTATION:
+ name: combinations
+ version_added: "historical"
+ short_description: combinations from the elements of a list
+ description:
+ - Create a list of combinations of sets from the elements of a list.
+ positional: _input, set_size
+ options:
+ _input:
+ description: Elements to combine.
+ type: list
+ required: true
+ set_size:
+ description: The size of the set for each combination.
+ type: int
+ required: true
+EXAMPLES: |
+
+ # combos_of_two => [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 1, 5 ], [ 2, 3 ], [ 2, 4 ], [ 2, 5 ], [ 3, 4 ], [ 3, 5 ], [ 4, 5 ] ]
+ combos_of_two: "{{ [1,2,3,4,5] | combinations(2) }}"
+
+
+RETURN:
+ _value:
+ description: List of combination sets resulting from the supplied elements and set size.
+ type: list
diff --git a/lib/ansible/plugins/filter/combine.yml b/lib/ansible/plugins/filter/combine.yml
new file mode 100644
index 0000000..86788f3
--- /dev/null
+++ b/lib/ansible/plugins/filter/combine.yml
@@ -0,0 +1,44 @@
+DOCUMENTATION:
+ name: combine
+ version_added: "2.0"
+ short_description: combine two dictionaries
+ description:
+ - Create a dictionary (hash/associative array) as a result of merging existing dictionaries.
+ positional: _input, _dicts
+ options:
+ _input:
+ description: First dictionary to combine.
+ type: dict
+ required: true
+ _dicts: # TODO: this is really an *args so not list, but list ref
+ description: The list of dictionaries to combine.
+ type: list
+ elements: dictionary
+ required: true
+ recursive:
+ description: If C(True), merge elements recursively.
+ type: bool
+ default: false
+ list_merge:
+ description: Behavior when encountering list elements.
+ type: str
+ default: replace
+ choices:
+ replace: overwrite older entries with newer ones
+ keep: discard newer entries
+ append: append newer entries to the older ones
+ prepend: insert newer entries in front of the older ones
+ append_rp: append newer entries to the older ones, overwrite duplicates
+ prepend_rp: insert newer entries in front of the older ones, discard duplicates
+
+EXAMPLES: |
+
+ # ab => {'a':1, 'b':3, 'c': 4}
+ ab: {{ {'a':1, 'b':2} | combine({'b':3, 'c':4}) }}
+
+ many: "{{ dict1 | combine(dict2, dict3, dict4) }}"
+
+RETURN:
+ _value:
+ description: Resulting merge of supplied dictionaries.
+ type: dict
diff --git a/lib/ansible/plugins/filter/comment.yml b/lib/ansible/plugins/filter/comment.yml
new file mode 100644
index 0000000..95a4efb
--- /dev/null
+++ b/lib/ansible/plugins/filter/comment.yml
@@ -0,0 +1,60 @@
+DOCUMENTATION:
+ name: comment
+ version_added: 'historical'
+ short_description: comment out a string
+ description:
+ - Use programming language conventions to turn the input string into an embeddable comment.
+ positional: _input, style
+ options:
+ _input:
+ description: String to comment.
+ type: string
+ required: true
+ style:
+ description: Comment style to use.
+ type: string
+ default: plain
+ choices: ['plain', 'decoration', 'erlang', 'c', 'cblock', 'xml']
+ decoration:
+ description: Indicator for comment or intermediate comment depending on the style.
+ type: string
+ begining:
+ description: Indicator of the start of a comment block, only available for styles that support multiline comments.
+ type: string
+ end:
+ description: Indicator the end of a comment block, only available for styles that support multiline comments.
+ type: string
+ newline:
+ description: Indicator of comment end of line, only available for styles that support multiline comments.
+ type: string
+ default: '\n'
+ prefix:
+ description: Token to start each line inside a comment block, only available for styles that support multiline comments.
+ type: string
+ prefix_count:
+ description: Number of times to add a prefix at the start of a line, when a prefix exists and is usable.
+ type: int
+ default: 1
+ postfix:
+ description: Indicator of the end of each line inside a comment block, only available for styles that support multiline comments.
+ type: string
+ protfix_count:
+ description: Number of times to add a postfix at the end of a line, when a prefix exists and is usable.
+ type: int
+ default: 1
+
+EXAMPLES: |
+
+ # commented => #
+ # # Plain style (default)
+ # #
+ commented: "{{ 'Plain style (default)' | comment }}"
+
+ # not going to show that here ...
+ verycustom: "{{ "Custom style" | comment('plain', prefix='#######\n#', postfix='#\n#######\n ###\n #') }}"
+
+
+RETURN:
+ _value:
+ description: The 'commented out' string.
+ type: string
diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py
new file mode 100644
index 0000000..52a2cd1
--- /dev/null
+++ b/lib/ansible/plugins/filter/core.py
@@ -0,0 +1,658 @@
+# (c) 2012, Jeroen Hoekx <jeroen@hoekx.be>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import base64
+import glob
+import hashlib
+import json
+import ntpath
+import os.path
+import re
+import shlex
+import sys
+import time
+import uuid
+import yaml
+import datetime
+
+from collections.abc import Mapping
+from functools import partial
+from random import Random, SystemRandom, shuffle
+
+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.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.hashing import md5s, checksum_s
+from ansible.utils.unicode import unicode_wrap
+from ansible.utils.vars import merge_hash
+
+display = Display()
+
+UUID_NAMESPACE_ANSIBLE = uuid.UUID('361E6D51-FAEC-444A-9079-341386DA8E2E')
+
+
+def to_yaml(a, *args, **kw):
+ '''Make verbose, human readable yaml'''
+ default_flow_style = kw.pop('default_flow_style', None)
+ try:
+ transformed = yaml.dump(a, Dumper=AnsibleDumper, allow_unicode=True, default_flow_style=default_flow_style, **kw)
+ except Exception as e:
+ raise AnsibleFilterError("to_yaml - %s" % to_native(e), orig_exc=e)
+ return to_text(transformed)
+
+
+def to_nice_yaml(a, indent=4, *args, **kw):
+ '''Make verbose, human readable yaml'''
+ try:
+ transformed = yaml.dump(a, Dumper=AnsibleDumper, indent=indent, allow_unicode=True, default_flow_style=False, **kw)
+ except Exception as e:
+ raise AnsibleFilterError("to_nice_yaml - %s" % to_native(e), orig_exc=e)
+ return to_text(transformed)
+
+
+def to_json(a, *args, **kw):
+ ''' Convert the value to JSON '''
+
+ # defaults for filters
+ if 'vault_to_text' not in kw:
+ kw['vault_to_text'] = True
+ if 'preprocess_unsafe' not in kw:
+ kw['preprocess_unsafe'] = False
+
+ return json.dumps(a, cls=AnsibleJSONEncoder, *args, **kw)
+
+
+def to_nice_json(a, indent=4, sort_keys=True, *args, **kw):
+ '''Make verbose, human readable JSON'''
+ return to_json(a, indent=indent, sort_keys=sort_keys, separators=(',', ': '), *args, **kw)
+
+
+def to_bool(a):
+ ''' return a bool for the arg '''
+ if a is None or isinstance(a, bool):
+ return a
+ if isinstance(a, string_types):
+ a = a.lower()
+ if a in ('yes', 'on', '1', 'true', 1):
+ return True
+ return False
+
+
+def to_datetime(string, format="%Y-%m-%d %H:%M:%S"):
+ return datetime.datetime.strptime(string, format)
+
+
+def strftime(string_format, second=None, utc=False):
+ ''' return a date string using string. See https://docs.python.org/3/library/time.html#time.strftime for format '''
+ if utc:
+ timefn = time.gmtime
+ else:
+ timefn = time.localtime
+ if second is not None:
+ try:
+ second = float(second)
+ except Exception:
+ raise AnsibleFilterError('Invalid value for epoch value (%s)' % second)
+ return time.strftime(string_format, timefn(second))
+
+
+def quote(a):
+ ''' return its argument quoted for shell usage '''
+ if a is None:
+ a = u''
+ return shlex.quote(to_text(a))
+
+
+def fileglob(pathname):
+ ''' return list of matched regular files for glob '''
+ return [g for g in glob.glob(pathname) if os.path.isfile(g)]
+
+
+def regex_replace(value='', pattern='', replacement='', ignorecase=False, multiline=False):
+ ''' Perform a `re.sub` returning a string '''
+
+ value = to_text(value, errors='surrogate_or_strict', nonstring='simplerepr')
+
+ flags = 0
+ if ignorecase:
+ flags |= re.I
+ if multiline:
+ flags |= re.M
+ _re = re.compile(pattern, flags=flags)
+ return _re.sub(replacement, value)
+
+
+def regex_findall(value, regex, multiline=False, ignorecase=False):
+ ''' Perform re.findall and return the list of matches '''
+
+ value = to_text(value, errors='surrogate_or_strict', nonstring='simplerepr')
+
+ flags = 0
+ if ignorecase:
+ flags |= re.I
+ if multiline:
+ flags |= re.M
+ return re.findall(regex, value, flags)
+
+
+def regex_search(value, regex, *args, **kwargs):
+ ''' Perform re.search and return the list of matches or a backref '''
+
+ value = to_text(value, errors='surrogate_or_strict', nonstring='simplerepr')
+
+ groups = list()
+ for arg in args:
+ if arg.startswith('\\g'):
+ match = re.match(r'\\g<(\S+)>', arg).group(1)
+ groups.append(match)
+ elif arg.startswith('\\'):
+ match = int(re.match(r'\\(\d+)', arg).group(1))
+ groups.append(match)
+ else:
+ raise AnsibleFilterError('Unknown argument')
+
+ flags = 0
+ if kwargs.get('ignorecase'):
+ flags |= re.I
+ if kwargs.get('multiline'):
+ flags |= re.M
+
+ match = re.search(regex, value, flags)
+ if match:
+ if not groups:
+ return match.group()
+ else:
+ items = list()
+ for item in groups:
+ items.append(match.group(item))
+ return items
+
+
+def ternary(value, true_val, false_val, none_val=None):
+ ''' value ? true_val : false_val '''
+ if value is None and none_val is not None:
+ return none_val
+ elif bool(value):
+ return true_val
+ else:
+ return false_val
+
+
+def regex_escape(string, re_type='python'):
+ 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':
+ # list of BRE special chars:
+ # https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions
+ return regex_replace(string, r'([].[^$*\\])', r'\\\1')
+ # TODO: implement posix_extended
+ # It's similar to, but different from python regex, which is similar to,
+ # but different from PCRE. It's possible that re.escape would work here.
+ # https://remram44.github.io/regex-cheatsheet/regex.html#programs
+ elif re_type == 'posix_extended':
+ raise AnsibleFilterError('Regex type (%s) not yet implemented' % re_type)
+ else:
+ raise AnsibleFilterError('Invalid regex type (%s)' % re_type)
+
+
+def from_yaml(data):
+ if isinstance(data, string_types):
+ # The ``text_type`` call here strips any custom
+ # string wrapper class, so that CSafeLoader can
+ # read the data
+ return yaml_load(text_type(to_text(data, errors='surrogate_or_strict')))
+ return data
+
+
+def from_yaml_all(data):
+ if isinstance(data, string_types):
+ # The ``text_type`` call here strips any custom
+ # string wrapper class, so that CSafeLoader can
+ # read the data
+ return yaml_load_all(text_type(to_text(data, errors='surrogate_or_strict')))
+ return data
+
+
+@pass_environment
+def rand(environment, end, start=None, step=None, seed=None):
+ if seed is None:
+ r = SystemRandom()
+ else:
+ r = Random(seed)
+ if isinstance(end, integer_types):
+ if not start:
+ start = 0
+ if not step:
+ step = 1
+ return r.randrange(start, end, step)
+ elif hasattr(end, '__iter__'):
+ if start or step:
+ raise AnsibleFilterError('start and step can only be used with integer values')
+ return r.choice(end)
+ else:
+ raise AnsibleFilterError('random can only be used on sequences and integers')
+
+
+def randomize_list(mylist, seed=None):
+ try:
+ mylist = list(mylist)
+ if seed:
+ r = Random(seed)
+ r.shuffle(mylist)
+ else:
+ shuffle(mylist)
+ except Exception:
+ pass
+ return mylist
+
+
+def get_hash(data, hashtype='sha1'):
+ try:
+ h = hashlib.new(hashtype)
+ except Exception as e:
+ # hash is not supported?
+ raise AnsibleFilterError(e)
+
+ h.update(to_bytes(data, errors='surrogate_or_strict'))
+ return h.hexdigest()
+
+
+def get_encrypted_password(password, hashtype='sha512', salt=None, salt_size=None, rounds=None, ident=None):
+ passlib_mapping = {
+ 'md5': 'md5_crypt',
+ 'blowfish': 'bcrypt',
+ 'sha256': 'sha256_crypt',
+ 'sha512': 'sha512_crypt',
+ }
+
+ hashtype = passlib_mapping.get(hashtype, hashtype)
+ try:
+ return passlib_or_crypt(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])
+
+
+def to_uuid(string, namespace=UUID_NAMESPACE_ANSIBLE):
+ uuid_namespace = namespace
+ if not isinstance(uuid_namespace, uuid.UUID):
+ try:
+ uuid_namespace = uuid.UUID(namespace)
+ except (AttributeError, ValueError) as e:
+ raise AnsibleFilterError("Invalid value '%s' for 'namespace': %s" % (to_native(namespace), to_native(e)))
+ # uuid.uuid5() requires bytes on Python 2 and bytes or text or Python 3
+ return to_text(uuid.uuid5(uuid_namespace, to_native(string, errors='surrogate_or_strict')))
+
+
+def mandatory(a, msg=None):
+ 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)
+ else:
+ name = ''
+
+ if msg is not None:
+ raise AnsibleFilterError(to_native(msg))
+ else:
+ raise AnsibleFilterError("Mandatory variable %s not defined." % name)
+
+ return a
+
+
+def combine(*terms, **kwargs):
+ recursive = kwargs.pop('recursive', False)
+ list_merge = kwargs.pop('list_merge', 'replace')
+ if kwargs:
+ raise AnsibleFilterError("'recursive' and 'list_merge' are the only valid keyword arguments")
+
+ # allow the user to do `[dict1, dict2, ...] | combine`
+ dictionaries = flatten(terms, levels=1)
+
+ # recursively check that every elements are defined (for jinja2)
+ recursive_check_defined(dictionaries)
+
+ if not dictionaries:
+ return {}
+
+ if len(dictionaries) == 1:
+ return dictionaries[0]
+
+ # merge all the dicts so that the dict at the end of the array have precedence
+ # over the dict at the beginning.
+ # we merge the dicts from the highest to the lowest priority because there is
+ # a huge probability that the lowest priority dict will be the biggest in size
+ # (as the low prio dict will hold the "default" values and the others will be "patches")
+ # and merge_hash create a copy of it's first argument.
+ # so high/right -> low/left is more efficient than low/left -> high/right
+ high_to_low_prio_dict_iterator = reversed(dictionaries)
+ result = next(high_to_low_prio_dict_iterator)
+ for dictionary in high_to_low_prio_dict_iterator:
+ result = merge_hash(dictionary, result, recursive, list_merge)
+
+ return result
+
+
+def comment(text, style='plain', **kw):
+ # Predefined comment types
+ comment_styles = {
+ 'plain': {
+ 'decoration': '# '
+ },
+ 'erlang': {
+ 'decoration': '% '
+ },
+ 'c': {
+ 'decoration': '// '
+ },
+ 'cblock': {
+ 'beginning': '/*',
+ 'decoration': ' * ',
+ 'end': ' */'
+ },
+ 'xml': {
+ 'beginning': '<!--',
+ 'decoration': ' - ',
+ 'end': '-->'
+ }
+ }
+
+ # Pointer to the right comment type
+ style_params = comment_styles[style]
+
+ if 'decoration' in kw:
+ prepostfix = kw['decoration']
+ else:
+ prepostfix = style_params['decoration']
+
+ # Default params
+ p = {
+ 'newline': '\n',
+ 'beginning': '',
+ 'prefix': (prepostfix).rstrip(),
+ 'prefix_count': 1,
+ 'decoration': '',
+ 'postfix': (prepostfix).rstrip(),
+ 'postfix_count': 1,
+ 'end': ''
+ }
+
+ # Update default params
+ p.update(style_params)
+ p.update(kw)
+
+ # Compose substrings for the final string
+ str_beginning = ''
+ if p['beginning']:
+ str_beginning = "%s%s" % (p['beginning'], p['newline'])
+ str_prefix = ''
+ if p['prefix']:
+ if p['prefix'] != p['newline']:
+ str_prefix = str(
+ "%s%s" % (p['prefix'], p['newline'])) * int(p['prefix_count'])
+ else:
+ str_prefix = str(
+ "%s" % (p['newline'])) * int(p['prefix_count'])
+ str_text = ("%s%s" % (
+ p['decoration'],
+ # Prepend each line of the text with the decorator
+ text.replace(
+ p['newline'], "%s%s" % (p['newline'], p['decoration'])))).replace(
+ # Remove trailing spaces when only decorator is on the line
+ "%s%s" % (p['decoration'], p['newline']),
+ "%s%s" % (p['decoration'].rstrip(), p['newline']))
+ str_postfix = p['newline'].join(
+ [''] + [p['postfix'] for x in range(p['postfix_count'])])
+ str_end = ''
+ if p['end']:
+ str_end = "%s%s" % (p['newline'], p['end'])
+
+ # Return the final string
+ return "%s%s%s%s%s" % (
+ str_beginning,
+ str_prefix,
+ str_text,
+ str_postfix,
+ str_end)
+
+
+@pass_environment
+def extract(environment, item, container, morekeys=None):
+ if morekeys is None:
+ keys = [item]
+ elif isinstance(morekeys, list):
+ keys = [item] + morekeys
+ else:
+ keys = [item, morekeys]
+
+ value = container
+ for key in keys:
+ value = environment.getitem(value, key)
+
+ return value
+
+
+def b64encode(string, encoding='utf-8'):
+ return to_text(base64.b64encode(to_bytes(string, encoding=encoding, errors='surrogate_or_strict')))
+
+
+def b64decode(string, encoding='utf-8'):
+ return to_text(base64.b64decode(to_bytes(string, errors='surrogate_or_strict')), encoding=encoding)
+
+
+def flatten(mylist, levels=None, skip_nulls=True):
+
+ ret = []
+ for element in mylist:
+ if skip_nulls and element in (None, 'None', 'null'):
+ # ignore null items
+ continue
+ elif is_sequence(element):
+ if levels is None:
+ ret.extend(flatten(element, skip_nulls=skip_nulls))
+ elif levels >= 1:
+ # decrement as we go down the stack
+ ret.extend(flatten(element, levels=(int(levels) - 1), skip_nulls=skip_nulls))
+ else:
+ ret.append(element)
+ else:
+ ret.append(element)
+
+ return ret
+
+
+def subelements(obj, subelements, skip_missing=False):
+ '''Accepts a dict or list of dicts, and a dotted accessor and produces a product
+ of the element and the results of the dotted accessor
+
+ >>> obj = [{"name": "alice", "groups": ["wheel"], "authorized": ["/tmp/alice/onekey.pub"]}]
+ >>> subelements(obj, 'groups')
+ [({'name': 'alice', 'groups': ['wheel'], 'authorized': ['/tmp/alice/onekey.pub']}, 'wheel')]
+
+ '''
+ if isinstance(obj, dict):
+ element_list = list(obj.values())
+ elif isinstance(obj, list):
+ element_list = obj[:]
+ else:
+ raise AnsibleFilterError('obj must be a list of dicts or a nested dict')
+
+ if isinstance(subelements, list):
+ subelement_list = subelements[:]
+ elif isinstance(subelements, string_types):
+ subelement_list = subelements.split('.')
+ else:
+ raise AnsibleFilterTypeError('subelements must be a list or a string')
+
+ results = []
+
+ for element in element_list:
+ values = element
+ for subelement in subelement_list:
+ try:
+ values = values[subelement]
+ except KeyError:
+ if skip_missing:
+ values = []
+ break
+ raise AnsibleFilterError("could not find %r key in iterated item %r" % (subelement, values))
+ except TypeError:
+ raise AnsibleFilterTypeError("the key %s should point to a dictionary, got '%s'" % (subelement, values))
+ if not isinstance(values, list):
+ raise AnsibleFilterTypeError("the key %r should point to a list, got %r" % (subelement, values))
+
+ for value in values:
+ results.append((element, value))
+
+ return results
+
+
+def dict_to_list_of_dict_key_value_elements(mydict, key_name='key', value_name='value'):
+ ''' takes a dictionary and transforms it into a list of dictionaries,
+ with each having a 'key' and 'value' keys that correspond to the keys and values of the original '''
+
+ if not isinstance(mydict, Mapping):
+ raise AnsibleFilterTypeError("dict2items requires a dictionary, got %s instead." % type(mydict))
+
+ ret = []
+ for key in mydict:
+ ret.append({key_name: key, value_name: mydict[key]})
+ return ret
+
+
+def list_of_dict_key_value_elements_to_dict(mylist, key_name='key', value_name='value'):
+ ''' takes a list of dicts with each having a 'key' and 'value' keys, and transforms the list into a dictionary,
+ effectively as the reverse of dict2items '''
+
+ if not is_sequence(mylist):
+ raise AnsibleFilterTypeError("items2dict requires a list, got %s instead." % type(mylist))
+
+ try:
+ return dict((item[key_name], item[value_name]) for item in mylist)
+ except KeyError:
+ raise AnsibleFilterTypeError(
+ "items2dict requires each dictionary in the list to contain the keys '%s' and '%s', got %s instead."
+ % (key_name, value_name, mylist)
+ )
+ except TypeError:
+ raise AnsibleFilterTypeError("items2dict requires a list of dictionaries, got %s instead." % mylist)
+
+
+def path_join(paths):
+ ''' takes a sequence or a string, and return a concatenation
+ of the different members '''
+ if isinstance(paths, string_types):
+ return os.path.join(paths)
+ elif is_sequence(paths):
+ return os.path.join(*paths)
+ else:
+ raise AnsibleFilterTypeError("|path_join expects string or sequence, got %s instead." % type(paths))
+
+
+class FilterModule(object):
+ ''' Ansible core jinja2 filters '''
+
+ def filters(self):
+ return {
+ # base 64
+ 'b64decode': b64decode,
+ 'b64encode': b64encode,
+
+ # uuid
+ 'to_uuid': to_uuid,
+
+ # json
+ 'to_json': to_json,
+ 'to_nice_json': to_nice_json,
+ 'from_json': json.loads,
+
+ # yaml
+ 'to_yaml': to_yaml,
+ 'to_nice_yaml': to_nice_yaml,
+ 'from_yaml': from_yaml,
+ 'from_yaml_all': from_yaml_all,
+
+ # path
+ 'basename': partial(unicode_wrap, os.path.basename),
+ 'dirname': partial(unicode_wrap, os.path.dirname),
+ 'expanduser': partial(unicode_wrap, os.path.expanduser),
+ 'expandvars': partial(unicode_wrap, os.path.expandvars),
+ 'path_join': path_join,
+ 'realpath': partial(unicode_wrap, os.path.realpath),
+ 'relpath': partial(unicode_wrap, os.path.relpath),
+ 'splitext': partial(unicode_wrap, os.path.splitext),
+ 'win_basename': partial(unicode_wrap, ntpath.basename),
+ 'win_dirname': partial(unicode_wrap, ntpath.dirname),
+ 'win_splitdrive': partial(unicode_wrap, ntpath.splitdrive),
+
+ # file glob
+ 'fileglob': fileglob,
+
+ # types
+ 'bool': to_bool,
+ 'to_datetime': to_datetime,
+
+ # date formatting
+ 'strftime': strftime,
+
+ # quote string for shell usage
+ 'quote': quote,
+
+ # hash filters
+ # md5 hex digest of string
+ 'md5': md5s,
+ # sha1 hex digest of string
+ 'sha1': checksum_s,
+ # checksum of string as used by ansible for checksumming files
+ 'checksum': checksum_s,
+ # generic hashing
+ 'password_hash': get_encrypted_password,
+ 'hash': get_hash,
+
+ # regex
+ 'regex_replace': regex_replace,
+ 'regex_escape': regex_escape,
+ 'regex_search': regex_search,
+ 'regex_findall': regex_findall,
+
+ # ? : ;
+ 'ternary': ternary,
+
+ # random stuff
+ 'random': rand,
+ 'shuffle': randomize_list,
+
+ # undefined
+ 'mandatory': mandatory,
+
+ # comment-style decoration
+ 'comment': comment,
+
+ # debug
+ 'type_debug': lambda o: o.__class__.__name__,
+
+ # Data structures
+ 'combine': combine,
+ 'extract': extract,
+ 'flatten': flatten,
+ 'dict2items': dict_to_list_of_dict_key_value_elements,
+ 'items2dict': list_of_dict_key_value_elements_to_dict,
+ 'subelements': subelements,
+ 'split': partial(unicode_wrap, text_type.split),
+ }
diff --git a/lib/ansible/plugins/filter/dict2items.yml b/lib/ansible/plugins/filter/dict2items.yml
new file mode 100644
index 0000000..aa51826
--- /dev/null
+++ b/lib/ansible/plugins/filter/dict2items.yml
@@ -0,0 +1,45 @@
+DOCUMENTATION:
+ name: dict2items
+ author: Ansible core team
+ version_added: "2.6"
+ short_description: Convert a dictionary into an itemized list of dictionaries
+ positional: _input, key_name, value_name
+ description:
+ - Takes a dictionary and transforms it into a list of dictionaries, with each having a
+ C(key) and C(value) keys that correspond to the keys and values of the original.
+ options:
+ _input:
+ description:
+ - The dictionary to transform
+ type: dict
+ required: true
+ key_name:
+ description: The name of the property on the item representing the dictionary's keys.
+ type: str
+ default: key
+ version_added: "2.8"
+ value_name:
+ description: The name of the property on the item representing the dictionary's values.
+ type: str
+ default: value
+ version_added: "2.8"
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.items2dict
+
+EXAMPLES: |
+
+ # items => [ { "key": "a", "value": 1 }, { "key": "b", "value": 2 } ]
+ items: "{{ {'a': 1, 'b': 2}| dict2items}}"
+
+ vars:
+ files:
+ users: /etc/passwd
+ groups: /etc/group
+ files_dicts: "{{ files | dict2items(key_name='file', value_name='path') }}"
+
+RETURN:
+ _value:
+ description: A list of dictionaries.
+ type: list
+ elements: dict
diff --git a/lib/ansible/plugins/filter/difference.yml b/lib/ansible/plugins/filter/difference.yml
new file mode 100644
index 0000000..decc811
--- /dev/null
+++ b/lib/ansible/plugins/filter/difference.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: difference
+ author: Brian Coca (@bcoca)
+ version_added: "1.4"
+ short_description: the difference of one list from another
+ description:
+ - Provide a unique list of all the elements of the first list that do not appear in the second one.
+ options:
+ _input:
+ description: A list.
+ type: list
+ required: true
+ _second_list:
+ description: A list.
+ type: list
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.intersect
+ - plugin_type: filter
+ plugin: ansible.builtin.symmetric_difference
+ - plugin_type: filter
+ plugin: ansible.builtin.union
+ - plugin_type: filter
+ plugin: ansible.builtin.unique
+EXAMPLES: |
+ # return the elements of list1 not in list2
+ # list1: [1, 2, 5, 1, 3, 4, 10]
+ # list2: [1, 2, 3, 4, 5, 11, 99]
+ {{ list1 | difference(list2) }}
+ # => [10]
+RETURN:
+ _value:
+ description: A unique list of the elements from the first list that do not appear on the second.
+ type: list
diff --git a/lib/ansible/plugins/filter/dirname.yml b/lib/ansible/plugins/filter/dirname.yml
new file mode 100644
index 0000000..52f7d5d
--- /dev/null
+++ b/lib/ansible/plugins/filter/dirname.yml
@@ -0,0 +1,24 @@
+DOCUMENTATION:
+ name: dirname
+ author: ansible core team
+ version_added: "historical"
+ short_description: get a path's directory name
+ description:
+ - Returns the 'head' component of a path, basically everything that is not the 'basename'.
+ options:
+ _input:
+ description: A path.
+ type: path
+ required: true
+ seealso:
+ - plugin: ansible.builtin.basename
+ plugin_type: filter
+EXAMPLES: |
+
+ # To get the dir name of a file path, like '/etc/asdf' out of '/etc/asdf/foo.txt'
+ {{ mypath | dirname }}
+
+RETURN:
+ _value:
+ description: The directory portion of the original path.
+ type: path
diff --git a/lib/ansible/plugins/filter/encryption.py b/lib/ansible/plugins/filter/encryption.py
new file mode 100644
index 0000000..b6f4961
--- /dev/null
+++ b/lib/ansible/plugins/filter/encryption.py
@@ -0,0 +1,82 @@
+# Copyright: (c) 2021, Ansible Project
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from jinja2.runtime import Undefined
+from jinja2.exceptions import UndefinedError
+
+from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError
+from ansible.module_utils._text import to_native, to_bytes
+from ansible.module_utils.six import string_types, binary_type
+from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
+from ansible.parsing.vault import is_encrypted, VaultSecret, VaultLib
+from ansible.utils.display import Display
+
+display = Display()
+
+
+def do_vault(data, secret, salt=None, vaultid='filter_default', wrap_object=False):
+
+ if not isinstance(secret, (string_types, binary_type, Undefined)):
+ raise AnsibleFilterTypeError("Secret passed is required to be a string, instead we got: %s" % type(secret))
+
+ if not isinstance(data, (string_types, binary_type, Undefined)):
+ raise AnsibleFilterTypeError("Can only vault strings, instead we got: %s" % type(data))
+
+ vault = ''
+ vs = VaultSecret(to_bytes(secret))
+ vl = VaultLib()
+ try:
+ vault = vl.encrypt(to_bytes(data), vs, vaultid, salt)
+ except UndefinedError:
+ raise
+ except Exception as e:
+ raise AnsibleFilterError("Unable to encrypt: %s" % to_native(e), orig_exc=e)
+
+ if wrap_object:
+ vault = AnsibleVaultEncryptedUnicode(vault)
+ else:
+ vault = to_native(vault)
+
+ return vault
+
+
+def do_unvault(vault, secret, vaultid='filter_default'):
+
+ if not isinstance(secret, (string_types, binary_type, Undefined)):
+ raise AnsibleFilterTypeError("Secret passed is required to be as string, instead we got: %s" % type(secret))
+
+ if not isinstance(vault, (string_types, binary_type, AnsibleVaultEncryptedUnicode, Undefined)):
+ raise AnsibleFilterTypeError("Vault should be in the form of a string, instead we got: %s" % type(vault))
+
+ data = ''
+ vs = VaultSecret(to_bytes(secret))
+ vl = VaultLib([(vaultid, vs)])
+ if isinstance(vault, AnsibleVaultEncryptedUnicode):
+ vault.vault = vl
+ data = vault.data
+ elif is_encrypted(vault):
+ try:
+ data = vl.decrypt(vault)
+ except UndefinedError:
+ raise
+ except Exception as e:
+ raise AnsibleFilterError("Unable to decrypt: %s" % to_native(e), orig_exc=e)
+ else:
+ data = vault
+
+ return to_native(data)
+
+
+class FilterModule(object):
+ ''' Ansible vault jinja2 filters '''
+
+ def filters(self):
+ filters = {
+ 'vault': do_vault,
+ 'unvault': do_unvault,
+ }
+
+ return filters
diff --git a/lib/ansible/plugins/filter/expanduser.yml b/lib/ansible/plugins/filter/expanduser.yml
new file mode 100644
index 0000000..2aff468
--- /dev/null
+++ b/lib/ansible/plugins/filter/expanduser.yml
@@ -0,0 +1,21 @@
+DOCUMENTATION:
+ name: basename
+ author: ansible core team
+ version_added: "1.5"
+ short_description: Returns a path with C(~) translation.
+ description:
+ - Translates C(~) in a path to the proper user's home directory.
+ options:
+ _input:
+ description: A string that contains a path.
+ type: path
+ required: true
+EXAMPLES: |
+
+ # To get '/home/myuser/stuff.txt' from '~/stuff.txt'.
+ {{ mypath | expanduser }}
+
+RETURN:
+ _value:
+ description: The translated path.
+ type: path
diff --git a/lib/ansible/plugins/filter/expandvars.yml b/lib/ansible/plugins/filter/expandvars.yml
new file mode 100644
index 0000000..02c201e
--- /dev/null
+++ b/lib/ansible/plugins/filter/expandvars.yml
@@ -0,0 +1,21 @@
+DOCUMENTATION:
+ name: expandvars
+ author: ansible core team
+ version_added: "1.5"
+ short_description: expand environment variables
+ description:
+ - Will do a shell-like substitution of environment variables on the provided input.
+ options:
+ _input:
+ description: A string that contains environment variables.
+ type: str
+ required: true
+EXAMPLES: |
+
+ # To get '/home/myuser/stuff.txt' from '$HOME/stuff.txt'
+ {{ mypath | expandvars }}
+
+RETURN:
+ _value:
+ description: The string with translated environment variable values.
+ type: str
diff --git a/lib/ansible/plugins/filter/extract.yml b/lib/ansible/plugins/filter/extract.yml
new file mode 100644
index 0000000..2b4989d
--- /dev/null
+++ b/lib/ansible/plugins/filter/extract.yml
@@ -0,0 +1,39 @@
+DOCUMENTATION:
+ name: extract
+ version_added: "2.1"
+ short_description: extract a value based on an index or key
+ description:
+ - Extract a value from a list or dictionary based on an index/key.
+ - User must ensure that index or key used matches the type of container.
+ - Equivalent of using C(list[index]) and C(dictionary[key]) but useful as a filter to combine with C(map).
+ positional: _input, container, morekeys
+ options:
+ _input:
+ description: Index or key to extract.
+ type: raw
+ required: true
+ contianer:
+ description: Dictionary or list from which to extract a value.
+ type: raw
+ required: true
+ morekeys:
+ description: Indicies or keys to extract from the initial result (subkeys/subindices).
+ type: list
+ elements: dictionary
+ required: true
+
+EXAMPLES: |
+
+ # extracted => 'b', same as ['a', 'b', 'c'][1]
+ extracted: "{{ 1 | extract(['a', 'b', 'c']) }}"
+
+ # extracted_key => '2', same as {'a': 1, 'b': 2, 'c': 3}['b']
+ extracted_key: "{{ 'b' | extract({'a': 1, 'b': 2, 'c': 3}) }}"
+
+ # extracted_key_r => '2', same as [{'a': 1, 'b': 2, 'c': 3}, {'x': 9, 'y': 10}][0]['b']
+ extracted_key_r: "{{ 0 | extract([{'a': 1, 'b': 2, 'c': 3}, {'x': 9, 'y': 10}], morekeys='b') }}"
+
+RETURN:
+ _value:
+ description: Resulting merge of supplied dictionaries.
+ type: dict
diff --git a/lib/ansible/plugins/filter/fileglob.yml b/lib/ansible/plugins/filter/fileglob.yml
new file mode 100644
index 0000000..69e8a9b
--- /dev/null
+++ b/lib/ansible/plugins/filter/fileglob.yml
@@ -0,0 +1,22 @@
+DOCUMENTATION:
+ name: fileglob
+ short_description: explode a path glob to matching files
+ description:
+ - Return a list of files that matches the supplied path glob pattern.
+ - Filters run on the controller, so the files are matched from the controller's file system.
+ positional: _input
+ options:
+ _input:
+ description: Path glob pattern.
+ type: string
+ required: true
+
+EXAMPLES: |
+ # found = ['/etc/hosts', '/etc/hasts']
+ found: "{{ '/etc/h?sts' | fileglob }}"
+
+RETURN:
+ _value:
+ description: List of files matched.
+ type: list
+ elements: string
diff --git a/lib/ansible/plugins/filter/flatten.yml b/lib/ansible/plugins/filter/flatten.yml
new file mode 100644
index 0000000..b909c3d
--- /dev/null
+++ b/lib/ansible/plugins/filter/flatten.yml
@@ -0,0 +1,32 @@
+DOCUMENTATION:
+ name: flatten
+ version_added: "2.5"
+ short_description: flatten lists within a list
+ description:
+ - For a given list, take any elements that are lists and insert their elements into the parent list directly.
+ positional: _input, levels, skip_nulls
+ options:
+ _input:
+ description: First dictionary to combine.
+ type: dict
+ required: true
+ levels:
+ description: Number of recursive list depths to flatten.
+ type: int
+ skip_nulls:
+ description: Skip C(null)/C(None) elements when inserting into the top list.
+ type: bool
+ default: true
+
+EXAMPLES: |
+
+ # [1,2,3,4,5,6]
+ flat: "{{ [1 , 2, [3, [4, 5]], 6] | flatten }}"
+
+ # [1,2,3,[4,5],6]
+ flatone: "{{ [1, 2, [3, [4, 5]], 6] | flatten(1) }}"
+
+RETURN:
+ _value:
+ description: The flattened list.
+ type: list
diff --git a/lib/ansible/plugins/filter/from_json.yml b/lib/ansible/plugins/filter/from_json.yml
new file mode 100644
index 0000000..4edc2bd
--- /dev/null
+++ b/lib/ansible/plugins/filter/from_json.yml
@@ -0,0 +1,25 @@
+DOCUMENTATION:
+ name: from_json
+ version_added: 'historical'
+ short_description: Convert JSON string into variable structure
+ description:
+ - Converts a JSON string representation into an equivalent structured Ansible variable.
+ - Ansible automatically converts JSON strings into variable structures in most contexts, use this plugin in contexts where automatic conversion does not happen.
+ notes:
+ - This filter functions as a wrapper to the Python C(json.loads) function.
+ options:
+ _input:
+ description: A JSON string.
+ type: string
+ required: true
+EXAMPLES: |
+ # variable from string variable containing a JSON document
+ {{ docker_config | from_json }}
+
+ # variable from string JSON document
+ {{ '{"a": true, "b": 54, "c": [1,2,3]}' | from_json }}
+
+RETURN:
+ _value:
+ description: The variable resulting from deserialization of the JSON document.
+ type: raw
diff --git a/lib/ansible/plugins/filter/from_yaml.yml b/lib/ansible/plugins/filter/from_yaml.yml
new file mode 100644
index 0000000..e9b1599
--- /dev/null
+++ b/lib/ansible/plugins/filter/from_yaml.yml
@@ -0,0 +1,25 @@
+DOCUMENTATION:
+ name: from_yaml
+ version_added: 'historical'
+ short_description: Convert YAML string into variable structure
+ description:
+ - Converts a YAML string representation into an equivalent structured Ansible variable.
+ - Ansible automatically converts YAML strings into variable structures in most contexts, use this plugin in contexts where automatic conversion does not happen.
+ notes:
+ - This filter functions as a wrapper to the L(Python pyyaml library, https://pypi.org/project/PyYAML/)'s C(yaml.safe_load) function.
+ options:
+ _input:
+ description: A YAML string.
+ type: string
+ required: true
+EXAMPLES: |
+ # variable from string variable containing a YAML document
+ {{ github_workflow | from_yaml}}
+
+ # variable from string JSON document
+ {{ '{"a": true, "b": 54, "c": [1,2,3]}' | from_yaml }}
+
+RETURN:
+ _value:
+ description: The variable resulting from deserializing the YAML document.
+ type: raw
diff --git a/lib/ansible/plugins/filter/from_yaml_all.yml b/lib/ansible/plugins/filter/from_yaml_all.yml
new file mode 100644
index 0000000..b179f1c
--- /dev/null
+++ b/lib/ansible/plugins/filter/from_yaml_all.yml
@@ -0,0 +1,28 @@
+DOCUMENTATION:
+ name: from_yaml_all
+ version_added: 'historical'
+ short_description: Convert a series of YAML documents into a variable structure
+ description:
+ - Converts a YAML documents in a string representation into an equivalent structured Ansible variable.
+ - Ansible internally auto-converts YAML strings into variable structures in most contexts, but by default does not handle 'multi document' YAML files or strings.
+ - If multiple YAML documents are not supplied, this is the equivalend of using C(from_yaml).
+ notes:
+ - This filter functions as a wrapper to the Python C(yaml.safe_load_all) function, part of the L(pyyaml Python library, https://pypi.org/project/PyYAML/).
+ - Possible conflicts in variable names from the mulitple documents are resolved directly by the pyyaml library.
+ options:
+ _input:
+ description: A YAML string.
+ type: string
+ required: true
+
+EXAMPLES: |
+ # variable from string variable containing YAML documents
+ {{ multidoc_yaml_string | from_yaml_all }}
+
+ # variable from multidocument YAML string
+ {{ '---\n{"a": true, "b": 54, "c": [1,2,3]}\n...\n---{"x": 1}\n...\n' | from_yaml_all}}
+
+RETURN:
+ _value:
+ description: The variable resulting from deserializing the YAML documents.
+ type: raw
diff --git a/lib/ansible/plugins/filter/hash.yml b/lib/ansible/plugins/filter/hash.yml
new file mode 100644
index 0000000..0f5f315
--- /dev/null
+++ b/lib/ansible/plugins/filter/hash.yml
@@ -0,0 +1,28 @@
+DOCUMENTATION:
+ name: checksum
+ version_added: "1.9"
+ short_description: hash of input data
+ description:
+ - Returns a configurable hash of the input data. Uses L(SHA-1, https://en.wikipedia.org/wiki/SHA-1) by default.
+ positional: _input
+ options:
+ _input:
+ description: Data to checksum.
+ type: raw
+ required: true
+ hashtype:
+ description:
+ - Type of algorithm to produce the hash.
+ - The list of available choices depends on the installed Python's hashlib.
+ type: string
+ default: sha1
+EXAMPLES: |
+ # sha1_hash => "109f4b3c50d7b0df729d299bc6f8e9ef9066971f"
+ sha1_hash: {{ 'test2' | hash('sha1') }}
+ # md5 => "5a105e8b9d40e1329780d62ea2265d8a"
+ md5: {{ 'test2' | hash('md5') }}
+
+RETURN:
+ _value:
+ description: The checksum of the input, as configured in I(hashtype).
+ type: string
diff --git a/lib/ansible/plugins/filter/human_readable.yml b/lib/ansible/plugins/filter/human_readable.yml
new file mode 100644
index 0000000..e3028ac
--- /dev/null
+++ b/lib/ansible/plugins/filter/human_readable.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: human_redable
+ version_added: "historical"
+ short_description: Make bytes/bits human readable
+ description:
+ - Convert byte or bit figures to more human readable formats.
+ positional: _input, isbits, unit
+ options:
+ _input:
+ description: Number of bytes, or bits. Depends on I(isbits).
+ type: int
+ required: true
+ isbits:
+ description: Whether the input is bits, instead of bytes.
+ type: bool
+ default: false
+ unit:
+ description: Unit to force output into. If none specified the largest unit arrived at will be used.
+ type: str
+ choices: [ 'Y', 'Z', 'E', 'P', 'T', 'G', 'M', 'K', 'B']
+EXAMPLES: |
+
+ # size => "1.15 GB"
+ size: "{{ 1232345345 | human_readable }}"
+
+ # size => "1.15 Gb"
+ size_bits: "{{ 1232345345 | human_readable(true) }}"
+
+ # size => "1175.26 MB"
+ size_MB: "{{ 1232345345 | human_readable(unit='M') }}"
+
+RETURN:
+ _value:
+ description: Human readable byte or bit size.
+ type: str
diff --git a/lib/ansible/plugins/filter/human_to_bytes.yml b/lib/ansible/plugins/filter/human_to_bytes.yml
new file mode 100644
index 0000000..f03deed
--- /dev/null
+++ b/lib/ansible/plugins/filter/human_to_bytes.yml
@@ -0,0 +1,34 @@
+DOCUMENTATION:
+ name: human_to_bytes
+ version_added: "historical"
+ short_description: Get bytes from string
+ description:
+ - Convert a human readable byte or bit string into a number bytes.
+ positional: _input, default_unit, isbits
+ options:
+ _input:
+ description: Human readable description of a number of bytes.
+ type: int
+ required: true
+ default_unit:
+ description: Unit to assume when input does not specify it.
+ type: str
+ choices: ['Y', 'Z', 'E', 'P', 'T', 'G', 'M', 'K', 'B']
+ isbits:
+ description: If C(True), force to interpret only bit input; if C(False), force bytes. Otherwise use the notation to guess.
+ type: bool
+EXAMPLES: |
+
+ # size => 1234803098
+ size: '{{ "1.15 GB" | human_to_bytes }}'
+
+ # size => 1234803098
+ size: '{{ "1.15" | human_to_bytes(deafult_unit="G") }}'
+
+ # this is an error, wants bits, got bytes
+ ERROR: '{{ "1.15 GB" | human_to_bytes(isbits=true) }}'
+
+RETURN:
+ _value:
+ description: Integer representing the bytes from the input.
+ type: int
diff --git a/lib/ansible/plugins/filter/intersect.yml b/lib/ansible/plugins/filter/intersect.yml
new file mode 100644
index 0000000..d811eca
--- /dev/null
+++ b/lib/ansible/plugins/filter/intersect.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: intersect
+ author: Brian Coca (@bcoca)
+ version_added: "1.4"
+ short_description: intersection of lists
+ description:
+ - Provide a list with the common elements from other lists.
+ options:
+ _input:
+ description: A list.
+ type: list
+ required: true
+ _second_list:
+ description: A list.
+ type: list
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.difference
+ - plugin_type: filter
+ plugin: ansible.builtin.symmetric_difference
+ - plugin_type: filter
+ plugin: ansible.builtin.unique
+ - plugin_type: filter
+ plugin: ansible.builtin.union
+EXAMPLES: |
+ # return only the common elements of list1 and list2
+ # list1: [1, 2, 5, 3, 4, 10]
+ # list2: [1, 2, 3, 4, 5, 11, 99]
+ {{ list1 | intersect(list2) }}
+ # => [1, 2, 5, 3, 4]
+RETURN:
+ _value:
+ description: A list with unique elements common to both lists, also known as a set.
+ type: list
diff --git a/lib/ansible/plugins/filter/items2dict.yml b/lib/ansible/plugins/filter/items2dict.yml
new file mode 100644
index 0000000..1352c67
--- /dev/null
+++ b/lib/ansible/plugins/filter/items2dict.yml
@@ -0,0 +1,48 @@
+DOCUMENTATION:
+ name: items2dict
+ author: Ansible core team
+ version_added: "2.7"
+ short_description: Consolidate a list of itemized dictionaries into a dictionary
+ positional: _input, key_name, value_name
+ description:
+ - Takes a list of dicts with each having a C(key) and C(value) keys, and transforms the list into a dictionary,
+ effectively as the reverse of R(dict2items,ansible_collections.ansible.builtin.dict2items_filter).
+ options:
+ _input:
+ description:
+ - A list of dictionaries.
+ - Every dictionary must have keys C(key) and C(value).
+ type: list
+ elements: dict
+ required: true
+ key_name:
+ description: The name of the key in the element dictionaries that holds the key to use at destination.
+ type: str
+ default: key
+ value_name:
+ description: The name of the key in the element dictionaries that holds the value to use at destination.
+ type: str
+ default: value
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.dict2items
+
+EXAMPLES: |
+ # mydict => { "hi": "bye", "ciao": "ciao" }
+ mydict: {{ [{'key': 'hi', 'value': 'bye'}, {'key': 'ciao', 'value': 'ciao'} ]| items2dict}}
+
+ # The output is a dictionary with two key/value pairs:
+ # Application: payment
+ # Environment: dev
+ vars:
+ tags:
+ - key: Application
+ value: payment
+ - key: Environment
+ value: dev
+ consolidated: "{{ tags | items2dict }}"
+
+RETURN:
+ _value:
+ description: Dictionary with the consolidated key/values.
+ type: dict
diff --git a/lib/ansible/plugins/filter/log.yml b/lib/ansible/plugins/filter/log.yml
new file mode 100644
index 0000000..c7bb704
--- /dev/null
+++ b/lib/ansible/plugins/filter/log.yml
@@ -0,0 +1,33 @@
+DOCUMENTATION:
+ name: log
+ version_added: "1.9"
+ short_description: log of (math operation)
+ description:
+ - Math operation that returns the L(logarithm, https://en.wikipedia.org/wiki/Logarithm) to base N of the input number.
+ - By default, computes the L(natural logarithm, https://en.wikipedia.org/wiki/Natural_logarithm).
+ notes:
+ - This is a passthrough to Python's C(math.log).
+ positional: _input, base
+ options:
+ _input:
+ description: Number to operate on.
+ type: float
+ required: true
+ base:
+ description: Which base to use. Defaults to L(Euler's number, https://en.wikipedia.org/wiki/Euler%27s_number).
+ type: float
+ default: 2.718281828459045
+
+EXAMPLES: |
+
+ # 1.2920296742201791
+ eightlogfive: "{{ 8 | log(5) }}"
+
+ # 0.9030899869919435
+ eightlog10: "{{ 8 | log() }}"
+
+
+RETURN:
+ _value:
+ description: Resulting number.
+ type: float
diff --git a/lib/ansible/plugins/filter/mandatory.yml b/lib/ansible/plugins/filter/mandatory.yml
new file mode 100644
index 0000000..5addf15
--- /dev/null
+++ b/lib/ansible/plugins/filter/mandatory.yml
@@ -0,0 +1,21 @@
+DOCUMENTATION:
+ name: mandatory
+ version_added: "historical"
+ short_description: make a variable's existance mandatory
+ description:
+ - Depending on context undefined variables can be ignored or skipped, this ensures they force an error.
+ positional: _input
+ options:
+ _input:
+ description: Mandatory expression.
+ type: raw
+ required: true
+EXAMPLES: |
+
+ # results in a Filter Error
+ {{ notdefined | mandatory }}
+
+RETURN:
+ _value:
+ description: The input if defined, otherwise an error.
+ type: raw
diff --git a/lib/ansible/plugins/filter/mathstuff.py b/lib/ansible/plugins/filter/mathstuff.py
new file mode 100644
index 0000000..d4b6af7
--- /dev/null
+++ b/lib/ansible/plugins/filter/mathstuff.py
@@ -0,0 +1,252 @@
+# Copyright 2014, Brian Coca <bcoca@ansible.com>
+# Copyright 2017, Ken Celenza <ken@networktocode.com>
+# Copyright 2017, Jason Edelman <jason@networktocode.com>
+# Copyright 2017, Ansible Project
+#
+# 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 itertools
+import math
+
+from collections.abc import Hashable, Mapping, Iterable
+
+from jinja2.filters import pass_environment
+
+from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError
+from ansible.module_utils.common.text import formatters
+from ansible.module_utils.six import binary_type, text_type
+from ansible.module_utils._text import to_native, to_text
+from ansible.utils.display import Display
+
+try:
+ from jinja2.filters import do_unique
+ HAS_UNIQUE = True
+except ImportError:
+ HAS_UNIQUE = False
+
+
+display = Display()
+
+
+@pass_environment
+# Use case_sensitive=None as a sentinel value, so we raise an error only when
+# explicitly set and cannot be handle (by Jinja2 w/o 'unique' or fallback version)
+def unique(environment, a, case_sensitive=None, attribute=None):
+
+ def _do_fail(e):
+ if case_sensitive is False or attribute:
+ raise AnsibleFilterError("Jinja2's unique filter failed and we cannot fall back to Ansible's version "
+ "as it does not support the parameters supplied", orig_exc=e)
+
+ error = e = None
+ try:
+ if HAS_UNIQUE:
+ c = list(do_unique(environment, a, case_sensitive=bool(case_sensitive), attribute=attribute))
+ except TypeError as e:
+ error = e
+ _do_fail(e)
+ except Exception as e:
+ error = e
+ _do_fail(e)
+ display.warning('Falling back to Ansible unique filter as Jinja2 one failed: %s' % to_text(e))
+
+ if not HAS_UNIQUE or error:
+
+ # handle Jinja2 specific attributes when using Ansible's version
+ if case_sensitive is False or attribute:
+ raise AnsibleFilterError("Ansible's unique filter does not support case_sensitive=False nor attribute parameters, "
+ "you need a newer version of Jinja2 that provides their version of the filter.")
+
+ c = []
+ for x in a:
+ if x not in c:
+ c.append(x)
+
+ return c
+
+
+@pass_environment
+def intersect(environment, a, b):
+ if isinstance(a, Hashable) and isinstance(b, Hashable):
+ c = set(a) & set(b)
+ else:
+ c = unique(environment, [x for x in a if x in b], True)
+ return c
+
+
+@pass_environment
+def difference(environment, a, b):
+ if isinstance(a, Hashable) and isinstance(b, Hashable):
+ c = set(a) - set(b)
+ else:
+ c = unique(environment, [x for x in a if x not in b], True)
+ return c
+
+
+@pass_environment
+def symmetric_difference(environment, a, b):
+ if isinstance(a, Hashable) and isinstance(b, Hashable):
+ c = set(a) ^ set(b)
+ else:
+ isect = intersect(environment, a, b)
+ c = [x for x in union(environment, a, b) if x not in isect]
+ return c
+
+
+@pass_environment
+def union(environment, a, b):
+ if isinstance(a, Hashable) and isinstance(b, Hashable):
+ c = set(a) | set(b)
+ else:
+ c = unique(environment, a + b, True)
+ return c
+
+
+def logarithm(x, base=math.e):
+ try:
+ if base == 10:
+ return math.log10(x)
+ else:
+ return math.log(x, base)
+ except TypeError as e:
+ raise AnsibleFilterTypeError('log() can only be used on numbers: %s' % to_native(e))
+
+
+def power(x, y):
+ try:
+ return math.pow(x, y)
+ except TypeError as e:
+ raise AnsibleFilterTypeError('pow() can only be used on numbers: %s' % to_native(e))
+
+
+def inversepower(x, base=2):
+ try:
+ if base == 2:
+ return math.sqrt(x)
+ else:
+ return math.pow(x, 1.0 / float(base))
+ except (ValueError, TypeError) as e:
+ raise AnsibleFilterTypeError('root() can only be used on numbers: %s' % to_native(e))
+
+
+def human_readable(size, isbits=False, unit=None):
+ ''' Return a human readable string '''
+ try:
+ return formatters.bytes_to_human(size, isbits, unit)
+ except TypeError as e:
+ raise AnsibleFilterTypeError("human_readable() failed on bad input: %s" % to_native(e))
+ except Exception:
+ raise AnsibleFilterError("human_readable() can't interpret following string: %s" % size)
+
+
+def human_to_bytes(size, default_unit=None, isbits=False):
+ ''' Return bytes count from a human readable string '''
+ try:
+ return formatters.human_to_bytes(size, default_unit, isbits)
+ except TypeError as e:
+ raise AnsibleFilterTypeError("human_to_bytes() failed on bad input: %s" % to_native(e))
+ except Exception:
+ raise AnsibleFilterError("human_to_bytes() can't interpret following string: %s" % size)
+
+
+def rekey_on_member(data, key, duplicates='error'):
+ """
+ Rekey a dict of dicts on another member
+
+ May also create a dict from a list of dicts.
+
+ duplicates can be one of ``error`` or ``overwrite`` to specify whether to error out if the key
+ value would be duplicated or to overwrite previous entries if that's the case.
+ """
+ if duplicates not in ('error', 'overwrite'):
+ raise AnsibleFilterError("duplicates parameter to rekey_on_member has unknown value: {0}".format(duplicates))
+
+ new_obj = {}
+
+ # Ensure the positional args are defined - raise jinja2.exceptions.UndefinedError if not
+ bool(data) and bool(key)
+
+ if isinstance(data, Mapping):
+ iterate_over = data.values()
+ elif isinstance(data, Iterable) and not isinstance(data, (text_type, binary_type)):
+ iterate_over = data
+ else:
+ raise AnsibleFilterTypeError("Type is not a valid list, set, or dict")
+
+ for item in iterate_over:
+ if not isinstance(item, Mapping):
+ raise AnsibleFilterTypeError("List item is not a valid dict")
+
+ try:
+ key_elem = item[key]
+ except KeyError:
+ raise AnsibleFilterError("Key {0} was not found".format(key))
+ except TypeError as e:
+ raise AnsibleFilterTypeError(to_native(e))
+ except Exception as e:
+ raise AnsibleFilterError(to_native(e))
+
+ # Note: if new_obj[key_elem] exists it will always be a non-empty dict (it will at
+ # minimum contain {key: key_elem}
+ if new_obj.get(key_elem, None):
+ if duplicates == 'error':
+ raise AnsibleFilterError("Key {0} is not unique, cannot correctly turn into dict".format(key_elem))
+ elif duplicates == 'overwrite':
+ new_obj[key_elem] = item
+ else:
+ new_obj[key_elem] = item
+
+ return new_obj
+
+
+class FilterModule(object):
+ ''' Ansible math jinja2 filters '''
+
+ def filters(self):
+ filters = {
+ # exponents and logarithms
+ 'log': logarithm,
+ 'pow': power,
+ 'root': inversepower,
+
+ # set theory
+ 'unique': unique,
+ 'intersect': intersect,
+ 'difference': difference,
+ 'symmetric_difference': symmetric_difference,
+ 'union': union,
+
+ # combinatorial
+ 'product': itertools.product,
+ 'permutations': itertools.permutations,
+ 'combinations': itertools.combinations,
+
+ # computer theory
+ 'human_readable': human_readable,
+ 'human_to_bytes': human_to_bytes,
+ 'rekey_on_member': rekey_on_member,
+
+ # zip
+ 'zip': zip,
+ 'zip_longest': itertools.zip_longest,
+
+ }
+
+ return filters
diff --git a/lib/ansible/plugins/filter/md5.yml b/lib/ansible/plugins/filter/md5.yml
new file mode 100644
index 0000000..c97870d
--- /dev/null
+++ b/lib/ansible/plugins/filter/md5.yml
@@ -0,0 +1,24 @@
+DOCUMENTATION:
+ name: md5
+ version_added: "historical"
+ short_description: MD5 hash of input data
+ description:
+ - Returns an L(MD5 hash, https://en.wikipedia.org/wiki/MD5) of the input data
+ positional: _input
+ notes:
+ - This requires the MD5 algorithm to be available on the system, security contexts like FIPS might prevent this.
+ - MD5 has long been deemed insecure and is not recommended for security related uses.
+ options:
+ _input:
+ description: data to hash
+ type: raw
+ required: true
+
+EXAMPLES: |
+ # md5hash => "ae2b1fca515949e5d54fb22b8ed95575"
+ md5hash: "{{ 'testing' | md5 }}"
+
+RETURN:
+ _value:
+ description: The MD5 hash of the input.
+ type: string
diff --git a/lib/ansible/plugins/filter/password_hash.yml b/lib/ansible/plugins/filter/password_hash.yml
new file mode 100644
index 0000000..d12efb4
--- /dev/null
+++ b/lib/ansible/plugins/filter/password_hash.yml
@@ -0,0 +1,37 @@
+DOCUMENTATION:
+ name: password_hash
+ version_added: "historical"
+ short_description: convert input password into password_hash
+ description:
+ - Returns a password_hash of a secret.
+ positional: _input
+ notes:
+ - Algorithms available might be restricted by the system.
+ options:
+ _input:
+ description: Secret to hash.
+ type: string
+ required: true
+ hashtype:
+ description: Hashing algorithm to use.
+ type: string
+ default: sha512
+ choices: [ md5, blowfish, sha256, sha512 ]
+ salt:
+ description: Secret string that is used for the hashing, if none is provided a random one can be generated.
+ type: int
+ rounds:
+ description: Number of encryption rounds, default varies by algorithm used.
+ type: int
+ ident:
+ description: Algorithm identifier.
+ type: string
+
+EXAMPLES: |
+ # pwdhash => "$6$/bQCntzQ7VrgVcFa$VaMkmevkY1dqrx8neaenUDlVU.6L/.ojRbrnI4ID.yBHU6XON1cB422scCiXfUL5wRucMdLgJU0Fn38uoeBni/"
+ pwdhash: "{{ 'testing' | password_hash }}"
+
+RETURN:
+ _value:
+ description: The resulting password hash.
+ type: string
diff --git a/lib/ansible/plugins/filter/path_join.yml b/lib/ansible/plugins/filter/path_join.yml
new file mode 100644
index 0000000..d50deaa
--- /dev/null
+++ b/lib/ansible/plugins/filter/path_join.yml
@@ -0,0 +1,30 @@
+DOCUMENTATION:
+ name: path_join
+ author: Anthony Bourguignon (@Toniob)
+ version_added: "2.10"
+ short_description: Join one or more path components
+ positional: _input
+ description:
+ - Returns a path obtained by joining one or more path components.
+ options:
+ _input:
+ description: A path, or a list of paths.
+ type: list
+ elements: str
+ required: true
+
+EXAMPLES: |
+
+ # If path == 'foo/bar' and file == 'baz.txt', the result is '/etc/foo/bar/subdir/baz.txt'
+ {{ ('/etc', path, 'subdir', file) | path_join }}
+
+ # equivalent to '/etc/subdir/{{filename}}'
+ wheremyfile: "{{ ['/etc', 'subdir', filename] | path_join }}"
+
+ # trustme => '/etc/apt/trusted.d/mykey.gpgp'
+ trustme: "{{ ['/etc', 'apt', 'trusted.d', 'mykey.gpg'] | path_join }}"
+
+RETURN:
+ _value:
+ description: The concatenated path.
+ type: str
diff --git a/lib/ansible/plugins/filter/permutations.yml b/lib/ansible/plugins/filter/permutations.yml
new file mode 100644
index 0000000..6e0202b
--- /dev/null
+++ b/lib/ansible/plugins/filter/permutations.yml
@@ -0,0 +1,26 @@
+DOCUMENTATION:
+ name: permutations
+ version_added: "historical"
+ short_description: permutations from the elements of a list
+ description:
+ - Create a list of the permutations of lists from the elements of a list.
+ - Unlike combinations, in permutations order is significant.
+ positional: _input, list_size
+ options:
+ _input:
+ description: Elements to base the permutations on.
+ type: list
+ required: true
+ list_size:
+ description: The size of the list for each permutation.
+ type: int
+ required: true
+
+EXAMPLES: |
+ # ptrs_of_two => [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 1, 5 ], [ 2, 1 ], [ 2, 3 ], [ 2, 4 ], [ 2, 5 ], [ 3, 1 ], [ 3, 2 ], [ 3, 4 ], [ 3, 5 ], [ 4, 1 ], [ 4, 2 ], [ 4, 3 ], [ 4, 5 ], [ 5, 1 ], [ 5, 2 ], [ 5, 3 ], [ 5, 4 ] ]
+ prts_of_two: "{{ [1,2,3,4,5] | permutations(2) }}"
+
+RETURN:
+ _value:
+ description: List of permutations lists resulting from the supplied elements and list size.
+ type: list
diff --git a/lib/ansible/plugins/filter/pow.yml b/lib/ansible/plugins/filter/pow.yml
new file mode 100644
index 0000000..da2fa42
--- /dev/null
+++ b/lib/ansible/plugins/filter/pow.yml
@@ -0,0 +1,34 @@
+DOCUMENTATION:
+ name: pow
+ version_added: "1.9"
+ short_description: power of (math operation)
+ description:
+ - Math operation that returns the Nth power of inputed number, C(X ^ N).
+ notes:
+ - This is a passthrough to Python's C(math.pow).
+ positional: _input, _power
+ options:
+ _input:
+ description: The base.
+ type: float
+ required: true
+ _power:
+ description: Which power (exponent) to use.
+ type: float
+ required: true
+
+EXAMPLES: |
+
+ # => 32768
+ eight_power_five: "{{ 8 | pow(5) }}"
+
+ # 4
+ square_of_2: "{{ 2 | pow(2) }}"
+
+ # me ^ 3
+ cube_me: "{{ me | pow(3) }}"
+
+RETURN:
+ _value:
+ description: Resulting number.
+ type: float
diff --git a/lib/ansible/plugins/filter/product.yml b/lib/ansible/plugins/filter/product.yml
new file mode 100644
index 0000000..5035522
--- /dev/null
+++ b/lib/ansible/plugins/filter/product.yml
@@ -0,0 +1,42 @@
+DOCUMENTATION:
+ name: product
+ version_added: "historical"
+ short_description: cartesian product of lists
+ description:
+ - Combines two lists into one with each element being the product of the elements of the input lists.
+ - Creates 'nested loops'. Looping over C(listA) and C(listB) is the same as looping over C(listA | product(listB)).
+ notes:
+ - This is a passthrough to Python's C(itertools.product)
+ positional: _input, _additional_lists, repeat
+ options:
+ _input:
+ description: First list.
+ type: list
+ required: true
+ _additional_lists: #TODO: *args, N possible additional lists
+ description: Additional list for the product.
+ type: list
+ required: false
+ repeat:
+ description: Number of times to repeat the product against itself.
+ default: 1
+ type: int
+EXAMPLES: |
+
+ # product => [ [ 1, "a" ], [ 1, "b" ], [ 1, "c" ], [ 2, "a" ], [ 2, "b" ], [ 2, "c" ], [ 3, "a" ], [ 3, "b" ], [ 3, "c" ], [ 4, "a" ], [ 4, "b" ], [ 4, "c" ], [ 5, "a" ], [ 5, "b" ], [ 5, "c" ] ]
+ product: "{{ [1,2,3,4,5] | product(['a', 'b', 'c']) }}"
+
+ # repeat_original => [ [ 1, 1 ], [ 1, 2 ], [ 2, 1 ], [ 2, 2 ] ]
+ repeat_original: "{{ [1,2] | product(repeat=2) }}"
+
+ # repeat_product => [ [ 1, "a", 1, "a" ], [ 1, "a", 1, "b" ], [ 1, "a", 2, "a" ], [ 1, "a", 2, "b" ], [ 1, "b", 1, "a" ], [ 1, "b", 1, "b" ], [ 1, "b", 2, "a" ], [ 1, "b", 2, "b" ], [ 2, "a", 1, "a" ], [ 2, "a", 1, "b" ], [ 2, "a", 2, "a" ], [ 2, "a", 2, "b" ], [ 2, "b", 1, "a" ], [ 2, "b", 1, "b" ], [ 2, "b", 2, "a" ], [ 2, "b", 2, "b" ] ]
+ repeat_product: "{{ [1,2] | product(['a', 'b'], repeat=2) }}"
+
+ # domains => [ 'example.com', 'ansible.com', 'redhat.com' ]
+ domains: "{{ [ 'example', 'ansible', 'redhat'] | product(['com']) | map('join', '.') }}"
+
+RETURN:
+ _value:
+ description: List of lists of combined elements from the input lists.
+ type: list
+ elements: list
diff --git a/lib/ansible/plugins/filter/quote.yml b/lib/ansible/plugins/filter/quote.yml
new file mode 100644
index 0000000..2d621ed
--- /dev/null
+++ b/lib/ansible/plugins/filter/quote.yml
@@ -0,0 +1,23 @@
+DOCUMENTATION:
+ name: quote
+ version_added: "2.10"
+ short_description: shell quoting
+ description:
+ - Quote a string to safely use as in a POSIX shell.
+ notes:
+ - This is a passthrough to Python's C(shlex.quote).
+ positional: _input
+ options:
+ _input:
+ description: String to quote.
+ type: str
+ required: true
+
+EXAMPLES: |
+ - name: Run a shell command
+ shell: echo {{ string_value | quote }}
+
+RETURN:
+ _value:
+ description: Quoted string.
+ type: str
diff --git a/lib/ansible/plugins/filter/random.yml b/lib/ansible/plugins/filter/random.yml
new file mode 100644
index 0000000..b72dbb2
--- /dev/null
+++ b/lib/ansible/plugins/filter/random.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: random
+ version_added: "2.6"
+ short_description: random number or list item
+ description:
+ - Use the input to either select a random element of a list or generate a random number.
+ positional: _input, start, step, seed
+ options:
+ _input:
+ description: A number or list/sequence, if it is a number it is the top bound for random number generation, if it is a sequence or list, the source of the random element selected.
+ type: raw
+ required: true
+ start:
+ description: Bottom bound for the random number/element generated.
+ type: int
+ step:
+ description: Subsets the defined range by only using this value to select the increments of it between start and end.
+ type: int
+ default: 1
+ seed:
+ description: If specified use a pseudo random selection instead (repeatable).
+ type: str
+
+EXAMPLES: |
+
+ # can be any item from the list
+ random_item: "{{ ['a','b','c'] | random }}"
+
+ # cron line, select random minute repeatable for each host
+ "{{ 60 | random(seed=inventory_hostname) }} * * * * root /script/from/cron"
+
+RETURN:
+ _value:
+ description: Random number or list element.
+ type: raw
diff --git a/lib/ansible/plugins/filter/realpath.yml b/lib/ansible/plugins/filter/realpath.yml
new file mode 100644
index 0000000..12687b6
--- /dev/null
+++ b/lib/ansible/plugins/filter/realpath.yml
@@ -0,0 +1,21 @@
+DOCUMENTATION:
+ name: realpath
+ author: darkone23 (@darkone23)
+ version_added: "1.8"
+ short_description: Turn path into real path
+ description:
+ - Resolves/follows symliknks to return the 'real path' from a given path.
+ - Filters alwasy run on controller so this path is resolved using the controller's filesystem.
+ options:
+ _input:
+ description: A path.
+ type: path
+ required: true
+EXAMPLES: |
+
+ realpath: {{ '/path/to/synlink' | realpath }}
+
+RETURN:
+ _value:
+ description: The canonical path.
+ type: path
diff --git a/lib/ansible/plugins/filter/regex_escape.yml b/lib/ansible/plugins/filter/regex_escape.yml
new file mode 100644
index 0000000..7819909
--- /dev/null
+++ b/lib/ansible/plugins/filter/regex_escape.yml
@@ -0,0 +1,29 @@
+DOCUMENTATION:
+ name: regex_escape
+ version_added: "2.8"
+ short_description: escape regex chars
+ description:
+ - Escape special characters in a string for use in a regular expression.
+ positional: _input, re_type
+ notes:
+ - posix_extended is not implemented yet
+ options:
+ _input:
+ description: String to escape.
+ type: str
+ required: true
+ re_type:
+ description: Which type of escaping to use.
+ type: str
+ default: python
+ choices: [python, posix_basic]
+
+EXAMPLES: |
+
+ # safe_for_regex => '\^f\.\*o\(\.\*\)\$'
+ safe_for_regex: "{{ '^f.*o(.*)$' | regex_escape() }}"
+
+RETURN:
+ _value:
+ description: Escaped string.
+ type: str
diff --git a/lib/ansible/plugins/filter/regex_findall.yml b/lib/ansible/plugins/filter/regex_findall.yml
new file mode 100644
index 0000000..707d6fa
--- /dev/null
+++ b/lib/ansible/plugins/filter/regex_findall.yml
@@ -0,0 +1,37 @@
+DOCUMENTATION:
+ name: regex_findall
+ version_added: "2.0"
+ short_description: extract all regex matches from string
+ description:
+ - Search in a string or extract all the parts of a string matching a regular expression.
+ positional: _input, _regex
+ options:
+ _input:
+ description: String to match against.
+ type: str
+ required: true
+ _regex:
+ description: Regular expression string that defines the match.
+ type: str
+ multiline:
+ description: Search across line endings if C(True), do not if otherwise.
+ type: bool
+ default: no
+ ignorecase:
+ description: Force the search to be case insensitive if C(True), case sensitive otherwise.
+ type: bool
+ default: no
+
+EXAMPLES: |
+
+ # all_pirates => ['CAR', 'tar', 'bar']
+ all_pirates: "{{ 'CAR\ntar\nfoo\nbar\n' | regex_findall('^.ar$', multiline=True, ignorecase=True) }}"
+
+ # get_ips => ['8.8.8.8', '8.8.4.4']
+ get_ips: "{{ 'Some DNS servers are 8.8.8.8 and 8.8.4.4' | regex_findall('\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b') }}"
+
+RETURN:
+ _value:
+ description: List of matched strings.
+ type: list
+ elements: str
diff --git a/lib/ansible/plugins/filter/regex_replace.yml b/lib/ansible/plugins/filter/regex_replace.yml
new file mode 100644
index 0000000..0277b56
--- /dev/null
+++ b/lib/ansible/plugins/filter/regex_replace.yml
@@ -0,0 +1,46 @@
+DOCUMENTATION:
+ name: regex_replace
+ version_added: "2.0"
+ short_description: replace a string via regex
+ description:
+ - Replace a substring defined by a regular expression with another defined by another regular expression based on the first match.
+ notes:
+ - Maps to Python's C(re.replace).
+ positional: _input, _regex_match, _regex_replace
+ options:
+ _input:
+ description: String to match against.
+ type: str
+ required: true
+ _regex_match:
+ description: Regular expression string that defines the match.
+ type: int
+ required: true
+ _regex_replace:
+ description: Regular expression string that defines the replacement.
+ type: int
+ required: true
+ multiline:
+ description: Search across line endings if C(True), do not if otherwise.
+ type: bool
+ default: no
+ ignorecase:
+ description: Force the search to be case insensitive if C(True), case sensitive otherwise.
+ type: bool
+ default: no
+
+EXAMPLES: |
+
+ # whatami => 'able'
+ whatami: "{{ 'ansible' | regex_replace('^a.*i(.*)$', 'a\\1') }}"
+
+ # commalocal => 'localhost, 80'
+ commalocal: "{{ 'localhost:80' | regex_replace('^(?P<host>.+):(?P<port>\\d+)$', '\\g<host>, \\g<port>') }}"
+
+ # piratecomment => '#CAR\n#tar\nfoo\n#bar\n'
+ piratecomment: "{{ 'CAR\ntar\nfoo\nbar\n' | regex_replace('^(.ar)$', '#\\1', multiline=True, ignorecase=True) }}"
+
+RETURN:
+ _value:
+ description: String with substitution (or original if no match).
+ type: str
diff --git a/lib/ansible/plugins/filter/regex_search.yml b/lib/ansible/plugins/filter/regex_search.yml
new file mode 100644
index 0000000..c61efb7
--- /dev/null
+++ b/lib/ansible/plugins/filter/regex_search.yml
@@ -0,0 +1,38 @@
+DOCUMENTATION:
+ name: regex_search
+ version_added: "2.0"
+ short_description: extract regex match from string
+ description:
+ - Search in a string to extract the part that matches the regular expression.
+ notes:
+ - Maps to Python's C(re.search).
+ positional: _input, _regex
+ options:
+ _input:
+ description: String to match against.
+ type: str
+ required: true
+ _regex:
+ description: Regular expression string that defines the match.
+ type: str
+ multiline:
+ description: Search across line endings if C(True), do not if otherwise.
+ type: bool
+ default: no
+ ignorecase:
+ description: Force the search to be case insensitive if C(True), case sensitive otherwise.
+ type: bool
+ default: no
+
+EXAMPLES: |
+
+ # db => 'database42'
+ db: "{{ 'server1/database42' | regex_search('database[0-9]+') }}"
+
+ # drinkat => 'BAR'
+ drinkat: "{{ 'foo\nBAR' | regex_search('^bar', multiline=True, ignorecase=True) }}"
+
+RETURN:
+ _value:
+ description: Matched string or empty string if no match.
+ type: str
diff --git a/lib/ansible/plugins/filter/rekey_on_member.yml b/lib/ansible/plugins/filter/rekey_on_member.yml
new file mode 100644
index 0000000..d7470ab
--- /dev/null
+++ b/lib/ansible/plugins/filter/rekey_on_member.yml
@@ -0,0 +1,30 @@
+DOCUMENTATION:
+ name: rekey_on_member
+ version_added: "2.13"
+ short_description: Rekey a list of dicts into a dict using a member
+ positional: _input, '_key', duplicates
+ description: Iterate over several iterables in parallel, producing tuples with an item from each one.
+ options:
+ _input:
+ description: Original dictionary.
+ type: dict
+ required: yes
+ _key:
+ description: The key to rekey.
+ type: str
+ required: yes
+ duplicates:
+ description: How to handle duplicates.
+ type: str
+ default: error
+ choices: [overwrite, error]
+
+EXAMPLES: |
+
+ # mydict => {'eigrp': {'state': 'enabled', 'proto': 'eigrp'}, 'ospf': {'state': 'enabled', 'proto': 'ospf'}}
+ mydict: '{{ [{"proto": "eigrp", "state": "enabled"}, {"proto": "ospf", "state": "enabled"}] | rekey_on_member("proto") }}'
+
+RETURN:
+ _value:
+ description: The resulting dictionary.
+ type: dict
diff --git a/lib/ansible/plugins/filter/relpath.yml b/lib/ansible/plugins/filter/relpath.yml
new file mode 100644
index 0000000..47611c7
--- /dev/null
+++ b/lib/ansible/plugins/filter/relpath.yml
@@ -0,0 +1,28 @@
+DOCUMENTATION:
+ name: relpath
+ author: Jakub Jirutka (@jirutka)
+ version_added: "1.7"
+ short_description: Make a path relative
+ positional: _input, start
+ description:
+ - Converts the given path to a relative path from the I(start),
+ or relative to the directory given in I(start).
+ options:
+ _input:
+ description: A path.
+ type: str
+ required: true
+ start:
+ description: The directory the path should be relative to. If not supplied the current working directory will be used.
+ type: str
+
+EXAMPLES: |
+
+ # foobar => ../test/me.txt
+ testing: "{{ '/tmp/test/me.txt' | relpath('/tmp/other/') }}"
+ otherrelpath: "{{ mypath | relpath(mydir) }}"
+
+RETURN:
+ _value:
+ description: The relative path.
+ type: str
diff --git a/lib/ansible/plugins/filter/root.yml b/lib/ansible/plugins/filter/root.yml
new file mode 100644
index 0000000..4f52590
--- /dev/null
+++ b/lib/ansible/plugins/filter/root.yml
@@ -0,0 +1,32 @@
+DOCUMENTATION:
+ name: root
+ version_added: "1.9"
+ short_description: root of (math operation)
+ description:
+ - Math operation that returns the Nth root of inputed number C(X ^^ N).
+ positional: _input, base
+ options:
+ _input:
+ description: Number to operate on.
+ type: float
+ required: true
+ base:
+ description: Which root to take.
+ type: float
+ default: 2
+
+EXAMPLES: |
+
+ # => 8
+ fiveroot: "{{ 32768 | root (5) }}"
+
+ # 2
+ sqrt_of_2: "{{ 4 | root }}"
+
+ # me ^^ 3
+ cuberoot_me: "{{ me | root(3) }}"
+
+RETURN:
+ _value:
+ description: Resulting number.
+ type: float
diff --git a/lib/ansible/plugins/filter/sha1.yml b/lib/ansible/plugins/filter/sha1.yml
new file mode 100644
index 0000000..f80803b
--- /dev/null
+++ b/lib/ansible/plugins/filter/sha1.yml
@@ -0,0 +1,24 @@
+DOCUMENTATION:
+ name: sha1
+ version_added: "historical"
+ short_description: SHA-1 hash of input data
+ description:
+ - Returns a L(SHA-1 hash, https://en.wikipedia.org/wiki/SHA-1) of the input data.
+ positional: _input
+ notes:
+ - This requires the SHA-1 algorithm to be available on the system, security contexts like FIPS might prevent this.
+ - SHA-1 has been deemed insecure and is not recommended for security related uses.
+ options:
+ _input:
+ description: Data to hash.
+ type: raw
+ required: true
+
+EXAMPLES: |
+ # sha1hash => "dc724af18fbdd4e59189f5fe768a5f8311527050"
+ sha1hash: "{{ 'testing' | sha1 }}"
+
+RETURN:
+ _value:
+ description: The SHA-1 hash of the input.
+ type: string
diff --git a/lib/ansible/plugins/filter/shuffle.yml b/lib/ansible/plugins/filter/shuffle.yml
new file mode 100644
index 0000000..a7c3e7e
--- /dev/null
+++ b/lib/ansible/plugins/filter/shuffle.yml
@@ -0,0 +1,27 @@
+DOCUMENTATION:
+ name: shuffle
+ version_added: "2.6"
+ short_description: randomize a list
+ description:
+ - Take the elements of the input list and return in a random order.
+ positional: _input
+ options:
+ _input:
+ description: A number or list to randomize.
+ type: list
+ elements: any
+ required: true
+ seed:
+ description: If specified use a pseudo random selection instead (repeatable).
+ type: str
+
+EXAMPLES: |
+
+ randomized_list: "{{ ['a','b','c'] | shuffle}}"
+ per_host_repeatable: "{{ ['a','b','c'] | shuffle(seed=inventory_hostname) }}"
+
+RETURN:
+ _value:
+ description: Random number or list element.
+ type: list
+ elements: any
diff --git a/lib/ansible/plugins/filter/split.yml b/lib/ansible/plugins/filter/split.yml
new file mode 100644
index 0000000..3e7b59e
--- /dev/null
+++ b/lib/ansible/plugins/filter/split.yml
@@ -0,0 +1,32 @@
+DOCUMENTATION:
+ name: split
+ version_added: "historical"
+ short_description: split a string into a list
+ description:
+ - Using Python's text object method C(split) we turn strings into lists via a 'spliting character'.
+ notes:
+ - This is a passthrough to Python's C(str.split).
+ positional: _input, _split_string
+ options:
+ _input:
+ description: A string to split.
+ type: str
+ required: true
+ _split_string:
+ description: A string on which to split the original.
+ type: str
+ default: ' '
+
+EXAMPLES: |
+
+ # listjojo => [ "jojo", "is", "a" ]
+ listjojo: "{{ 'jojo is a' | split }}"
+
+ # listjojocomma => [ "jojo is", "a" ]
+ listjojocomma: "{{ 'jojo is, a' | split(',' }}"
+
+RETURN:
+ _value:
+ description: List of substrings split from the original.
+ type: list
+ elements: str
diff --git a/lib/ansible/plugins/filter/splitext.yml b/lib/ansible/plugins/filter/splitext.yml
new file mode 100644
index 0000000..ea9cbce
--- /dev/null
+++ b/lib/ansible/plugins/filter/splitext.yml
@@ -0,0 +1,30 @@
+DOCUMENTATION:
+ name: splitext
+ author: Matt Martz (@sivel)
+ version_added: "2.0"
+ short_description: split a path into root and file extension
+ positional: _input
+ description:
+ - Returns a list of two, with the elements consisting of filename root and extension.
+ options:
+ _input:
+ description: A path.
+ type: str
+ required: true
+
+EXAMPLES: |
+
+ # gobble => [ '/etc/make', 'conf' ]
+ gobble: "{{ '/etc/make.conf' | splitext }}"
+
+ # file_n_ext => [ 'ansible', 'cfg' ]
+ file_n_ext: "{{ 'ansible.cfg' | splitext }}"
+
+ # hoax => ['/etc/hoasdf', '']
+ hoax: '{{ "/etc//hoasdf/"|splitext }}'
+
+RETURN:
+ _value:
+ description: A list consisting of root of the path and the extension.
+ type: list
+ elements: str
diff --git a/lib/ansible/plugins/filter/strftime.yml b/lib/ansible/plugins/filter/strftime.yml
new file mode 100644
index 0000000..6cb8874
--- /dev/null
+++ b/lib/ansible/plugins/filter/strftime.yml
@@ -0,0 +1,45 @@
+DOCUMENTATION:
+ name: strftime
+ version_added: "2.4"
+ short_description: date formating
+ description:
+ - Using Python's C(strftime) function, take a data formating string and a date/time to create a formated date.
+ notes:
+ - This is a passthrough to Python's C(stftime).
+ positional: _input, second, utc
+ options:
+ _input:
+ description:
+ - A formating string following C(stftime) conventions.
+ - See L(the Python documentation, https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior) for a reference.
+ type: str
+ required: true
+ second:
+ description: Datetime in seconds from C(epoch) to format, if not supplied C(gmttime/localtime) will be used.
+ type: int
+ utc:
+ description: Whether time supplied is in UTC.
+ type: bool
+ default: false
+
+EXAMPLES: |
+ # Display year-month-day
+ {{ '%Y-%m-%d' | strftime }}
+ # => "2021-03-19"
+
+ # Display hour:min:sec
+ {{ '%H:%M:%S' | strftime }}
+ # => "21:51:04"
+
+ # Use ansible_date_time.epoch fact
+ {{ '%Y-%m-%d %H:%M:%S' | strftime(ansible_date_time.epoch) }}
+ # => "2021-03-19 21:54:09"
+
+ # Use arbitrary epoch value
+ {{ '%Y-%m-%d' | strftime(0) }} # => 1970-01-01
+ {{ '%Y-%m-%d' | strftime(1441357287) }} # => 2015-09-04
+
+RETURN:
+ _value:
+ description: A formatted date/time string.
+ type: str
diff --git a/lib/ansible/plugins/filter/subelements.yml b/lib/ansible/plugins/filter/subelements.yml
new file mode 100644
index 0000000..a2d1a94
--- /dev/null
+++ b/lib/ansible/plugins/filter/subelements.yml
@@ -0,0 +1,38 @@
+DOCUMENTATION:
+ name: subelements
+ version_added: "2.7"
+ short_description: retuns a product of a list and it's elements
+ positional: _input, _subelement, skip_missing
+ description:
+ - This produces a product of an object and the subelement values of that object, similar to the subelements lookup. This lets you specify individual subelements to use in a template I(_input).
+ options:
+ _input:
+ description: Original list.
+ type: list
+ elements: any
+ required: yes
+ _subelement:
+ description: Label of property to extract from original list items.
+ type: str
+ required: yes
+ skip_missing:
+ description: If C(True), ignore missing subelements, otherwise missing subelements generate an error.
+ type: bool
+ default: no
+
+EXAMPLES: |
+ # data
+ users:
+ - groups: [1,2,3]
+ name: lola
+ - name: fernando
+ groups: [2,3,4]
+
+ # user_w_groups =>[ { "groups": [ 1, 2, 3 ], "name": "lola" }, 1 ], [ { "groups": [ 1, 2, 3 ], "name": "lola" }, 2 ], [ { "groups": [ 1, 2, 3 ], "name": "lola" }, 3 ], [ { "groups": [ 2, 3, 4 ], "name": "fernando" }, 2 ], [ { "groups": [ 2, 3, 4 ], "name": "fernando" }, 3 ], [ { "groups": [ 2, 3, 4 ], "name": "fernando" }, 4 ] ]
+ users_w_groups: {{ users | subelements('groups', skip_missing=True) }}
+
+RETURN:
+ _value:
+ description: List made of original list and product of the subelement list.
+ type: list
+ elements: any
diff --git a/lib/ansible/plugins/filter/symmetric_difference.yml b/lib/ansible/plugins/filter/symmetric_difference.yml
new file mode 100644
index 0000000..de4f3c6
--- /dev/null
+++ b/lib/ansible/plugins/filter/symmetric_difference.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: symmetric_difference
+ author: Brian Coca (@bcoca)
+ version_added: "1.4"
+ short_description: different items from two lists
+ description:
+ - Provide a unique list of all the elements unique to each list.
+ options:
+ _input:
+ description: A list.
+ type: list
+ required: true
+ _second_list:
+ description: A list.
+ type: list
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.difference
+ - plugin_type: filter
+ plugin: ansible.builtin.intersect
+ - plugin_type: filter
+ plugin: ansible.builtin.union
+ - plugin_type: filter
+ plugin: ansible.builtin.unique
+EXAMPLES: |
+ # return the elements of list1 not in list2 and the elements in list2 not in list1
+ # list1: [1, 2, 5, 1, 3, 4, 10]
+ # list2: [1, 2, 3, 4, 5, 11, 99]
+ {{ list1 | symmetric_difference(list2) }}
+ # => [10, 11, 99]
+RETURN:
+ _value:
+ description: A unique list of the elements from two lists that are unique to each one.
+ type: list
diff --git a/lib/ansible/plugins/filter/ternary.yml b/lib/ansible/plugins/filter/ternary.yml
new file mode 100644
index 0000000..50ff767
--- /dev/null
+++ b/lib/ansible/plugins/filter/ternary.yml
@@ -0,0 +1,44 @@
+DOCUMENTATION:
+ name: ternary
+ author: Brian Coca (@bcoca)
+ version_added: '1.9'
+ short_description: Ternary operation filter
+ description:
+ - Return the first value if the input is C(True), the second if C(False).
+ positional: true_val, false_val
+ options:
+ _input:
+ description: A boolean expression, must evaluate to C(True) or C(False).
+ type: bool
+ required: true
+ true_val:
+ description: Value to return if the input is C(True).
+ type: any
+ required: true
+ false_val:
+ description: Value to return if the input is C(False).
+ type: any
+ none_val:
+ description: Value to return if the input is C(None). If not set, C(None) will be treated as C(False).
+ type: any
+ version_added: '2.8'
+ notes:
+ - Vars as values are evaluated even when not returned. This is due to them being evaluated before being passed into the filter.
+
+EXAMPLES: |
+ # set first 10 volumes rw, rest as dp
+ volume_mode: "{{ (item|int < 11)|ternary('rw', 'dp') }}"
+
+ # choose correct vpc subnet id, note that vars as values are evaluated even if not returned
+ vpc_subnet_id: "{{ (ec2_subnet_type == 'public') | ternary(ec2_vpc_public_subnet_id, ec2_vpc_private_subnet_id) }}"
+
+ - name: service-foo, use systemd module unless upstart is present, then use old service module
+ service:
+ state: restarted
+ enabled: yes
+ use: "{{ (ansible_service_mgr == 'upstart') | ternary('service', 'systemd') }}"
+
+RETURN:
+ _value:
+ description: The value indicated by the input.
+ type: any
diff --git a/lib/ansible/plugins/filter/to_datetime.yml b/lib/ansible/plugins/filter/to_datetime.yml
new file mode 100644
index 0000000..dbd476a
--- /dev/null
+++ b/lib/ansible/plugins/filter/to_datetime.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: to_datetime
+ version_added: "2.4"
+ short_description: Get C(datetime) from string
+ description:
+ - Using the input string attempt to create a matching Python C(datetime) object.
+ notes:
+ - For a full list of format codes for working with Python date format strings, see
+ L(the Python documentation, https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior).
+ positional: _input
+ options:
+ _input:
+ description: A string containing date time information.
+ type: str
+ required: true
+ format:
+ description: C(strformat) formatted string that describes the expected format of the input string.
+ type: str
+
+EXAMPLES: |
+
+ # Get total amount of seconds between two dates. Default date format is %Y-%m-%d %H:%M:%S but you can pass your own format
+ secsdiff: '{{ (("2016-08-14 20:00:12" | to_datetime) - ("2015-12-25" | to_datetime("%Y-%m-%d"))).total_seconds() }}'
+
+ # Get remaining seconds after delta has been calculated. NOTE: This does NOT convert years, days, hours, and so on to seconds. For that, use total_seconds()
+ {{ (("2016-08-14 20:00:12" | to_datetime) - ("2016-08-14 18:00:00" | to_datetime)).seconds }}
+ # This expression evaluates to "12" and not "132". Delta is 2 hours, 12 seconds
+
+ # get amount of days between two dates. This returns only number of days and discards remaining hours, minutes, and seconds
+ {{ (("2016-08-14 20:00:12" | to_datetime) - ("2015-12-25" | to_datetime('%Y-%m-%d'))).days }}
+
+RETURN:
+ _value:
+ description: C(datetime) object from the represented value.
+ type: raw
diff --git a/lib/ansible/plugins/filter/to_json.yml b/lib/ansible/plugins/filter/to_json.yml
new file mode 100644
index 0000000..6f32d7c
--- /dev/null
+++ b/lib/ansible/plugins/filter/to_json.yml
@@ -0,0 +1,69 @@
+DOCUMENTATION:
+ name: to_json
+ author: core team
+ version_added: 'historical'
+ short_description: Convert variable to JSON string
+ description:
+ - Converts an Ansible variable into a JSON string representation.
+ - This filter functions as a wrapper to the Python C(json.dumps) function.
+ - Ansible internally auto-converts JSON strings into variable structures so this plugin is used to force it into a JSON string.
+ options:
+ _input:
+ description: A variable or expression that returns a data structure.
+ type: raw
+ required: true
+ vault_to_text:
+ description: Toggle to either unvault a vault or create the JSON version of a vaulted object.
+ type: bool
+ default: True
+ version_added: '2.9'
+ preprocess_unsafe:
+ description: Toggle to represent unsafe values directly in JSON or create a unsafe object in JSON.
+ type: bool
+ default: True
+ version_added: '2.9'
+ allow_nan:
+ description: When C(False), strict adherence to float value limits of the JSON specifications, so C(nan), C(inf) and C(-inf) values will produce errors.
+ When C(True), JavaScript equivalents will be used (C(NaN), C(Infinity), C(-Infinity)).
+ default: True
+ type: bool
+ check_circular:
+ description: Controls the usage of the internal circular reference detection, if off can result in overflow errors.
+ default: True
+ type: bool
+ ensure_ascii:
+ description: Escapes all non ASCII characters.
+ default: True
+ type: bool
+ indent:
+ description: Number of spaces to indent Python structures, mainly used for display to humans.
+ default: 0
+ type: integer
+ separators:
+ description: The C(item) and C(key) separator to be used in the serialized output,
+ default may change depending on I(indent) and Python version.
+ default: "(', ', ': ')"
+ type: tuple
+ skipkeys:
+ description: If C(True), keys that are not basic Python types will be skipped.
+ default: False
+ type: bool
+ sort_keys:
+ description: Affects sorting of dictionary keys.
+ default: False
+ type: bool
+ notes:
+ - Both I(vault_to_text) and I(preprocess_unsafe) defaulted to C(False) between Ansible 2.9 and 2.12.
+ - 'These parameters to C(json.dumps) will be ignored, as they are overriden internally: I(cls), I(default)'
+
+EXAMPLES: |
+ # dump variable in a template to create a JSON document
+ {{ docker_config|to_json }}
+
+ # same as above but 'prettier' (equivalent to to_nice_json filter)
+ {{ docker_config|to_json(indent=4, sort_keys=True) }}
+
+RETURN:
+ _value:
+ description: The JSON serialized string representing the variable structure inputted.
+ type: string
diff --git a/lib/ansible/plugins/filter/to_nice_json.yml b/lib/ansible/plugins/filter/to_nice_json.yml
new file mode 100644
index 0000000..bedc18b
--- /dev/null
+++ b/lib/ansible/plugins/filter/to_nice_json.yml
@@ -0,0 +1,54 @@
+DOCUMENTATION:
+ name: to_nice_json
+ author: core team
+ version_added: 'historical'
+ short_description: Convert variable to 'nicely formatted' JSON string
+ description:
+ - Converts an Ansible variable into a 'nicely formatted' JSON string representation
+ - This filter functions as a wrapper to the Python C(json.dumps) function.
+ - Ansible automatically converts JSON strings into variable structures so this plugin is used to forcibly retain a JSON string.
+ options:
+ _input:
+ description: A variable or expression that returns a data structure.
+ type: raw
+ required: true
+ vault_to_text:
+ description: Toggle to either unvault a vault or create the JSON version of a vaulted object.
+ type: bool
+ default: True
+ version_added: '2.9'
+ preprocess_unsafe:
+ description: Toggle to represent unsafe values directly in JSON or create a unsafe object in JSON.
+ type: bool
+ default: True
+ version_added: '2.9'
+ allow_nan:
+ description: When C(False), strict adherence to float value limits of the JSON specification, so C(nan), C(inf) and C(-inf) values will produce errors.
+ When C(True), JavaScript equivalents will be used (C(NaN), C(Infinity), C(-Infinity)).
+ default: True
+ type: bool
+ check_circular:
+ description: Controls the usage of the internal circular reference detection, if off can result in overflow errors.
+ default: True
+ type: bool
+ ensure_ascii:
+ description: Escapes all non ASCII characters.
+ default: True
+ type: bool
+ skipkeys:
+ description: If C(True), keys that are not basic Python types will be skipped.
+ default: False
+ type: bool
+ notes:
+ - Both I(vault_to_text) and I(preprocess_unsafe) defaulted to C(False) between Ansible 2.9 and 2.12.
+ - 'These parameters to C(json.dumps) will be ignored, they are overriden for internal use: I(cls), I(default), I(indent), I(separators), I(sort_keys).'
+
+EXAMPLES: |
+ # dump variable in a template to create a nicely formatted JSON document
+ {{ docker_config|to_nice_json }}
+
+
+RETURN:
+ _value:
+ description: The 'nicely formatted' JSON serialized string representing the variable structure inputted.
+ type: string
diff --git a/lib/ansible/plugins/filter/to_nice_yaml.yml b/lib/ansible/plugins/filter/to_nice_yaml.yml
new file mode 100644
index 0000000..4677a86
--- /dev/null
+++ b/lib/ansible/plugins/filter/to_nice_yaml.yml
@@ -0,0 +1,39 @@
+DOCUMENTATION:
+ name: to_yaml
+ author: core team
+ version_added: 'historical'
+ short_description: Convert variable to YAML string
+ description:
+ - Converts an Ansible variable into a YAML string representation.
+ - This filter functions as a wrapper to the L(Python PyYAML library, https://pypi.org/project/PyYAML/)'s C(yaml.dump) function.
+ - Ansible internally auto-converts YAML strings into variable structures so this plugin is used to force it into a YAML string.
+ positional: _input
+ options:
+ _input:
+ description: A variable or expression that returns a data structure.
+ type: raw
+ required: true
+ indent:
+ description: Number of spaces to indent Python structures, mainly used for display to humans.
+ type: integer
+ sort_keys:
+ description: Affects sorting of dictionary keys.
+ default: True
+ type: bool
+ #allow_unicode:
+ # description:
+ # type: bool
+ # default: true
+ #default_style=None, canonical=None, width=None, line_break=None, encoding=None, explicit_start=None, explicit_end=None, version=None, tags=None
+ notes:
+ - More options may be available, see L(PyYAML documentation, https://pyyaml.org/wiki/PyYAMLDocumentation) for details.
+ - 'These parameters to C(yaml.dump) will be ignored, as they are overriden internally: I(default_flow_style)'
+
+EXAMPLES: |
+ # dump variable in a template to create a YAML document
+ {{ github_workflow | to_nice_yaml }}
+
+RETURN:
+ _value:
+ description: The YAML serialized string representing the variable structure inputted.
+ type: string
diff --git a/lib/ansible/plugins/filter/to_uuid.yml b/lib/ansible/plugins/filter/to_uuid.yml
new file mode 100644
index 0000000..266bf05
--- /dev/null
+++ b/lib/ansible/plugins/filter/to_uuid.yml
@@ -0,0 +1,30 @@
+DOCUMENTATION:
+ name: to_uuid
+ version_added: "2.9"
+ short_description: namespaced UUID generator
+ description:
+ - Use to generate namespeced Universal Unique ID.
+ positional: _input, namespace
+ options:
+ _input:
+ description: String to use as base fo the UUID.
+ type: str
+ required: true
+ namespace:
+ description: UUID namespace to use.
+ type: str
+ default: 361E6D51-FAEC-444A-9079-341386DA8E2E
+
+EXAMPLES: |
+
+ # To create a namespaced UUIDv5
+ uuid: "{{ string | to_uuid(namespace='11111111-2222-3333-4444-555555555555') }}"
+
+
+ # To create a namespaced UUIDv5 using the default Ansible namespace '361E6D51-FAEC-444A-9079-341386DA8E2E'
+ uuid: "{{ string | to_uuid }}"
+
+RETURN:
+ _value:
+ description: Generated UUID.
+ type: string
diff --git a/lib/ansible/plugins/filter/to_yaml.yml b/lib/ansible/plugins/filter/to_yaml.yml
new file mode 100644
index 0000000..2e7be60
--- /dev/null
+++ b/lib/ansible/plugins/filter/to_yaml.yml
@@ -0,0 +1,52 @@
+DOCUMENTATION:
+ name: to_yaml
+ author: core team
+ version_added: 'historical'
+ short_description: Convert variable to YAML string
+ description:
+ - Converts an Ansible variable into a YAML string representation.
+ - This filter functions as a wrapper to the L(Python PyYAML library, https://pypi.org/project/PyYAML/)'s C(yaml.dump) function.
+ - Ansible automatically converts YAML strings into variable structures so this plugin is used to forcibly retain a YAML string.
+ positional: _input
+ options:
+ _input:
+ description: A variable or expression that returns a data structure.
+ type: raw
+ required: true
+ indent:
+ description: Number of spaces to indent Python structures, mainly used for display to humans.
+ type: integer
+ sort_keys:
+ description: Affects sorting of dictionary keys.
+ default: True
+ type: bool
+ notes:
+ - More options may be available, see L(PyYAML documentation, https://pyyaml.org/wiki/PyYAMLDocumentation) for details.
+
+ # TODO: find docs for these
+ #allow_unicode:
+ # description:
+ # type: bool
+ # default: true
+ #default_flow_style
+ #default_style
+ #canonical=None,
+ #width=None,
+ #line_break=None,
+ #encoding=None,
+ #explicit_start=None,
+ #explicit_end=None,
+ #version=None,
+ #tags=None
+
+EXAMPLES: |
+ # dump variable in a template to create a YAML document
+ {{ github_workflow |to_yaml}}
+
+ # same as above but 'prettier' (equivalent to to_nice_yaml filter)
+ {{ docker_config|to_json(indent=4) }}
+
+RETURN:
+ _value:
+ description: The YAML serialized string representing the variable structure inputted.
+ type: string
diff --git a/lib/ansible/plugins/filter/type_debug.yml b/lib/ansible/plugins/filter/type_debug.yml
new file mode 100644
index 0000000..73f7946
--- /dev/null
+++ b/lib/ansible/plugins/filter/type_debug.yml
@@ -0,0 +1,20 @@
+DOCUMENTATION:
+ name: type_debug
+ author: Adrian Likins (@alikins)
+ version_added: "2.3"
+ short_description: show input data type
+ description:
+ - Returns the equivalent of Python's C(type) function.
+ options:
+ _input:
+ description: Variable or expression of which you want to determine type.
+ type: any
+ required: true
+EXAMPLES: |
+ # get type of 'myvar'
+ {{ myvar | type_debug }}
+
+RETURN:
+ _value:
+ description: The Python 'type' of the I(_input) provided.
+ type: string
diff --git a/lib/ansible/plugins/filter/union.yml b/lib/ansible/plugins/filter/union.yml
new file mode 100644
index 0000000..d737900
--- /dev/null
+++ b/lib/ansible/plugins/filter/union.yml
@@ -0,0 +1,35 @@
+DOCUMENTATION:
+ name: union
+ author: Brian Coca (@bcoca)
+ version_added: "1.4"
+ short_description: union of lists
+ description:
+ - Provide a unique list of all the elements of two lists.
+ options:
+ _input:
+ description: A list.
+ type: list
+ required: true
+ _second_list:
+ description: A list.
+ type: list
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.difference
+ - plugin_type: filter
+ plugin: ansible.builtin.intersect
+ - plugin_type: filter
+ plugin: ansible.builtin.symmetric_difference
+ - plugin_type: filter
+ plugin: ansible.builtin.unique
+EXAMPLES: |
+ # return the unique elements of list1 added to list2
+ # list1: [1, 2, 5, 1, 3, 4, 10]
+ # list2: [1, 2, 3, 4, 5, 11, 99]
+ {{ list1 | union(list2) }}
+ # => [1, 2, 5, 1, 3, 4, 10, 11, 99]
+RETURN:
+ _value:
+ description: A unique list of all the elements from both lists.
+ type: list
diff --git a/lib/ansible/plugins/filter/unique.yml b/lib/ansible/plugins/filter/unique.yml
new file mode 100644
index 0000000..c627816
--- /dev/null
+++ b/lib/ansible/plugins/filter/unique.yml
@@ -0,0 +1,30 @@
+DOCUMENTATION:
+ name: unique
+ author: Brian Coca (@bcoca)
+ version_added: "1.4"
+ short_description: set of unique items of a list
+ description:
+ - Creates a list of unique elements (a set) from the provided input list.
+ options:
+ _input:
+ description: A list.
+ type: list
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.difference
+ - plugin_type: filter
+ plugin: ansible.builtin.intersect
+ - plugin_type: filter
+ plugin: ansible.builtin.symmetric_difference
+ - plugin_type: filter
+ plugin: ansible.builtin.union
+EXAMPLES: |
+ # return only the unique elements of list1
+ # list1: [1, 2, 5, 1, 3, 4, 10]
+ {{ list1 | unique }}
+ # => [1, 2, 5, 3, 4, 10]
+RETURN:
+ _value:
+ description: A list with unique elements, also known as a set.
+ type: list
diff --git a/lib/ansible/plugins/filter/unvault.yml b/lib/ansible/plugins/filter/unvault.yml
new file mode 100644
index 0000000..96a82ca
--- /dev/null
+++ b/lib/ansible/plugins/filter/unvault.yml
@@ -0,0 +1,36 @@
+DOCUMENTATION:
+ name: unvault
+ author: Brian Coca (@bcoca)
+ version_added: "2.12"
+ short_description: Open an Ansible Vault
+ description:
+ - Retrieve your information from an encrypted Ansible Vault.
+ positional: secret
+ options:
+ _input:
+ description: Vault string, or an C(AnsibleVaultEncryptedUnicode) string object.
+ type: string
+ required: true
+ secret:
+ description: Vault secret, the key that lets you open the vault.
+ type: string
+ required: true
+ vault_id:
+ description: Secret identifier, used internally to try to best match a secret when multiple are provided.
+ type: string
+ default: 'filter_default'
+
+EXAMPLES: |
+ # simply decrypt my key from a vault
+ vars:
+ mykey: "{{ myvaultedkey|unvault(passphrase) }} "
+
+ - name: save templated unvaulted data
+ template: src=dump_template_data.j2 dest=/some/key/clear.txt
+ vars:
+ template_data: '{{ secretdata|uvault(vaultsecret) }}'
+
+RETURN:
+ _value:
+ description: The string that was contained in the vault.
+ type: string
diff --git a/lib/ansible/plugins/filter/urldecode.yml b/lib/ansible/plugins/filter/urldecode.yml
new file mode 100644
index 0000000..dd76937
--- /dev/null
+++ b/lib/ansible/plugins/filter/urldecode.yml
@@ -0,0 +1,48 @@
+DOCUMENTATION:
+ name: urlsplit
+ version_added: "2.4"
+ short_description: get components from URL
+ description:
+ - Split a URL into its component parts.
+ positional: _input, query
+ options:
+ _input:
+ description: URL string to split.
+ type: str
+ required: true
+ query:
+ description: Specify a single component to return.
+ type: str
+ choices: ["fragment", "hostname", "netloc", "password", "path", "port", "query", "scheme", "username"]
+
+RETURN:
+ _value:
+ description:
+ - A dictionary with components as keyword and their value.
+ - If I(query) is provided, a string or integer will be returned instead, depending on I(query).
+ type: any
+
+EXAMPLES: |
+
+ {{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit }}
+ # =>
+ # {
+ # "fragment": "fragment",
+ # "hostname": "www.acme.com",
+ # "netloc": "user:password@www.acme.com:9000",
+ # "password": "password",
+ # "path": "/dir/index.html",
+ # "port": 9000,
+ # "query": "query=term",
+ # "scheme": "http",
+ # "username": "user"
+ # }
+
+ {{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('hostname') }}
+ # => 'www.acme.com'
+
+ {{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('query') }}
+ # => 'query=term'
+
+ {{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit('path') }}
+ # => '/dir/index.html'
diff --git a/lib/ansible/plugins/filter/urls.py b/lib/ansible/plugins/filter/urls.py
new file mode 100644
index 0000000..fb7abc6
--- /dev/null
+++ b/lib/ansible/plugins/filter/urls.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2012, Dag Wieers (@dagwieers) <dag@wieers.com>
+# 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 functools import partial
+
+from urllib.parse import unquote_plus
+
+
+class FilterModule(object):
+ ''' Ansible core jinja2 filters '''
+
+ def filters(self):
+ return {
+ 'urldecode': partial(unquote_plus),
+ }
diff --git a/lib/ansible/plugins/filter/urlsplit.py b/lib/ansible/plugins/filter/urlsplit.py
new file mode 100644
index 0000000..cce54bb
--- /dev/null
+++ b/lib/ansible/plugins/filter/urlsplit.py
@@ -0,0 +1,87 @@
+# Copyright (c) 2017 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
+
+DOCUMENTATION = r'''
+ name: urlsplit
+ version_added: "2.4"
+ short_description: get components from URL
+ description:
+ - Split a URL into its component parts.
+ positional: _input, query
+ options:
+ _input:
+ description: URL string to split.
+ type: str
+ required: true
+ query:
+ description: Specify a single component to return.
+ type: str
+ choices: ["fragment", "hostname", "netloc", "password", "path", "port", "query", "scheme", "username"]
+'''
+
+EXAMPLES = r'''
+
+ parts: '{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit }}'
+ # =>
+ # {
+ # "fragment": "fragment",
+ # "hostname": "www.acme.com",
+ # "netloc": "user:password@www.acme.com:9000",
+ # "password": "password",
+ # "path": "/dir/index.html",
+ # "port": 9000,
+ # "query": "query=term",
+ # "scheme": "http",
+ # "username": "user"
+ # }
+
+ hostname: '{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit("hostname") }}'
+ # => 'www.acme.com'
+
+ query: '{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit("query") }}'
+ # => 'query=term'
+
+ path: '{{ "http://user:password@www.acme.com:9000/dir/index.html?query=term#fragment" | urlsplit("path") }}'
+ # => '/dir/index.html'
+'''
+
+RETURN = r'''
+ _value:
+ description:
+ - A dictionary with components as keyword and their value.
+ - If I(query) is provided, a string or integer will be returned instead, depending on I(query).
+ type: any
+'''
+
+from urllib.parse import urlsplit
+
+from ansible.errors import AnsibleFilterError
+from ansible.utils import helpers
+
+
+def split_url(value, query='', alias='urlsplit'):
+
+ results = helpers.object_to_dict(urlsplit(value), exclude=['count', 'index', 'geturl', 'encode'])
+
+ # If a query is supplied, make sure it's valid then return the results.
+ # If no option is supplied, return the entire dictionary.
+ if query:
+ if query not in results:
+ raise AnsibleFilterError(alias + ': unknown URL component: %s' % query)
+ return results[query]
+ else:
+ return results
+
+
+# ---- Ansible filters ----
+class FilterModule(object):
+ ''' URI filter '''
+
+ def filters(self):
+ return {
+ 'urlsplit': split_url
+ }
diff --git a/lib/ansible/plugins/filter/vault.yml b/lib/ansible/plugins/filter/vault.yml
new file mode 100644
index 0000000..1ad541e
--- /dev/null
+++ b/lib/ansible/plugins/filter/vault.yml
@@ -0,0 +1,48 @@
+DOCUMENTATION:
+ name: vault
+ author: Brian Coca (@bcoca)
+ version_added: "2.12"
+ short_description: vault your secrets
+ description:
+ - Put your information into an encrypted Ansible Vault.
+ positional: secret
+ options:
+ _input:
+ description: Data to vault.
+ type: string
+ required: true
+ secret:
+ description: Vault secret, the key that lets you open the vault.
+ type: string
+ required: true
+ salt:
+ description:
+ - Encryption salt, will be random if not provided.
+ - While providing one makes the resulting encrypted string reproducible, it can lower the security of the vault.
+ type: string
+ vault_id:
+ description: Secret identifier, used internally to try to best match a secret when multiple are provided.
+ type: string
+ default: 'filter_default'
+ wrap_object:
+ description:
+ - This toggle can force the return of an C(AnsibleVaultEncryptedUnicode) string object, when C(False), you get a simple string.
+ - Mostly useful when combining with the C(to_yaml) filter to output the 'inline vault' format.
+ type: bool
+ default: False
+
+EXAMPLES: |
+ # simply encrypt my key in a vault
+ vars:
+ myvaultedkey: "{{ keyrawdata|vault(passphrase) }} "
+
+ - name: save templated vaulted data
+ template: src=dump_template_data.j2 dest=/some/key/vault.txt
+ vars:
+ mysalt: '{{2**256|random(seed=inventory_hostname)}}'
+ template_data: '{{ secretdata|vault(vaultsecret, salt=mysalt) }}'
+
+RETURN:
+ _value:
+ description: The vault string that contains the secret data (or C(AnsibleVaultEncryptedUnicode) string object).
+ type: string
diff --git a/lib/ansible/plugins/filter/win_basename.yml b/lib/ansible/plugins/filter/win_basename.yml
new file mode 100644
index 0000000..f89baa5
--- /dev/null
+++ b/lib/ansible/plugins/filter/win_basename.yml
@@ -0,0 +1,24 @@
+DOCUMENTATION:
+ name: win_basename
+ author: ansible core team
+ version_added: "2.0"
+ short_description: Get a Windows path's base name
+ description:
+ - Returns the last name component of a Windows path, what is left in the string that is not 'win_dirname'.
+ options:
+ _input:
+ description: A Windows path.
+ type: str
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.win_dirname
+EXAMPLES: |
+
+ # To get the last name of a file Windows path, like 'foo.txt' out of 'C:\Users\asdf\foo.txt'
+ {{ mypath | win_basename }}
+
+RETURN:
+ _value:
+ description: The base name from the Windows path provided.
+ type: str
diff --git a/lib/ansible/plugins/filter/win_dirname.yml b/lib/ansible/plugins/filter/win_dirname.yml
new file mode 100644
index 0000000..dbc85c7
--- /dev/null
+++ b/lib/ansible/plugins/filter/win_dirname.yml
@@ -0,0 +1,24 @@
+DOCUMENTATION:
+ name: win_dirname
+ author: ansible core team
+ version_added: "2.0"
+ short_description: Get a Windows path's directory
+ description:
+ - Returns the directory component of a Windows path, what is left in the string that is not 'win_basename'.
+ options:
+ _input:
+ description: A Windows path.
+ type: str
+ required: true
+ seealso:
+ - plugin_type: filter
+ plugin: ansible.builtin.win_basename
+EXAMPLES: |
+
+ # To get the last name of a file Windows path, like 'C:\users\asdf' out of 'C:\Users\asdf\foo.txt'
+ {{ mypath | win_dirname }}
+
+RETURN:
+ _value:
+ description: The directory from the Windows path provided.
+ type: str
diff --git a/lib/ansible/plugins/filter/win_splitdrive.yml b/lib/ansible/plugins/filter/win_splitdrive.yml
new file mode 100644
index 0000000..828d1dd
--- /dev/null
+++ b/lib/ansible/plugins/filter/win_splitdrive.yml
@@ -0,0 +1,29 @@
+DOCUMENTATION:
+ name: win_splitdrive
+ author: ansible core team
+ version_added: "2.0"
+ short_description: Split a Windows path by the drive letter
+ description:
+ - Returns a list with the first component being the drive letter and the second, the rest of the path.
+ options:
+ _input:
+ description: A Windows path.
+ type: str
+ required: true
+
+EXAMPLES: |
+
+ # To get the last name of a file Windows path, like ['C', '\Users\asdf\foo.txt'] out of 'C:\Users\asdf\foo.txt'
+ {{ mypath | win_splitdrive }}
+
+ # just the drive letter
+ {{ mypath | win_splitdrive | first }}
+
+ # path w/o drive letter
+ {{ mypath | win_splitdrive | last }}
+
+RETURN:
+ _value:
+ description: List in which the first element is the drive letter and the second the rest of the path.
+ type: list
+ elements: str
diff --git a/lib/ansible/plugins/filter/zip.yml b/lib/ansible/plugins/filter/zip.yml
new file mode 100644
index 0000000..20d7a9b
--- /dev/null
+++ b/lib/ansible/plugins/filter/zip.yml
@@ -0,0 +1,43 @@
+DOCUMENTATION:
+ name: zip
+ version_added: "2.3"
+ short_description: combine list elements
+ positional: _input, _additional_lists
+ description: Iterate over several iterables in parallel, producing tuples with an item from each one.
+ notes:
+ - This is mostly a passhtrough to Python's C(zip) function.
+ options:
+ _input:
+ description: Original list.
+ type: list
+ elements: any
+ required: yes
+ _additional_lists:
+ description: Additional list(s).
+ type: list
+ elements: any
+ required: yes
+ strict:
+ description: If C(True) return an error on mismatching list length, otherwise shortest list determines output.
+ type: bool
+ default: no
+
+EXAMPLES: |
+
+ # two => [[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, "e"], [6, "f"]]
+ two: "{{ [1,2,3,4,5,6] | zip(['a','b','c','d','e','f']) }}"
+
+ # three => [ [ 1, "a", "d" ], [ 2, "b", "e" ], [ 3, "c", "f" ] ]
+ three: "{{ [1,2,3] | zip(['a','b','c'], ['d','e','f']) }}"
+
+ # shorter => [[1, "a"], [2, "b"], [3, "c"]]
+ shorter: "{{ [1,2,3] | zip(['a','b','c','d','e','f']) }}"
+
+ # compose dict from lists of keys and values
+ mydcit: "{{ dict(keys_list | zip(values_list)) }}"
+
+RETURN:
+ _value:
+ description: List of lists made of elements matching the positions of the input lists.
+ type: list
+ elements: list
diff --git a/lib/ansible/plugins/filter/zip_longest.yml b/lib/ansible/plugins/filter/zip_longest.yml
new file mode 100644
index 0000000..db351b4
--- /dev/null
+++ b/lib/ansible/plugins/filter/zip_longest.yml
@@ -0,0 +1,36 @@
+DOCUMENTATION:
+ name: zip_longest
+ version_added: "2.3"
+ short_description: combine list elements, with filler
+ positional: _input, _additional_lists
+ description:
+ - Make an iterator that aggregates elements from each of the iterables.
+ If the iterables are of uneven length, missing values are filled-in with I(fillvalue).
+ Iteration continues until the longest iterable is exhausted.
+ notes:
+ - This is mostly a passhtrough to Python's C(itertools.zip_longest) function
+ options:
+ _input:
+ description: Original list.
+ type: list
+ elements: any
+ required: yes
+ _additional_lists:
+ description: Additional list(s).
+ type: list
+ elements: any
+ required: yes
+ fillvalue:
+ description: Filler value to add to output when one of the lists does not contain enough elements to match the others.
+ type: any
+
+EXAMPLES: |
+
+ # X_fill => [[1, "a", 21], [2, "b", 22], [3, "c", 23], ["X", "d", "X"], ["X", "e", "X"], ["X", "f", "X"]]
+ X_fill: "{{ [1,2,3] | zip_longest(['a','b','c','d','e','f'], [21, 22, 23], fillvalue='X') }}"
+
+RETURN:
+ _value:
+ description: List of lists made of elements matching the positions of the input lists.
+ type: list
+ elements: list