Добавление к спискам или добавление ключей к словарям в Ansible

34

(Относится к обратным вызовам или перехватам, а также к серии заданий многократного использования в роли Ansible )

Есть ли лучший способ добавить в список или добавить ключ к словарю в Ansible, чем (ab) с помощью выражения шаблона jina2?

Я знаю, что вы можете сделать что-то вроде:

- name: this is a hack
  shell: echo "{% originalvar.append('x') %}New value of originalvar is {{originalvar}}"

но неужели нет мета-задачи или помощника для этого?

Он выглядит хрупким, кажется недокументированным и опирается на множество предположений о том, как переменные работают в Ansible.

Мой вариант использования - это несколько ролей (расширения сервера базы данных), каждая из которых должна предоставить некоторую конфигурацию базовой роли (серверу базы данных). Это не так просто, как добавить строку в файл конфигурации сервера БД; каждое изменение применяется к одной и той же строке , например, к расширениям, bdrи pg_stat_statementsоба должны появляться в целевой строке:

shared_preload_libaries = 'bdr, pg_stat_statements'

Можно ли сделать это в Ansible, просто обработав файл конфигурации несколько раз (один раз для каждого расширения) с помощью регулярного выражения, которое извлекает текущее значение, анализирует его и затем переписывает? Если так, как вы делаете это идемпотентным через несколько прогонов?

Что, если конфигурация сложнее, чем эта, для анализа, и она не так проста, как добавление другого значения через запятую? Подумайте, файлы конфигурации XML.

Крейг Рингер
источник
Знаешь что? Мне нравится отрезок твоего
полного

Ответы:

13

Вы можете объединить два списка в переменной с +. Скажем, у вас есть group_varsфайл с этим содержанием:

---
# group_vars/all
pgsql_extensions:
  - ext1
  - ext2
  - ext3

И это используется в шаблоне, pgsql.conf.j2как:

# {{ ansible_managed }}
pgsql_extensions={% for item in pgsql_extensions %}{{ item }}, {% endfor %}

Затем вы можете добавить расширения к тестовым серверам баз данных следующим образом:

---
# group_vars/testing_db
append_exts:
  - ext4
  - ext5
pgsql_extensions: "{{ pgsql_extensions + append_exts }}"

Когда роль запускается на любом из тестирующих серверов, будут добавлены дополнительные расширения.

Я не уверен, что это работает и для словарей, а также будьте осторожны с пробелами и оставляя в конце строки висячую запятую.

ВНП
источник
Вы можете, но вы должны сделать все это group_vars, роли не могут позаботиться о деталях настройки расширений сами. Это добавление переменных из ролей, которые я особенно ищу, поэтому одна роль может дополнять переменную, представленную другой ролью.
Крейг Рингер
Знает ли ваша базовая роль о каждой роли расширения? У меня был похожий случай, когда я смог оставить конкатенацию до with_itemsпредложения.
GnP
нет, и это действительно проблема. В одном развертывании базовая роль может быть аль
Craig Ringer
4
Кажется, что если вы попытаетесь сделать это, чтобы объединить два списка, он думает, что это бесконечно рекурсивный шаблон, потому что левая сторона также находится на правой стороне. Я неправильно понимаю, как это использовать?
Ибрагим
2
@spectras По крайней мере, в Ansible 2.7 это НЕ работает. Как предположил Ибрагим, это вызывает ошибку: «в строке шаблона обнаружен рекурсивный цикл».
rluba
35

Начиная с Ansible v2.x вы можете сделать это:

# use case I: appending to LIST variable:

      - name: my appender
        set_fact:
          my_list_var: '{{my_list_myvar + new_items_list}}'

# use case II: appending to LIST variable one by one:

      - name: my appender
        set_fact:
          my_list_var: '{{my_list_var + [item]}}'
        with_items: '{{my_new_items|list}}'

# use case III: appending more keys DICT variable in a "batch":

      - name: my appender
        set_fact:
          my_dict_var: '{{my_dict_var|combine(my_new_keys_in_a_dict)}}'

