Dołączanie do list lub dodawanie kluczy do słowników w Ansible

34

(Związane z wywołaniami zwrotnymi lub przechwytywaniem i serią zadań wielokrotnego użytku, w rolach Ansible ):

Czy istnieje lepszy sposób na dołączenie do listy lub dodanie klucza do słownika w Ansible niż (ab) przy użyciu wyrażenia szablonu jina2?

Wiem, że możesz zrobić coś takiego:

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

ale czy naprawdę nie ma w tym rodzaju meta zadania lub pomocnika?

Jest delikatny, wydaje się nieudokumentowany i opiera się na wielu założeniach dotyczących działania zmiennych w Ansible.

Mój przypadek użycia to wiele ról (rozszerzenia serwera bazy danych), z których każda musi dostarczyć pewną konfigurację do roli podstawowej (serwer bazy danych). Nie jest to tak proste, jak dodanie linii do pliku konfiguracyjnego serwera db; każda zmiana dotyczy tej samej linii , np. rozszerzeń bdri pg_stat_statementsmuszą pojawiać się w linii docelowej:

shared_preload_libaries = 'bdr, pg_stat_statements'

Czy Ansible to zrobić, aby po prostu przetworzyć plik konfiguracyjny wiele razy (raz na rozszerzenie) za pomocą wyrażenia regularnego, które wyodrębnia bieżącą wartość, analizuje ją, a następnie przepisuje? Jeśli tak, to jak sprawić, by ten idempotent występował w wielu przebiegach?

Co jeśli konfiguracja jest trudniejsza do przeanalizowania i nie jest tak prosta jak dodanie innej wartości oddzielonej przecinkami? Pomyśl o plikach konfiguracyjnych XML.

Craig Ringer
źródło
Wiesz co? Podoba mi się cięcie twojego
pełnego

Odpowiedzi:

13

Możesz scalić dwie listy w zmiennej z +. Załóżmy, że masz group_varsplik o tej treści:

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

I jest używany w szablonie pgsql.conf.j2takim jak:

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

Następnie możesz dołączyć rozszerzenia do testujących serwerów baz danych w następujący sposób:

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

Po uruchomieniu roli na dowolnym serwerze testowym zostaną dodane dodatkowe rozszerzenia.

Nie jestem pewien, czy to działa również w przypadku słowników, a także bądź ostrożny ze spacjami i pozostawiając wiszący przecinek na końcu linii.

GnP
źródło
Możesz, ale musisz to wszystko zrobić group_vars, role nie mogą zająć się szczegółami konfigurowania samych rozszerzeń. Dołączyłem zmienne z ról , których szczególnie szukam, więc jedną rolę można dołączyć do zmiennej ujawnionej przez inną rolę.
Craig Ringer
Czy Twoja podstawowa rola wie o każdej roli rozszerzenia? Miałem podobny przypadek, w którym mogłem pozostawić konkatenację do with_itemswyroku.
GnP
nie, i to jest naprawdę problem. W jednym wdrożeniu podstawową rolą może być al
Craig Ringer
4
Wygląda na to, że jeśli spróbujesz to zrobić, aby połączyć dwie listy, wydaje się, że jest to nieskończenie rekurencyjny szablon, ponieważ lewa strona znajduje się również po prawej stronie. Czy nie rozumiem, jak z tego korzystać?
Ibrahim,
2
@spectras Przynajmniej od Ansible 2.7 to NIE działa. Jak sugerował Ibrahim, powoduje to błąd: „wykryto pętlę rekurencyjną w łańcuchu szablonu”.
rubauba
35

Od Ansible v2.x możesz to zrobić:

# 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' }

wszystkie powyższe są udokumentowane w: http://docs.ansible.com/ansible/playbooks_filters.html

Max Kovgan
źródło
1
dołączono przypadek użycia IVu'(': u\"'\"}"
ssc
1
dzięki, @ssc. Zauważyłem, że nie działa z ansible 2.4.x(NAPRAWIONO)
Max Kovgan
według USECASE # 4, dodałem wartość domyślną do obsługi niezdefiniowany błąd w moim scenariuszu: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. Nieokreślony błąd pojawia się, gdy używane jest filtrowanie lub nie zarejestrowano żadnych wyników.
SK Venkat
Panie SK Venkat, przykładowy kod tutaj pokazuje tylko bardzo specyficzną rzecz (dodawanie elementów słownika z krotek). Jeśli musisz zrobić coś innego, ten kod nie jest twoją funkcją kopiuj-wklej.
Max Kovgan
3

musisz podzielić pętlę na 2

--- 
- hosts: localhost
  zadania: 
    - include_vars: stosy
    - set_facts: roles = {{stacks.Roles | rozdzielać(' ')}}
    - obejmują: addhost.yml
      with_items: „{{roles}}”

i addhost.yml

- set_facts: nazwa grupy = {{item}}
- set_facts: ips = {{stacks [item] | split ('')}}
- local46: add_host nazwa_hosta = {{item}} nazwa grupy = {{nazwa grupy}}
  with_items: {{ips}}
