Подтвердить что ты не робот

Использование 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, и результат был идентичным.

4b9b3361

Ответ 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