Different behaviour between group_vars/all and vars_files/myvars.yml

For the same playbook, if my variables are defined in a file (let name it myvars.yml) specified with vars_files statement it works but if the same variables are defined in group_vars/all it don’t.

Example my playbook and it’s associated files using var_files/myvars.yml

playbook.yml


  • hosts: all
    sudo: yes
    vars_files:
  • myvars.yml
    roles:
  • usertest

myvars.yml


users:

  • username: timmy
    gecos: Timmy
    groups:
  • group1
  • group2
  • username: tony
    gecos: Tony
    groups:
  • group1
  • group3

roles/usertest/tasks/main.yml

  • include: tasks_user.yml user=$item
    with_items: $users

roles/usertest/tasks/task_user.yml (excerpt)


  • name: create user ${user.username}
    action: user name=${user.username} comment=${user.gecos}
  • name: “Create group”
    group: name=$item state=present
    with_items: ${user.groups}

  • name: add user to groups
    action: user name=${user.username} groups=$item append=yes
    with_items: ${user.groups}

When I run it, everything fine :

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [127.0.0.1]

TASK: [create user timmy] *****************************************************
ok: [127.0.0.1] => (item={‘username’: ‘timmy’, ‘gecos’: ‘Timmy’, ‘groups’: [‘group1’, ‘group2’]})

TASK: [Create group] **********************************************************
ok: [127.0.0.1] => (item=group1)
ok: [127.0.0.1] => (item=group2)

TASK: [add user to groups] ****************************************************
ok: [127.0.0.1] => (item=group1)
ok: [127.0.0.1] => (item=group2)

TASK: [create user tony] ******************************************************
ok: [127.0.0.1] => (item={‘username’: ‘tony’, ‘gecos’: ‘Tony’, ‘groups’: [‘group1’, ‘group3’]})

TASK: [Create group] **********************************************************
ok: [127.0.0.1] => (item=group1)
ok: [127.0.0.1] => (item=group3)

TASK: [add user to groups] ****************************************************
ok: [127.0.0.1] => (item=group1)
ok: [127.0.0.1] => (item=group3)

PLAY RECAP ********************************************************************
127.0.0.1 : ok=7 changed=0 unreachable=0 failed=0

Now instead of using an external file to define my users setting I want to put them in group_vars/all :

playbook.yml : I remove vars_files


  • hosts: all
    sudo: yes
    roles:
  • usertest

myvars.yml : deleted, users definition set in group_vars/all instead (same yaml)


users:

  • username: timmy
    gecos: Timmy
    groups:
  • group1
  • group2
  • username: tony
    gecos: Tony
    groups:
  • group1
  • group3

roles/usertest/tasks/main.yml : nothing changed

  • include: tasks_user.yml user=$item
    with_items: $users

roles/usertest/tasks/task_user.yml (excerpt) : nothing changed


  • name: create user ${user.username}
    action: user name=${user.username} comment=${user.gecos}
  • name: “Create group”
    group: name=$item state=present
    with_items: ${user.groups}

  • name: add user to groups
    action: user name=${user.username} groups=$item append=yes
    with_items: ${user.groups}

And when I run it, $users is not expended or something like that :

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [127.0.0.1]

TASK: [create user ${user.username}] ******************************************
ok: [127.0.0.1] => (item=$users)

TASK: [Create group] **********************************************************
fatal: [127.0.0.1] => with_items expects a list

FATAL: all hosts have already failed – aborting

PLAY RECAP ********************************************************************
to retry, use: --limit @/Users/ydavid/playbook-test.retry

127.0.0.1 : ok=2 changed=0 unreachable=1 failed=0

It create a user named ${user.username} and fail on the loop over groups because as $user is not expanded $user.groups is not a list

The problem comme from the association include and with_item because group_vars/all is readed correctly if I don’t use a loop

Must I open an issue ? Or may I did something wrong ?

Thanks for your help

​This is your problem. "include:" combined with "with_items" is a non
documented, non supported idiom.
While this works​ when defined in a vars file ( = same variables for all
hosts, where this can work in a consequent way0), it can't when defined at
inventory level, which group_vars/all is, and where you could give
different variable values for different hosts: this can't work, as
include+with items is parsed at the beginning, before inventory variables
is looked at!

Don't try both though, It is a deprecated feature in 1.4, and will probably
be removed in 1.5.

Serge

That, and also this syntax is incorrect because it uses legacy variables that will be going away:

with_items: ${user.groups}

Do this:

with_items: user.groups

Thanks!

The official docs already don’t do this, but there are a lot of old not well updated articles on the internet.

I strongly recommend starting with the official docs and github.com/ansible/ansible-examples for looking at things when possible.

Thanks!

Thanks for this answer this what I thought, but I wasn’t understood why it worked for one but not for the other, now I understand.

I have to found an another way to do want I want but how ?
How can I do nested loop ?

I have n users et for each user m groups, the with_items synthax cannot be used, this is why I’ve made an include/with_items (first loop) than in my included playbook a with_item on a task (second loop).

Do you an idea to do this ?

Thanks

Thanks for those points, I admit the synthax of variable are quite unclear for me :

  • $myvar
  • ${myvar}
  • {{ myvar }}
  • myvar
  • myvar.nestedvar
  • mavar[“nestedvar”]

So many synthax I had to re-read the doc.

And +1 for old tuto on Internet, Ansible is quite young but it progress so quickly…

​There are a couple of lookup plugins that allow you to do just that,
with_together and with_nested​, the latter should be what you seek I think.

Ansible 1.4 just released add the ability to do what I want :
http://www.ansibleworks.com/docs/playbooks_loops.html#looping-over-subelements

Vive Ansible !!

Ansible 1.4 just released add the ability to do what I want :

http://www.ansibleworks.com/docs/playbooks_loops.html#looping-over-subelements

Yeah, that's a very nice plugin :-D​​

Vive Ansible !!

​Lu & approuvé :)​

Done…

my playbook to manage users is finished, if someone is interested, here it is :

The configuration made in group_vars :

users:

  • username: timmy
    password: $6$rounds=60000$jnCPesFDgbvLtCL8$0p/F80qT/LlVutQ2QX4nSiTa6sRlKRVbpCBM4497PXJJLdIW16Nz1JyFpuszgYxvT5IV5eIas8toKtPdOnriy/
    userfullname: “Timmy”
    groups:
  • timmy
  • sudo
  • username: tony
    password: $6$rounds=60000$jnCPesFDgbvLtCL8$0p/F80qT/LlVutQ2QX4nSiTa6sRlKRVbpCBM4497PXJJLdIW16Nz1JyFpuszgYxvT5IV5eIas8toKtPdOnriy/
    userfullname: Tony
    groups:
  • tony
  • timmy

And the tasks, the group task use the new with_subelements directive…
(sorry task name in french)