Are group_vars in ansible not read before any vars_prompt?

Viewed 60

I've defined a file path variable sys_labels in Ansible inventory/group_vars/all/vars pointing to a JSON file.

I'm loading this within the vars section in a playbook via lookup('file', sys_labels) | from_json.

Debugging this in a simple playbook works. But, if I include a vars_prompt that uses the JSON data, it fails. Replacing the sys_labels variable in the vars section with the actual path works, however.
Why is that so?

Works:

---
- hosts: localhost
  gather_facts: false
  vars:
    json: "{{ lookup('file', sys_labels) | from_json }}"
  tasks:
    - name: debug
      debug:
        msg: "{{ json }}"

where sys_labels point to a file labels.json containing a JSON structure, e.g.,

{ 
  "labels": { 
    "label1":"true",
    "label1":"false",
    "label2":"true",
    "label3":"true" 
  } 
}

Adding the vars_prompt fails:

---
- hosts: localhost
  gather_facts: false
  vars:
    json: "{{ lookup('file', sys_labels) | from_json }}"
  vars_prompt:
    - name: label_choice
      prompt: |
        {% for key in json.labels %}
        {{ loop.index0 }} - {{ key }}={{ json.labels[key] }}
        {% endfor %}
        Choose labels to apply [none]
      private: no
  tasks:
    - name: debug
      debug:
        msg: "{{ json }}\n\n{{ label_choice }}"

The error is

ERROR! {{ lookup('file', sys_labels) | from_json }}: 'sys_labels' is undefined.

Replacing the above filepath variable sys_labels with the actual path works again:

---
- hosts: localhost
  gather_facts: false
  vars:
    json: "{{ lookup('file', '/path/to/labels.json') | from_json }}"
  vars_prompt:
    - name: label_choice
      prompt: |
        {% for key in json.labels %}
        {{ loop.index0 }} - {{ key }}={{ json.labels[key] }}
        {% endfor %}
        Choose labels to apply [none]
      private: no
  tasks:
    - name: debug
      debug:
        msg: "{{ json }}\n\n{{ label_choice }}"

This seems strange to me, and it looks like vars_prompt runs before global group_vars are eval'd?

And if so, why does vars_prompt then still look at the vars section of the playbook, but doesn't acknowledge the mapping from within group_vars?

Any pointers appreciated.

I'm on ansible core 2.12.1, python 3.10.1, jinja 3.0.3

1 Answers

It looks like it is indeed the expected behaviour.

From @bcoca, maintainer of Ansible:

at the time vars_prompt runs only extra vars are defined, so the when [the issue on which @bcoca was answering was about a when on vars_prompt, but it applies the same here -- Ed.] will not work with host/group vars nor facts.

Source: https://github.com/ansible/ansible/issues/13263#issuecomment-159037298

What you can do, to come around this issue, is to use the pause module instead.


Given the playbook:

- hosts: localhost
  gather_facts: false
  vars: 
    json: "{{ lookup('file', sys_labels) | from_json }}"

  tasks:
    - pause: 
        prompt: |-
          {% for key in json.labels %}
          {{ loop.index0 }} - {{ key }}={{ json.labels[key] }}
          {% endfor %}
          Choose labels to apply [none]
      register: label_choice

    - name: debug
      debug:
        msg: "{{ json }}\n\n{{ label_choice.user_input }}"

This yields:

TASK [pause] **********************************************************************
[pause]
0 - foo=bar
1 - baz=qux
Choose labels to apply [none]:
foo
ok: [localhost]

TASK [debug] **********************************************************************
ok: [localhost] => 
  msg: |-
    {'labels': {'foo': 'bar', 'baz': 'qux'}}
  
    foo
Related