在 Ansible 中创建动态列表的正确方法
Correct way to create dynamic lists in Ansible
我正在寻求建议。我有以下代码动态创建一个列表,稍后我可以在模板中使用它。
这是我放在一起的测试代码的副本 - 对于实际角色,我刚刚将 admins|regex_replace 变量添加到 j2 模板中。
---
- 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') }}`
这给了我以下信息:
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
所以...我得到了我需要的东西,但我的做法是否正确?
Ansible 版本是 2.0.2.0 运行 在 Centos 7.2 上。
提前致谢。
编辑:生成的过滤器最终看起来像这样:
- 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 }}
已将另一个参数添加到 yaml:
state: absent
根据需要,Ringo 被排除在外。
过滤器将对列表进行操作,因此 with_items 真的很浪费,而且正则表达式对于您正在做的事情来说非常迟钝。您真的想要逗号分隔的字符串,还是只想要从 admin_accounts
列表中提取的用户名列表?
如果您只想要列表,为什么不呢:
set_fact:
admin_usernames: "{{ admin_accounts | map(attribute='name') | list }}"
...如果您真的希望以逗号分隔的列表作为扁平字符串,只需添加一个连接过滤器:
set_fact:
admin_usernames: "{{ admin_accounts | map(attribute='name') | join(', ') }}"
不过,如果您的最终目标是模板,我建议您在模板内执行此操作,因为这看起来与格式相关而不是与逻辑相关(除非您只是为了 Stack Overflow 目的而进行简化) ...
当需要添加前缀和后缀(并使所有内容成为列表)时,请查看:
set_fact:
extended_etcd_endpoints_list: "{{ groups['etcd'] | map('extract', hostvars, ['ansible_default_ipv4','address']) | map('regex_replace', '^(.*)$','https://\1:2379') | list }}"
是做什么的:获取 etcd 组中所有机器的列表,提取 ipv4 地址,添加前缀 'https://' 和后缀 ':2379'。
最后,一切都变成了一个列表。
我正在寻求建议。我有以下代码动态创建一个列表,稍后我可以在模板中使用它。
这是我放在一起的测试代码的副本 - 对于实际角色,我刚刚将 admins|regex_replace 变量添加到 j2 模板中。
---
- 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') }}`
这给了我以下信息:
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
所以...我得到了我需要的东西,但我的做法是否正确?
Ansible 版本是 2.0.2.0 运行 在 Centos 7.2 上。
提前致谢。
编辑:生成的过滤器最终看起来像这样:
- 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 }}
已将另一个参数添加到 yaml:
state: absent
根据需要,Ringo 被排除在外。
过滤器将对列表进行操作,因此 with_items 真的很浪费,而且正则表达式对于您正在做的事情来说非常迟钝。您真的想要逗号分隔的字符串,还是只想要从 admin_accounts
列表中提取的用户名列表?
如果您只想要列表,为什么不呢:
set_fact:
admin_usernames: "{{ admin_accounts | map(attribute='name') | list }}"
...如果您真的希望以逗号分隔的列表作为扁平字符串,只需添加一个连接过滤器:
set_fact:
admin_usernames: "{{ admin_accounts | map(attribute='name') | join(', ') }}"
不过,如果您的最终目标是模板,我建议您在模板内执行此操作,因为这看起来与格式相关而不是与逻辑相关(除非您只是为了 Stack Overflow 目的而进行简化) ...
当需要添加前缀和后缀(并使所有内容成为列表)时,请查看:
set_fact:
extended_etcd_endpoints_list: "{{ groups['etcd'] | map('extract', hostvars, ['ansible_default_ipv4','address']) | map('regex_replace', '^(.*)$','https://\1:2379') | list }}"
是做什么的:获取 etcd 组中所有机器的列表,提取 ipv4 地址,添加前缀 'https://' 和后缀 ':2379'。 最后,一切都变成了一个列表。