deferred evaluation (?)

34 views
Skip to first unread message

Todd Lewis

unread,
Jul 27, 2023, 4:22:38 PM7/27/23
to Ansible Project
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,
--
Todd

Brian Coca

unread,
Jul 27, 2023, 4:52:24 PM7/27/23
to ansible...@googlegroups.com
try the template lookup

--
----------
Brian Coca

Todd Lewis

unread,
Jul 27, 2023, 5:18:39 PM7/27/23
to Ansible Project
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?

Vladimir Botka

unread,
Jul 27, 2023, 6:03:42 PM7/27/23
to Todd Lewis, ansible...@googlegroups.com
post expected result

--
Vladimir Botka

Todd Lewis

unread,
Jul 27, 2023, 8:54:16 PM7/27/23
to ansible...@googlegroups.com, uto...@gmail.com
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   


On 7/27/23 6:03 PM, Vladimir Botka wrote:
post expected result


-- 
Todd

Vladimir Botka

unread,
Jul 27, 2023, 11:27:49 PM7/27/23
to Todd Lewis, ansible...@googlegroups.com
Create a template. For example,

shell> cat create_test.j2
{% for i in strings %}
{{ i }} = {{ '{{' }} {{ i }} {{ '}}' }}
{% endfor %}

Then, the below playbook

shell> 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

--
Vladimir Botka
Reply all
Reply to author
Forward
0 new messages