---

- name: Show off Ansible's templating
  hosts: all
  vars:
    random_string: ""
    random_integer: random(-34485, 45666)
  tasks:

    # A.K.A. ternary operator.
    - name: Get back a conditional value.
      ansible.builtin.debug:
        var: "{{ 'true' if 'test me a lot' is match('test') else 'false' }}"
    - name: Use the ternary operator.
      ansible.builtin.debug:
        msg: >-
          {{
            'test me a lot' is match('test')
            | ternary(
              'what_if_true',
              'what_if_false'
            )
          }}
          {{
            'test me a lot' is match('test')
            | ternary(
              'what_if_true',
              'what_if_false',
              'what_if_null'
            )
          }}

    # Returns ["string"] from ["", "string", 0, false].
    - name: Remove empty or false values from a list piping it to 'select()'.
      vars:
        list: ["", "string", 0, false]
      ansible.builtin.debug:
        var: list | select

    # Returns ["string", 0, false] from ["", "string", 0, false].
    - name: Remove only empty strings from a list 'reject()'ing them.
      vars:
        list: ["", "string", 0, false]
      ansible.builtin.debug:
        var: list | reject('match', '^$')

    # Returns ["a", "b", "c", "d"] from ["a", "b"] and ["c", "d"].
    - name: Merge two lists.
      vars:
        list1: ["a", "b"]
        list2: ["c", "d"]
      ansible.builtin.debug:
        var: list1 + list2

    # Returns ["a", "b"] from ["a", "b", "b", "a"].
    - name: Dedupe elements in a list.
      vars:
        list: ["a", "b", "b", "a"]
      ansible.builtin.debug:
        var: list | unique

    # Returns ['2.7.0', '2.8.0', '2.9.0',, '2.10.0' '2.11.0'] from
    # ['2.8.0', '2.11.0', '2.7.0', '2.10.0', '2.9.0']
    - name: Sort list by version number (not lexicographically).
      vars:
        list: ['2.8.0', '2.11.0', '2.7.0', '2.10.0', '2.9.0']
      ansible.builtin.debug:
        var: list | community.general.version_sort

    - name: Replace spaces with underscores in a string.
      ansible.builtin.debug:
        var: "'string with spaces' | replace(' ', '_')"

    # Returns a random string following the specifications.
    - name: Generate a random password.
      vars:
        password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits,punctuation') }}"
      ansible.builtin.debug:
        var: password

    # Returns a hash of the requested type.
    # Requires the 'passlib' Python module on Darwin.
    - name: Hash a password.
      vars:
        password: abcd
        salt: "{{ lookup('community.general.random_string', special=false) }}"
      ansible.builtin.debug:
        var: password | password_hash('sha512', salt)

    - name: Get a variable's type.
      ansible.builtin.debug:
        var: "'string' | type_debug"

    - name: Make assertions.
      ansible.builtin.assert:
        that:
          - 12 | type_debug == "int"
          - 12 < 24

- name: Show off Ansible's testing
  hosts: all
  vars:
    resource_url: "https://example.com/users/foo/resources/bar"
    random_string: "{{ lookup('password', '/dev/null length=8 chars=ascii_letters') }}"
  tasks:

    - name: Check a variable is a string.
      ansible.builtin.debug:
        var: "'{{ random_string }}' is string"

    - name: Check a value is an integer.
      ansible.builtin.debug:
        var: 34 is integer

    - name: Check a given URL is in fact an URL.
      ansible.builtin.debug:
        var: "'{{ resource_url }}' is url"

    - name: Compare a semver version number.
      ansible.builtin.debug:
        var: "'2.0.0-rc.1+build.123' is version('2.1.0-rc.2+build.423', 'ge', version_type='semver')"

    # 'match' succeeds the pattern is **at the beginning** of the string.
    # 'search' succeeds the pattern is **anywhere** within the string.
    # 'regex' works like 'search', but can be configured to perform other
    #   tests by passing the 'match_type' keyword argument.
    # 'match_type' determines the 're' method used to perform the search.
    # All of the string tests can also take the optional 'ignorecase' and
    # 'multiline' arguments.
    - name: Test a substring is present in a string.
      ansible.builtin.debug:
        msg: "{{ item }}"
      with_items:
        - "{{ resource_url is match('https://example.com/users/.*/resources') }}"
        - "{{ resource_url is search('users/.*/resources/.*') }}"
        - "{{ resource_url is search('USERS', ignorecase=true) }}"
        - "{{ resource_url is regex('example\\.com/\\w+/foo') }}"

    - name: Get specific lines from walls of text.
      ansible.builtin.debug:
        msg: "{{ previous_task.stdout | regex_findall('Infra Phase complete, .*') }}"
    - name: Test specific lines from walls of text.
      ansible.builtin.debug:
        msg: >-
          {{
            (
              previous_task.stdout
              | regex_findall('Infra Phase complete, .*')
            ) is not search('0/')
          }}"

- name: Show off Ansible's loops
  hosts: all
  tasks:

    # See https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html
    # for the full list of special variables.
    - name: Get the values of some special variables.
      ansible.builtin.debug:
        var: "{{ item }}"
      with_items: ["ansible_local", "playbook_dir", "role_path"]

    - name: Iterate through a nested loop.
      vars:
        middles:
          - 'middle1'
          - 'middle2'
      ansible.builtin.debug:
        msg: "{{ item[0] }}, {{ item[1] }}, {{ item[2] }}"
      with_nested:
        - ['outer1', 'outer2']
        - "{{ middles }}"
        - ['inner1', 'inner2']
