Использование set_facts и with_items вместе в 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
Учитывая with_items в задаче 4 и тот факт, что результат показывает, что задача правильно повторена по элементам в этом списке, я ожидал, что результат будет содержать все числа от нуля до шести. Но эта последняя задача, по-видимому, оценивает только set_fact с последним элементом в списке. Возможно, это ошибка в Ansible?
Изменить: я также просто протестировал это на незаменимом 1.8, и результат был идентичным.
Ответы
Ответ 1
Похоже, это поведение похоже на то, как работает Ansible, хотя есть большая заинтересованность в исправлении его работы по желанию. В настоящее время тянуть запрос с желаемой функциональностью, поэтому, надеюсь, это в конечном итоге будет включено в Ansible.
Ответ 2
Существует обходное решение, которое может помочь. Вы можете "регистрировать" результаты для каждой итерации set_fact, а затем отображать результаты для списка:
---
- 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"
]
}
}
Ответ 3
Как упоминалось в комментариях других людей, верхнее решение, данное здесь, не работало для меня в Ansible 2.2, особенно когда также используется with_items
.
Похоже, что предполагаемый подход OP работает сейчас с небольшим изменением на цитирование item
.
- set_fact: something="{{ something + [ item ] }}"
with_items:
- one
- two
- three
И более длинный пример, когда я обработал начальный случай списка undefined и добавил необязательный when
, потому что это также вызывало у меня горе:
- set_fact: something="{{ something|default([]) + [ item ] }}"
with_items:
- one
- two
- three
when: item.name in allowed_things.item_list
Ответ 4
Jinja 2.6 не имеет функции отображения. Таким образом, альтернативный способ сделать это:
set_fact: foo="{% for i in bar_result.results %}{{ i.ansible_facts.foo_item }}{%endfor%}"
Ответ 5
Обновлено 2018-08-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 за ваш ответ, который заставил меня двигаться в правильном направлении, но оставил мне строку со списком, а не список. Это решение получает список, но становится еще более хакерским. Я надеюсь, что это будет решено в более чистой манере.
- 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(',') }}"
Ответ 6
Я искал ответ на этот вопрос. Я нашел это полезным. Шаблон не был очевиден в документации для 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