On Sun, May 16, 2021 at 12:23 AM Vladimir Botka wrote:
> third debug task fails because the expansion of the string
> "{{ ... }}" fails before the *or* expression could be evaluated.

Sure, but why is it expanded at all?  You're right that we can
make my already-minimal test when variable Does Not Exist
(dne) even shorter without needing to use hostvars:

- hosts: localhost
  become: false
  vars:
    ivar: '{{dne}}'
  tasks:
    - debug:
        msg: "{{'foo' or ivar}}"

> You'll need a default value if you want to use this kind of
> "lazy evaluation" constructs ...

I had thought ansible variables were lazily evaluated already.
In docs/docsite/rst/reference_appendices/glossary.rst it says:

    Lazy Evaluation
    In general, Ansible evaluates any variables in playbook
    content at the last possible second, which means
    that if you define a data structure that data structure itself
    can define variable values within it, and everything "just
    works" as you would expect.  This also means variable
    strings can include other variables inside of those strings.

This seems to imply that things which aren't ever referenced,
will never be expanded.  There is even an open issue with a
feature idea to force evaluation to be non-lazy:
https://github.com/ansible/ansible/issues/10374

I cannot use a default because this whole thing is relying
on whether it's defined or not later to take different actions.
the fuller example is:

- name: determine_subnet
  when: >
    project == project_bake
    or hostvars[target].ipnet is defined
  set_fact:
    subnet: '{{
      (project == project_bake) | ternary(
        subnet_bake, determined_subnet
    )}}'

the problem here is that determined_subnet is defined like this:

    determined_subnet: '{{subnets[ip_cidrnet]}}'

and the chain for that is:

    ip_host: '{{hostvars[ip_referent].ipnet}}'
    ip_referent: '{{host | d(target | d(inventory_hostname))}}'
    ip_network: "{{ip_host | ipaddr('network')}}"
    ip_cidrnet: '{{ip_network}}/{{ip_prefix}}'

When ipnet (an inventory variable) is not defined,
determined_subnet is still being expanded, even though
project == project_bake, and should therefore never need
to evaluate the second arg to ternary().  For this case, ipnet
is not set.

I've made it work by splitting it into two set_facts with
cascading 'when' clauses, but I don't understand why it's
happening in the first place.  The evaluation does not seem
to be lazy, or it would never need to evaluate an unused arg
right? And it's the same behavior using ternary, if/else, or
a disjunction ("or").

-- 
Scott

-- 
You received this message because you are subscribed to the Google Groups 
"Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to ansible-project+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/ansible-project/CACRKOwy3gcz%2BVRTrbgnZj3CjdAjFQW9v93TAZ4m3Hb7WLkCfog%40mail.gmail.com.

Reply via email to