在 Ansible 中一起使用 set_facts 和 with_items
Using set_facts and with_items together in Ansible
我目前使用的是 Ansible 1.7.2。我有以下测试剧本:
---
- hosts: localhost
tasks:
- name: set fact 1
set_fact: foo="[ 'zero' ]"
- name: set fact 2
set_fact: foo="{{ foo }} + [ 'one' ]"
- name: set fact 3
set_fact: foo="{{ foo }} + [ 'two', 'three' ]"
- name: set fact 4
set_fact: foo="{{ foo }} + [ '{{ item }}' ]"
with_items:
- four
- five
- six
- debug: var=foo
第一个任务设置一个事实,这是一个包含一个项目的列表。后续任务会使用更多值附加到该列表。前三个任务按预期工作,但最后一个没有。这是我 运行 时的输出:
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [set fact 1] ************************************************************
ok: [localhost]
TASK: [set fact 2] ************************************************************
ok: [localhost]
TASK: [set fact 3] ************************************************************
ok: [localhost]
TASK: [set fact 4] ************************************************************
ok: [localhost] => (item=four)
ok: [localhost] => (item=five)
ok: [localhost] => (item=six)
TASK: [debug var=foo] *********************************************************
ok: [localhost] => {
"foo": [
"zero",
"one",
"two",
"three",
"six"
]
}
PLAY RECAP ********************************************************************
localhost : ok=6 changed=0 unreachable=0 failed=0
鉴于任务 4 中的 with_items 以及输出显示任务正确迭代该列表中的项目这一事实,我本希望结果包含从零到六的所有数字。但最后一项任务似乎只对列表中的最后一项进行评估 set_fact 。这可能是 Ansible 中的错误吗?
编辑:我也在 ansible 1.8 上测试了这个,输出是相同的。
看起来这种行为是 Ansible 目前的工作方式,尽管有很多人希望修复它以按需要工作。目前有一个 pull request 具有所需的功能,因此希望它最终会被合并到 Ansible 中。
有一个解决方法可能会有所帮助。您可以为每个 set_fact 迭代获得 "register" 结果,然后将该结果映射到列表:
---
- hosts: localhost
tasks:
- name: set fact
set_fact: foo_item="{{ item }}"
with_items:
- four
- five
- six
register: foo_result
- name: make a list
set_fact: foo="{{ foo_result.results | map(attribute='ansible_facts.foo_item') | list }}"
- debug: var=foo
输出:
< TASK: debug var=foo >
---------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
ok: [localhost] => {
"var": {
"foo": [
"four",
"five",
"six"
]
}
}
Jinja 2.6 没有地图功能。因此,另一种方法是:
set_fact: foo="{% for i in bar_result.results %}{{ i.ansible_facts.foo_item }}{%endfor%}"
正如其他人评论中提到的,这里给出的最佳解决方案在 Ansible 2.2 中对我不起作用,尤其是在还使用 with_items
时。
看来 OP 的预期方法现在确实有效,只是对 item
的引用稍作改动。
- set_fact: something="{{ something + [ item ] }}"
with_items:
- one
- two
- three
还有一个更长的例子,我处理了列表未定义的初始情况并添加了一个可选的 when
因为这也让我感到悲伤:
- set_fact: something="{{ something|default([]) + [ item ] }}"
with_items:
- one
- two
- three
when: item.name in allowed_things.item_list
2018-06-08 更新:我之前的回答有点乱,所以我回来再看一遍。这是一种更简洁的 Jinja2 方法。
- name: Set fact 4
set_fact:
foo: "{% for i in foo_result.results %}{% do foo.append(i) %}{% endfor %}{{ foo }}"
我添加这个答案是因为 Ansible 2.2+ 的当前最佳答案没有完全涵盖原始问题。感谢 Russ Huguley 的回答,这让我朝着正确的方向前进,但它给我留下了一个连接的字符串而不是列表。该解决方案获得了一个列表,但变得更加 hacky。我希望这能以更清洁的方式得到解决。
- name: build foo_string
set_fact:
foo_string: "{% for i in foo_result.results %}{{ i.ansible_facts.foo_item }}{% if not loop.last %},{% endif %}{%endfor%}"
- name: set fact foo
set_fact:
foo: "{{ foo_string.split(',') }}"
我正在四处寻找这个问题的答案。我发现这很有帮助。该模式在 with_items.
的文档中并不明显
https://github.com/ansible/ansible/issues/39389
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: set_fact
set_fact:
foo: "{{ foo }} + [ '{{ item }}' ]"
with_items:
- "one"
- "two"
- "three"
vars:
foo: []
- name: Print the var
debug:
var: foo
以下适合我:
- name: set fact
set_fact:
foo_item: "{{foo_item | default([]) + [item]}}"
loop:
- four
- five
- six
我目前使用的是 Ansible 1.7.2。我有以下测试剧本:
---
- hosts: localhost
tasks:
- name: set fact 1
set_fact: foo="[ 'zero' ]"
- name: set fact 2
set_fact: foo="{{ foo }} + [ 'one' ]"
- name: set fact 3
set_fact: foo="{{ foo }} + [ 'two', 'three' ]"
- name: set fact 4
set_fact: foo="{{ foo }} + [ '{{ item }}' ]"
with_items:
- four
- five
- six
- debug: var=foo
第一个任务设置一个事实,这是一个包含一个项目的列表。后续任务会使用更多值附加到该列表。前三个任务按预期工作,但最后一个没有。这是我 运行 时的输出:
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [set fact 1] ************************************************************
ok: [localhost]
TASK: [set fact 2] ************************************************************
ok: [localhost]
TASK: [set fact 3] ************************************************************
ok: [localhost]
TASK: [set fact 4] ************************************************************
ok: [localhost] => (item=four)
ok: [localhost] => (item=five)
ok: [localhost] => (item=six)
TASK: [debug var=foo] *********************************************************
ok: [localhost] => {
"foo": [
"zero",
"one",
"two",
"three",
"six"
]
}
PLAY RECAP ********************************************************************
localhost : ok=6 changed=0 unreachable=0 failed=0
鉴于任务 4 中的 with_items 以及输出显示任务正确迭代该列表中的项目这一事实,我本希望结果包含从零到六的所有数字。但最后一项任务似乎只对列表中的最后一项进行评估 set_fact 。这可能是 Ansible 中的错误吗?
编辑:我也在 ansible 1.8 上测试了这个,输出是相同的。
看起来这种行为是 Ansible 目前的工作方式,尽管有很多人希望修复它以按需要工作。目前有一个 pull request 具有所需的功能,因此希望它最终会被合并到 Ansible 中。
有一个解决方法可能会有所帮助。您可以为每个 set_fact 迭代获得 "register" 结果,然后将该结果映射到列表:
---
- hosts: localhost
tasks:
- name: set fact
set_fact: foo_item="{{ item }}"
with_items:
- four
- five
- six
register: foo_result
- name: make a list
set_fact: foo="{{ foo_result.results | map(attribute='ansible_facts.foo_item') | list }}"
- debug: var=foo
输出:
< TASK: debug var=foo >
---------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
ok: [localhost] => {
"var": {
"foo": [
"four",
"five",
"six"
]
}
}
Jinja 2.6 没有地图功能。因此,另一种方法是:
set_fact: foo="{% for i in bar_result.results %}{{ i.ansible_facts.foo_item }}{%endfor%}"
正如其他人评论中提到的,这里给出的最佳解决方案在 Ansible 2.2 中对我不起作用,尤其是在还使用 with_items
时。
看来 OP 的预期方法现在确实有效,只是对 item
的引用稍作改动。
- set_fact: something="{{ something + [ item ] }}"
with_items:
- one
- two
- three
还有一个更长的例子,我处理了列表未定义的初始情况并添加了一个可选的 when
因为这也让我感到悲伤:
- set_fact: something="{{ something|default([]) + [ item ] }}"
with_items:
- one
- two
- three
when: item.name in allowed_things.item_list
2018-06-08 更新:我之前的回答有点乱,所以我回来再看一遍。这是一种更简洁的 Jinja2 方法。
- name: Set fact 4
set_fact:
foo: "{% for i in foo_result.results %}{% do foo.append(i) %}{% endfor %}{{ foo }}"
我添加这个答案是因为 Ansible 2.2+ 的当前最佳答案没有完全涵盖原始问题。感谢 Russ Huguley 的回答,这让我朝着正确的方向前进,但它给我留下了一个连接的字符串而不是列表。该解决方案获得了一个列表,但变得更加 hacky。我希望这能以更清洁的方式得到解决。
- name: build foo_string
set_fact:
foo_string: "{% for i in foo_result.results %}{{ i.ansible_facts.foo_item }}{% if not loop.last %},{% endif %}{%endfor%}"
- name: set fact foo
set_fact:
foo: "{{ foo_string.split(',') }}"
我正在四处寻找这个问题的答案。我发现这很有帮助。该模式在 with_items.
的文档中并不明显https://github.com/ansible/ansible/issues/39389
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: set_fact
set_fact:
foo: "{{ foo }} + [ '{{ item }}' ]"
with_items:
- "one"
- "two"
- "three"
vars:
foo: []
- name: Print the var
debug:
var: foo
以下适合我:
- name: set fact
set_fact:
foo_item: "{{foo_item | default([]) + [item]}}"
loop:
- four
- five
- six