Додавання до списків або додавання ключів до словників у Ansible


34

(Пов’язані з зворотними дзвінками або гачками, і ряд завдань, що використовуються повторно, у ролях 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'

Чи є відповідним способом це зробити, щоб просто обробити файл конфігурації кілька разів (один раз за розширення) з регулярним виразом, який витягує поточне значення, аналізує його, а потім переписує? Якщо так, то як зробити цей ідентифікатор протягом кількох прогонів?

Що робити, якщо конфігурацію важче, ніж це для аналізу, і це не так просто, як додавання іншого значення, розділеного комами? Подумайте файли конфігурації XML.


Знаєте, що? Мені подобається розріз вашого побічного ефекту ☺
DomQ

Відповіді:


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

ні, і це справді питання. В одному розгортанні базовою роллю може бути Аль
Крейг Рінгер

4
Схоже, якщо ви спробуєте зробити це для об'єднання двох списків, він вважає, що це нескінченно рекурсивний шаблон, оскільки ліва сторона також знаходиться на правій. Я нерозумію, як це використовувати?
Ібрагім

2
@spectras Принаймні щодо відповіді 2.7 це НЕ працює. Як запропонував Ібрагім, це спричиняє помилку: "в рядку шаблону виявлено рекурсивний цикл".
рлуба

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(FIXED)
Макс Ковган

згідно USECASE # 4, я додав значення за замовчуванням для обробки невизначеною помилки в моєму сценарії: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. Невизначена помилка виникає, коли використовується деяка фільтрація або відсутні результати.
СК Венкат

Г-н SK Venkat, зразок коду тут лише демонструє дуже специфічну річ (додавання словникових елементів з кортежів). Якщо вам потрібно зробити щось інше, цей код не є вашою копіювальною пастою.
Макс Ковган

3

вам потрібно розділити петлю на 2

--- 
- господарі: localhost
  завдання: 
    - include_vars: стеки
    - set_facts: role = {{stacks.Roles | розділити ('')}}
    - включати: addhost.yml
      with_items: "{{ролі}}"

та addhost.yml

- set_facts: назва групи = {{item}}
- set_facts: ips = {{stacks [item] | split ('')}}
- локальна перевірка: add_host hostname = {{item}} ім'я групи = {{ім'я групи}}
  with_items: {{ips}}

1

Не впевнені, коли вони додали це, але принаймні для словників / хешів (НЕ списки / масиви) ви можете встановити змінну hash_behaviour , наприклад так: hash_behaviour = mergeу вашому ansible.cfg.

У мене було досить декількох годин, щоб випадково натрапити на цю установку: S


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

0

Майже всі відповіді тут потребують змін у завданнях, але мені потрібно було динамічно об’єднувати словники у визначенні 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] }}"

Це просто фрагмент, але ви повинні зрозуміти, як він працює. Примітка: пошук ('імена', '') доступний з мовою 2.8

Я думаю, було б також можливим об'єднати всі змінні dictionary_of_bla.*в один словник під час виконання, використовуючи той самий пошук.

Перевага такого підходу полягає в тому, що вам не потрібно встановлювати точні списки імен змінних, а лише шаблон і користувач можуть його задавати динамічно.


-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
Схоже, ви говорите, що додаток слід змінити, щоб подолати обмеження в системі управління конфігурацією, або я повинен відмовитися від виконання повторно використовуваних ролей.
Крейг Рінгер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.