deferred evaluation (?)

I’m trying to loop over a set of strings with ansible.builtin.debug, and I want to produce a three-part message for each string, like this:

  • name: Demo expressions
    ansible.builtin.debug:
    msg:
  • ‘{{ item }}’
  • evaluate item as a Jinja2 expression
  • like previous, but with “| bool” appended
    loop:
  • “0”
  • “1”
  • “2”
  • “[‘aa’, ‘bb’, ‘cc’] | intersect([‘bb’, ‘cc’])”
  • “[‘aa’, ‘bb’, ‘cc’] | intersect([‘bb’, ‘cc’]) | length > 0”

The first part of the message should show the string, and it does.
The second part somehow needs to show the result of evaluating the string as a Jinja2 expression.
The third part is supposed to append “| bool” onto the string, evaluate that as a Jinja2 expression, and show the result.

I feel like there should be some way to do this with lookup(‘items’,…), but I’m having no luck. I’d appreciate any suggestions. Thanks,

try the template lookup

I’m confused. The template lookup wants a [list of] file[s]. I’d rather not write these strings out to temp files just to get them templated. Or am I misinterpreting your suggestion?

post expected result

Sure. Here’s a complete example where the debug task’s output msg contains exactly what I want. However, instead of each item being a 3-element list of strings, I want to pass in a single string, and use that string in various ways within the msg: expressions to accomplish the same thing.

To be clear: as presented below, this problem isn’t worth solving. After all, there’s the playbook down below already! But that’s not the point. The point is to understand effective run-time techniques to build strings containing Jinja2 expressions and have them evaluated. (“Templated” I guess is the verb rather than “evaluated,” but that feels backwards. In my brain, “to template” means to examine a sufficiently large set of outputs and create a template adequate to reproduce those outputs from reasonable inputs. But I digress.)

Apparently it’s possible to write such strings to a file and use lookup(‘template’,tmpfilename), but there doesn’t seem to be the equivalent of lookup(‘template’,jinja2_expression_string). Not that I have found anyway.

[utoddl@tango ansible]$ **cat deferred.yml** 
---
# deferred.yml
- name: Deferred evaluation demo
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Evaluate booleanness of various expressions
      ansible.builtin.debug:
        msg:
          - '{{ item.0 }}'
          - '{{ item.1 }}'
          - '{{ item.2 }}'
      loop:
        - [   "0",
           "{{ 0 }}",
           "{{ 0 | bool }}"]
        - [   "1",
           "{{ 1 }}",
           "{{ 1 | bool }}"]
        - [   "2",
           "{{ 2 }}",
           "{{ 2 | bool }}"]
        - [   "['aa', 'bb', 'cc'] | intersect(['bb', 'cc'])",
           "{{ ['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) }}",
           "{{ ['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) | bool }}"]
        - [   "['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) | length > 0",
           "{{ ['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) | length > 0 }}",
           "{{ ['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) | length > 0 | bool }}"]
[utoddl@tango ansible]$ **ansible-playbook deferred.yml**

PLAY [Deferred evaluation demo] *************************************************************************

TASK [Evaluate booleanness of various expressions] ******************************************************
ok: [localhost] => (item=['0', '0', False]) => {
    "msg": [
        "0",
        "0",
        false
    ]
}
ok: [localhost] => (item=['1', '1', True]) => {
    "msg": [
        "1",
        "1",
        true
    ]
}
ok: [localhost] => (item=['2', '2', False]) => {
    "msg": [
        "2",
        "2",
        false
    ]
}
ok: [localhost] => (item=["['aa', 'bb', 'cc'] | intersect(['bb', 'cc'])", ['bb', 'cc'], False]) => {
    "msg": [
        "['aa', 'bb', 'cc'] | intersect(['bb', 'cc'])",
        [
            "bb",
            "cc"
        ],
        false
    ]
}
ok: [localhost] => (item=["['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) | length > 0", True, True]) => {
    "msg": [
        "['aa', 'bb', 'cc'] | intersect(['bb', 'cc']) | length > 0",
        true,
        true
    ]
}

PLAY RECAP **********************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Create a template. For example,

cat create_test.j2

{% for i in strings %}
{{ i }} = {{ '{{' }} {{ i }} {{ '}}' }}
{% endfor %}

Then, the below playbook

cat pb.yml

- hosts: localhost
  tasks:
    - template:
        src: create_test.j2
        dest: /tmp/test.j2
      vars:
        strings:
          - '0'
          - '1'
          - "['aa', 'bb', 'cc']|intersect(['bb', 'cc'])"
          - "['aa', 'bb', 'cc']|intersect(['bb', 'cc'])|length > 0"
    - debug:
        msg: "{{ lookup('template', '/tmp/test.j2') }}"

gives abridged

  msg: |-
    0 = 0
    1 = 1
    ['aa', 'bb', 'cc']|intersect(['bb', 'cc']) = ['bb', 'cc']
    ['aa', 'bb', 'cc']|intersect(['bb', 'cc'])|length > 0 = True