# use case IV: appending keys DICT variable one by one from tuples
      - name: setup list of tuples (for 2.4.x and up
        set_fact:
          lot: >
            [('key1', 'value1',), ('key2', 'value2',), ..., ('keyN', 'valueN',)],
      - name: my appender
        set_fact:
          my_dict_var: '{{my_dict_var|combine({item[0]: item[1]})}}'
        with_items: '{{lot}}'
# use case V: appending keys DICT variable one by one from list of dicts (thanks to @ssc)

  - name: add new key / value pairs to dict
    set_fact:
      my_dict_var: "{{ my_dict_var | combine({item.key: item.value}) }}"
    with_items:
    - { key: 'key01', value: 'value 01' }
    - { key: 'key02', value: 'value 03' }
    - { key: 'key03', value: 'value 04' }

все вышеперечисленное описано в: http://docs.ansible.com/ansible/playbooks_filters.html

Макс Ковган
источник
1
случай использования IV только добавляетсяu'(': u\"'\"}"
ssc
1
спасибо, @ssc. Я заметил, что это не работает с ansible 2.4.x(ИСПРАВЛЕНО)
Макс Ковган
согласно USECASE # 4, я добавил значения по умолчанию для обработки неопределенной ошибки в моем сценарии: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. Неопределенная ошибка возникает, когда используется некоторая фильтрация или результаты не зарегистрированы.
СК Венкат
Г-н С. К. Венкат, пример кода здесь демонстрирует только очень специфическую вещь (добавление элементов словаря из кортежей). Если вам нужно сделать что-то еще, этот код не ваша копия-паста.
Макс Ковган
3

вам нужно разделить цикл на 2

--- 
- hosts: localhost
  задачи: 
    - include_vars: стеки
    - set_facts: role = {{stacks.Roles | Трещина(' ')}}
    - включить: addhost.yml
      with_items: "{{role}}"

и addhost.yml

- set_facts: groupname = {{item}}
- set_facts: ips = {{stacks [item] | split ('')}}
- local_action: add_host hostname = {{item}} groupname = {{groupname}}
  with_items: {{ips}}
Артур Цанг
источник
1

Не уверен, когда они добавили это, но, по крайней мере, для словарей / хэшей (НЕ списки / массивы), вы можете установить переменную hash_behaviour , вот так: hash_behaviour = mergeв вашем ansible.cfg.

Мне понадобилось несколько часов, чтобы случайно наткнуться на эту настройку: S

орешки
источник
это очень удобно, но будьте осторожны, чтобы включить его в существующей кодовой базе. может разбить несколько яиц.
Макс Ковган
0

Почти все ответы здесь требуют изменений в задачах, но мне нужно было динамически объединять словари в определении переменных, а не во время выполнения.

Например, я хочу определить некоторые общие переменные в, all group_varsа затем я хочу расширить их в некоторых других groupили host_vars. Очень полезно при работе на роли.

Если вы попытаетесь использовать фильтры combineили, unionперезаписывающие исходную переменную в файлах var, вы будете заканчивать бесконечный цикл во время создания шаблонов, поэтому я создал этот обходной путь (это не решение).

Вы можете определить несколько переменных на основе некоторого шаблона имени, а затем автоматически загрузить их в роли.

group_vars/all.yml

dictionary_of_bla:
  - name: blabla
    value1 : blabla
    value2 : blabla

group_vars/group1.yml

dictionary_of_bla_group1:
  - name: blabla2
    value1 : blabla2
    value2 : blabla2

фрагмент кода роли

tasks:
  - name: Run for all dictionary_of_bla.* variations
    include_tasks: do_some_stuff.yml
    with_items: "{{ lookup('varnames','dictionary_of_bla.*').split(',') }}"
    loop_control:
      loop_var: _dictionary_of_bla

do_some_stuff.yml

- name: do magic
  magic:
    trick_name: item.name
    trick_value1: item.value1
    trick_value2: item.value2
  with_items: "{{ vars[_dictionary_of_bla] }}"

Это всего лишь фрагмент, но вы должны понять, как это работает. примечание: поиск ('varnames', '') доступен начиная с версии 2.8

Я думаю, было бы также возможно объединить все переменные dictionary_of_bla.*в один словарь во время выполнения, используя тот же поиск.

Преимущество этого подхода состоит в том, что вам не нужно устанавливать точные списки имен переменных, а только шаблон и пользователь могут установить его динамически.

VeselaHouba
источник
-4

Ansibleэто система автоматизации, и, что касается управления файлами конфигурации, она не сильно отличается от apt. Причина, по которой все больше и больше программного обеспечения предлагает возможность считывать фрагменты конфигурации из conf.dкаталога, заключается в том, что такие системы автоматизации могут иметь различные пакеты / роли для добавления конфигурации в программное обеспечение. Я считаю, что философия заключается не в том, Ansibleчтобы делать то, что вы имеете в виду, а в том, чтобы использовать conf.dхитрость. Если конфигурируемое программное обеспечение не предлагает эту функцию, у вас могут быть проблемы.

Поскольку вы упоминаете файлы конфигурации XML, я пользуюсь возможностью, чтобы немного поплакать. Есть причина для традиции Unix использовать простые текстовые файлы конфигурации. Двоичные файлы конфигурации плохо подходят для автоматизации системы, поэтому любой вид двоичного формата доставит вам проблемы и, вероятно, потребует от вас создания программы для обработки конфигурации. (Если кто-то думает, что XML - это простой текстовый формат, он должен проверить свои мозги.)

Теперь по вашей конкретной PostgreSQLпроблеме. PostgreSQLподдерживает conf.dтрюк. Сначала я бы проверил, shared_preload_librariesможно ли указывать несколько раз. Я не нашел в документации ни одного намека на то, что он может, но все равно попробую. Если это не может быть указано несколько раз, я объясню свою проблему PostgreSQLпарням, если у них есть идеи; это PostgreSQLпроблема, а не Ansibleпроблема. Если решения не существует и я действительно не могу объединить разные роли в одну, я бы внедрил систему для компиляции конфигурации на управляемом хосте. В этом случае я бы, вероятно, создал скрипт, /usr/local/sbin/update_postgresql_configкоторый компилировался бы /etc/postgresql/postgresql.conf.jinjaв /etc/postgresql/9.x/main/postgresql.conf. Сценарий будет читать общие библиотеки предварительной загрузки /etc/postgresql/shared_preload_libraries.txt, по одной библиотеке на строку, и предоставлять их jinja.

Это не редкость для систем автоматизации. Примером является exim4пакет Debian .

Антонис Христофидес
источник
PostgreSQL поддерживает conf.dмеханизм включения и, к счастью, использует текстовые файлы. Тем не менее, есть некоторые параметры конфигурации, где несколько расширений могут иметь мнения по этому поводу - например, «увеличить max_wal_senders на 10 от того, что было раньше».
Крейг Рингер
4
Похоже, вы говорите, что приложение должно быть изменено, чтобы обойти ограничения в системе управления конфигурацией, или я должен отказаться от использования повторно используемых ролей.
Крейг Рингер