(Относится к Обратные вызовы или хуки, а также многоразовые серии задач в ролях Ansible):
Есть ли лучший способ добавить в список или добавить ключ в словарь в Ansible, чем (ab), используя выражение шаблона jina2?
Я знаю, что вы можете сделать что-то вроде:
- name: this is a hack
shell: echo "{% originalvar.append('x') %}New value of originalvar is {{originalvar}}"
но разве для этого не существует мета-задачи или помощника?
Он кажется хрупким, недокументированным и основан на множестве предположений о том, как переменные работают в Ansible.
Мой вариант использования - несколько ролей (расширения сервера базы данных), каждая из которых должна предоставить некоторую конфигурацию базовой роли (серверу базы данных). Это не так просто, как добавить строку в файл конфигурации сервера db; каждое изменение применяется к та же линия, например расширения bdr
и pg_stat_statements
оба должны появиться в целевой строке:
shared_preload_libaries = 'bdr, pg_stat_statements'
Можно ли с помощью Ansible обработать файл конфигурации несколько раз (один раз для каждого расширения) с помощью регулярного выражения, которое извлекает текущее значение, анализирует его и затем перезаписывает? Если да, то как сделать этот идемпотент в нескольких прогонах?
Что, если конфигурацию сложнее проанализировать, и это не так просто, как добавить другое значение, разделенное запятыми? Подумайте о файлах конфигурации XML.
Начиная с 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
Вы можете объединить два списка в переменной с помощью +
. Скажите, что у вас есть 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 }}"
Когда роль запускается на любом из тестовых серверов, будут добавлены дополнительные расширения.
Я не уверен, что это работает и со словарями, но также будьте осторожны с пробелами и оставляйте висящую запятую в конце строки.
вам нужно разбить петлю на 2
--- - hosts: localhost tasks: - include_vars: stacks - set_facts: roles={{stacks.Roles | split(' ')}} - include: addhost.yml with_items: "{{roles}}"
и addhost.yml
- set_facts: groupname={{item}} - set_facts: ips={{stacks[item]|split(' ')}} - local_action: add_host hostname={{item}} groupname={{groupname}} with_items: {{ips}}
Почти все ответы здесь требуют изменения задач, но мне нужно было динамически объединять словари в определении vars, а не во время выполнения.
Например. Я хочу определить несколько общих варов в 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', '') доступен начиная с ansible 2.8
Я думаю, можно было бы объединить все переменные dictionary_of_bla.*
в один словарь во время выполнения, используя тот же поиск.
Преимущество этого подхода в том, что вам не нужно задавать точные списки имен переменных, а только шаблон и пользователь могут устанавливать их динамически.
Точно сказать не могу когда они добавили это, но, по крайней мере, для словарей / хэшей (НЕ списков / массивов) вы можете установить переменную hash_behaviour, вот так: hash_behaviour = merge
в твоем ansible.cfg
.
Мне потребовалось несколько часов, чтобы случайно наткнуться на этот параметр: S
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.
Это не редкость для систем автоматизации. Примером является Debian exim4
пакет.