问题
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.
---
- 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:
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:
- 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:
state: absent
Ringo was left out, as desired.
回答1:
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:
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:
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)...
回答2:
When there is a need to add both prefix and suffix (and making everything a list), look at:
set_fact:
extended_etcd_endpoints_list: "{{ groups['etcd'] | map('extract', hostvars, ['ansible_default_ipv4','address']) | map('regex_replace', '^(.*)$','https://\\1:2379') | list }}"
What is does: takes the list of all machines in the group etcd, extracts the ipv4 address, adds a prefix of 'https://' and a suffix of ':2379'. At the end, everything is transformed to a list.
来源:https://stackoverflow.com/questions/37675259/correct-way-to-create-dynamic-lists-in-ansible