This is part of the series "The Horrors of Ansible Complex Variables." The results below were achieved with Ansible version 2.8.0.
My attempt to find a working complex variable structure understood by both Ansible and Jinja2 led to this:
---
# filename: dictionary.yml
- name: lists
hosts: localhost
connection: local
vars:
users:
- { username: alice, fullname: "Alice Appleworth" }
- { username: bob, fullname: "Bob Bananarama" }
tasks:
- name: add several users
debug:
msg: "{{ item.name }} {{ item.groups }}"
loop:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
- name: Print users (full object)
debug:
msg: "{{ item }}"
loop: "{{ users }}"
- name: Print users (detailed)
debug:
msg: "User {{ item.username }} is {{ item.fullname }}"
loop: "{{ users }}"
- name: template with the dictionary
template:
src=template.j2
dest=template.txt
That's not strictly a dictionary. I suspect that what it is is a list of lists of dictionary items ... But I'm more concerned that it works than what exactly the structure is.
UPDATE: I used loop:
above: with_items:
will also work (although Ansible's documentation seems to indicate that loop:
is the future). with_dict:
does NOT work.
Here's the template that goes with it:
{# filename: template.j2 #}
List of complete "user" variables:
{% for user in users %}
{{ user }}
{% endfor %}
Showing "user.username, user.fullname":
{% for user in users %}
{{ user.username }}, {{ user.fullname }}
{% endfor %}
Run the playbook:
$ ansible-playbook dictionary.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the
implicit localhost does not match 'all'
PLAY [lists] *****************************************************************************
TASK [Gathering Facts] *******************************************************************
ok: [localhost]
TASK [add several users] *****************************************************************
ok: [localhost] => (item={'name': 'testuser1', 'groups': 'wheel'}) => {
"msg": "testuser1 wheel"
}
ok: [localhost] => (item={'name': 'testuser2', 'groups': 'root'}) => {
"msg": "testuser2 root"
}
TASK [Print users (full object)] *********************************************************
ok: [localhost] => (item={'username': 'alice', 'fullname': 'Alice Appleworth'}) => {
"msg": {
"fullname": "Alice Appleworth",
"username": "alice"
}
}
ok: [localhost] => (item={'username': 'bob', 'fullname': 'Bob Bananarama'}) => {
"msg": {
"fullname": "Bob Bananarama",
"username": "bob"
}
}
TASK [Print users (detailed)] ************************************************************
ok: [localhost] => (item={'username': 'alice', 'fullname': 'Alice Appleworth'}) => {
"msg": "User alice is Alice Appleworth"
}
ok: [localhost] => (item={'username': 'bob', 'fullname': 'Bob Bananarama'}) => {
"msg": "User bob is Bob Bananarama"
}
TASK [template with the dictionary] ******************************************************
ok: [localhost]
PLAY RECAP *******************************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
And look at the resulting template.txt file:
List of complete "user" variables: {'username': 'alice', 'fullname': 'Alice Appleworth'} {'username': 'bob', 'fullname': 'Bob Bananarama'} Showing "user.username, user.fullname": alice, Alice Appleworth bob, Bob Bananarama
This is exactly what I wanted: a variable form that's easy to read and easy to reference in Ansible and Jinja2. In a practical sense, I needed to add some complexity: I wanted to be able to add a list to each user so that I could choose what groups they were members of. See the next entry.