Question:
I’m looking for advice. I have the following code that creates a list dynamically that I can then later use in a template.
This is a copy of the test code I put together – for the actual role I just added the admins|regex_replace variable into the j2 template.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
--- - hosts: localhost gather_facts: false vars: # define empty admins var first so ansible doesn't complain admins: admin_accounts: - name: john uid: 1000 group: sysadmin shell: /bin/bash comment: "Unix Administrator" - name: paul uid: 1001 group: sysadmin shell: /bin/bash comment: "Unix Administrator" - name: george uid: 1002 group: sysadmin shell: /bin/bash comment: "Unix Administrator" - name: ringo uid: 1003 group: sysadmin shell: /bin/bash comment: "Unix Administrator" tasks: - name: build array of admin user names set_fact: admins="{{ admins}} {{ item.name }}" with_items: "{{ admin_accounts }}" # print out the fact piping through two jinja2 filters # careful with word wrapping - debug: msg={{ admins | regex_replace( '\s+',', ' ) | regex_replace`(',\s(.*)','\\1') }}` |
This gives me the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
PLAY [localhost] *************************************************************** TASK [build array of admin user names] ***************************************** ok: [localhost] => (item={u'comment': u'Unix Administrator', u'shell': u'/bin/bash', u'group': u'sysadmin', u'name': u'john', u'uid': 1000}) ok: [localhost] => (item={u'comment': u'Unix Administrator', u'shell': u'/bin/bash', u'group': u'sysadmin', u'name': u'paul', u'uid': 1001}) ok: [localhost] => (item={u'comment': u'Unix Administrator', u'shell': u'/bin/bash', u'group': u'sysadmin', u'name': u'george', u'uid': 1002}) ok: [localhost] => (item={u'comment': u'Unix Administrator', u'shell': u'/bin/bash', u'group': u'sysadmin', u'name': u'ringo', u'uid': 1003}) TASK [debug] ******************************************************************* ok: [localhost] => { "msg": "john, paul, george, ringo" } PLAY RECAP ********************************************************************* localhost : ok=2 changed=0 unreachable=0 failed=0 |
So…I get what I need, but am I going about it the right way?
Ansible version is 2.0.2.0 running on Centos 7.2.
Thanks in advance.
Edit: The resultant filter ended up looking like this:
1 2 3 4 5 |
- name: build list of admin user names set_fact: admin_list: "{{ admin_accounts | selectattr('state', 'equalto', 'present') | map(attribute='name') | join(', ') }}" - debug: msg={{ admin_list }} |
Having added another parameter to the yaml:
1 2 |
state: absent |
Ringo was left out, as desired.
Answer:
Filters will operate on lists, so the with_items is really wasteful, and the regex stuff is pretty obtuse for what you’re doing. Do you really want a comma-separated string, or do you just want a list of the usernames extracted from the admin_accounts
list?
If you just want the list, why not:
1 2 3 |
set_fact: admin_usernames: "{{ admin_accounts | map(attribute='name') | list }}" |
… and if you really want the comma-separated list as a flat string, just add a join filter:
1 2 3 |
set_fact: admin_usernames: "{{ admin_accounts | map(attribute='name') | join(', ') }}" |
If your ultimate target is a template, though, I’d suggest doing this inside the template, since this looks pretty formatting-related as opposed to logic-related (unless you’re just simplifying for Stack Overflow purposes)…