Arthur Tsang
źródło
1

Nie jestem pewien, kiedy to dodali, ale przynajmniej dla słowników / skrótów (NIE list / tablic), możesz ustawić zmienną hash_behaviour , na przykład: hash_behaviour = mergew swoim ansible.cfg.

Zajęło mi kilka godzin, aby przypadkowo natknąć się na to ustawienie: S.

orzechy
źródło
jest to bardzo przydatne, ale uważaj, aby włączyć e2e na istniejącej bazie kodu. może rozbić niektóre jajka.
Max Kovgan
0

Prawie wszystkie odpowiedzi tutaj wymagają zmian w zadaniach, ale musiałem dynamicznie łączyć słowniki w definicji zmiennych, a nie podczas uruchamiania.

Np. Chcę zdefiniować niektóre wspólne zmienne w, all group_varsa następnie chcę je rozszerzyć w innym grouplub host_vars. Bardzo przydatne podczas pracy dla ról.

Jeśli spróbujesz użyć combinelub unionfiltrów nadpisujących oryginalną zmienną w plikach var, skończysz w nieskończonej pętli podczas tworzenia szablonów, więc stworzyłem to obejście (to nie jest rozwiązanie).

Możesz zdefiniować wiele zmiennych na podstawie pewnego wzorca nazwy, a następnie automatycznie załadować je w roli.

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

fragment kodu roli

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] }}"

To tylko fragment, ale powinieneś dowiedzieć się, jak to działa. Uwaga: wyszukiwanie („varnames”, „”) jest dostępne od wersji 2.8

Wydaje mi się, że byłoby możliwe scalenie wszystkich zmiennych dictionary_of_bla.*w jednym słowniku podczas działania przy użyciu tego samego wyszukiwania.

Zaletą tego podejścia jest to, że nie trzeba ustawiać dokładnych list nazw zmiennych, ale tylko wzorzec i użytkownik może ustawić je dynamicznie.

VeselaHouba
źródło
-4

Ansiblejest systemem automatyzacji i jeśli chodzi o zarządzanie plikami konfiguracyjnymi, nie różni się bardzo od apt. Powodem, dla którego coraz więcej oprogramowania oferuje funkcję odczytu fragmentów konfiguracji z conf.dkatalogu, jest umożliwienie takim systemom automatyzacji, aby różne pakiety / role dodawały konfigurację do oprogramowania. Uważam, że filozofią nie jest Ansiblerobienie tego, co masz na myśli, ale stosowanie tej conf.dsztuczki. Jeśli konfigurowane oprogramowanie nie oferuje tej funkcji, możesz mieć problemy.

Ponieważ wspominasz o plikach konfiguracyjnych XML, korzystam z okazji, by narzekać. Istnieje powód tradycji uniksowej korzystania z plików konfiguracyjnych w postaci zwykłego tekstu. Binarne pliki konfiguracyjne nie nadają się dobrze do automatyzacji systemu, więc każdy rodzaj formatu binarnego sprawi ci kłopotów i prawdopodobnie będzie wymagać utworzenia programu do obsługi konfiguracji. (Jeśli ktoś uważa, że ​​XML jest zwykłym formatem tekstowym, powinien przejść badanie mózgu).

Teraz na twój konkretny PostgreSQLproblem. PostgreSQLobsługuje conf.dlewę. Najpierw sprawdziłbym, czy shared_preload_librariesmożna to określić wiele razy. W dokumentacji nie znalazłem żadnej wskazówki, ale może i tak spróbuję. Jeśli nie można go podać wiele razy, wyjaśnię mój problem PostgreSQLchłopakom na wypadek, gdyby mieli pomysły; to jest PostgreSQLproblem, a nie Ansibleproblem. Jeśli nie ma rozwiązania i naprawdę nie mogłem scalić różnych ról w jedną, zaimplementowałbym system do kompilacji konfiguracji na zarządzanym hoście. W tym przypadku, prawdopodobnie utworzyć skrypt, /usr/local/sbin/update_postgresql_configktóry będzie kompilować /etc/postgresql/postgresql.conf.jinjaw /etc/postgresql/9.x/main/postgresql.conf. Skrypt odczyta współdzielone biblioteki wstępnego ładowania z /etc/postgresql/shared_preload_libraries.txtjednej biblioteki na linię i dostarczy je do jinja.

Często zdarza się, że systemy automatyki to robią. Przykładem jest exim4pakiet Debian .

Antonis Christofides
źródło
PostgreSQL obsługuje conf.dmechanizm dołączania i na szczęście używa plików tekstowych. Istnieją jednak opcje konfiguracji, w których wiele rozszerzeń może mieć na ten temat opinie - np. „Zwiększ max_wal_senders o 10 w stosunku do tego, co było wcześniej”.
Craig Ringer
4
Wygląda na to, że mówisz, że aplikacja powinna zostać zmieniona, aby obejść ograniczenia w systemie zarządzania konfiguracją, lub że powinienem zrezygnować z ról wielokrotnego użytku.
Craig Ringer