Menambahkan ke daftar atau menambahkan kunci ke kamus di Ansible

34

(Terkait dengan Panggilan balik atau kaitan, dan serangkaian tugas yang dapat digunakan kembali, dalam peran yang dimungkinkan ):

Apakah ada cara yang lebih baik untuk menambahkan ke daftar atau menambahkan kunci ke kamus di Ansible dari (ab) menggunakan ekspresi template jina2?

Saya tahu Anda dapat melakukan sesuatu seperti:

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

tetapi apakah benar-benar tidak ada semacam tugas atau penolong untuk melakukan ini?

Rasanya rapuh, tampaknya tidak berdokumen, dan bergantung pada banyak asumsi tentang bagaimana variabel bekerja di Ansible.

Kasing penggunaan saya adalah beberapa peran (ekstensi server basis data) yang masing-masing harus menyediakan beberapa konfigurasi ke peran dasar (server basis data). Ini tidak sesederhana menambahkan baris ke file konfigurasi server db; setiap perubahan berlaku untuk baris yang sama , misalnya ekstensi bdrdan pg_stat_statementskeduanya harus muncul pada baris target:

shared_preload_libaries = 'bdr, pg_stat_statements'

Apakah cara yang dimungkinkan untuk melakukan ini hanya memproses file konfigurasi beberapa kali (sekali per ekstensi) dengan regexp yang mengekstrak nilai saat ini, mem-parsingnya, dan kemudian menulis ulang? Jika demikian, bagaimana Anda membuat idempoten itu di beberapa berjalan?

Bagaimana jika konfigurasi lebih sulit dari ini untuk diurai dan tidak sesederhana menambahkan nilai lain yang dipisahkan koma? Pikirkan file konfigurasi XML.

Craig Ringer
sumber
Kamu tahu apa Saya suka potongan efek samping Anda
f

Jawaban:

13

Anda dapat menggabungkan dua daftar dalam variabel dengan +. Katakanlah Anda memiliki group_varsfile dengan konten ini:

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

Dan itu digunakan dalam template pgsql.conf.j2seperti:

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

Anda kemudian dapat menambahkan ekstensi ke server basis data pengujian seperti ini:

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

Ketika peran dijalankan di salah satu server pengujian, ekstensi tambahan akan ditambahkan.

Saya tidak yakin ini berfungsi untuk kamus juga, dan juga berhati-hati dengan spasi dan meninggalkan koma menggantung di akhir baris.

GnP
sumber
Anda bisa, tetapi Anda harus melakukan semuanya group_vars, peran tidak dapat mengurus detail pengaturan ekstensi itu sendiri. Ini menambahkan vars dari peran yang sangat saya cari, sehingga satu peran dapat ditambahkan ke var yang diekspos oleh peran lain.
Craig Ringer
Apakah peran dasar Anda tahu tentang setiap peran ekstensi? Saya punya kasus serupa di mana saya bisa membiarkan penggabungan sampai with_itemskalimat.
GnP
tidak, dan itulah masalahnya. Dalam satu penempatan peran dasar mungkin adalah al
Craig Ringer
4
Sepertinya jika Anda mencoba melakukan ini untuk menggabungkan dua daftar, itu berpikir itu adalah template rekursif tanpa batas karena sisi kiri juga di sisi kanan. Apakah saya salah paham bagaimana menggunakan ini?
Ibrahim
2
@spectras Setidaknya pada Ansible 2.7 ini TIDAK berfungsi. Seperti yang disarankan Ibrahim, ini menyebabkan kesalahan: "loop rekursif terdeteksi dalam string template".
rluba
35

Sejak Ansible v2.x Anda dapat melakukan ini:

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

semua hal di atas didokumentasikan dalam: http://docs.ansible.com/ansible/playbooks_filters.html

Max Kovgan
sumber
1
use case IV hanya menambahkanu'(': u\"'\"}"
ssc
1
terima kasih, @ssc. Saya perhatikan itu tidak bekerja dengan ansible 2.4.x(TETAP)
Max Kovgan
menurut usecase # 4, saya telah menambahkan nilai default untuk menangani kesalahan terdefinisi dalam skenario saya: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. Kesalahan yang tidak ditentukan datang ketika beberapa penyaringan digunakan atau tidak ada hasil terdaftar.
SK Venkat
Tn. SK Venkat, kode contoh di sini hanya menunjukkan hal yang sangat spesifik (menambahkan item kamus dari tupel). Jika Anda perlu melakukan sesuatu yang lain, kode ini bukan copy-paste Anda.
Max Kovgan
3

Anda perlu membagi lingkaran menjadi 2

--- 
- host: localhost
  tugas: 
    - include_vars: tumpukan
    - set_facts: peran = {{stacks.Roles | split ('')}}
    - termasuk: addhost.yml
      with_items: "{{peran}}"

dan addhost.yml

- set_facts: groupname = {{item}}
- set_facts: ips = {{stacks [item] | split ('')}}
- local_action: add_host hostname = {{item}} groupname = {{groupname}}
  with_items: {{ips}}
Arthur Tsang
sumber
1

Tidak yakin ketika mereka menambahkan ini, tetapi setidaknya untuk kamus / hash (BUKAN daftar / array), Anda dapat mengatur variabel hash_behaviour , seperti: hash_behaviour = mergedi Anda ansible.cfg.

Butuh beberapa jam untuk saya secara tidak sengaja menemukan pengaturan ini: S

gila
sumber
ini sangat berguna, tetapi berhati-hatilah untuk mengaktifkannya pada basis kode yang ada. dapat memecahkan beberapa telur.
Max Kovgan
0

Hampir semua jawaban di sini membutuhkan perubahan dalam tugas, tetapi saya perlu secara dinamis menggabungkan kamus dalam definisi vars, bukan selama menjalankan.

Misalnya saya ingin mendefinisikan beberapa vars yang dibagikan all group_varsdan kemudian saya ingin memperluasnya di beberapa var lain groupatau host_vars. Sangat berguna saat bekerja untuk peran.

Jika Anda mencoba menggunakan combineatau unionmemfilter menimpa variabel asli dalam file var, Anda akan berakhir dalam loop tak terbatas selama templating, jadi saya membuat solusi ini (bukan solusi).

Anda dapat mendefinisikan beberapa variabel berdasarkan beberapa pola nama dan kemudian secara otomatis memuatnya dalam peran.

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

cuplikan kode peran

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

Ini hanya cuplikan, tetapi Anda harus mendapatkan gagasan tentang cara kerjanya. catatan: lookup ('varnames', '') tersedia sejak an 2.8

Saya kira itu juga mungkin untuk menggabungkan semua variabel dictionary_of_bla.*menjadi satu kamus selama runtime menggunakan pencarian yang sama.

Keuntungan dari pendekatan ini adalah Anda tidak perlu mengatur daftar nama variabel yang tepat, tetapi hanya pola dan pengguna yang dapat mengaturnya secara dinamis.

VeselaHouba
sumber
-4

Ansibleadalah sistem otomasi, dan, mengenai manajemen file konfigurasi, itu tidak jauh berbeda dari apt. Alasan semakin banyak perangkat lunak menawarkan fitur untuk membaca cuplikan konfigurasi dari conf.ddirektori adalah untuk memungkinkan sistem otomasi tersebut membuat paket / peran yang berbeda menambah konfigurasi ke perangkat lunak. Saya percaya bahwa itu bukan filosofi Ansibleuntuk melakukan apa yang ada dalam pikiran Anda, melainkan menggunakan conf.dtriknya. Jika perangkat lunak yang dikonfigurasikan tidak menawarkan fungsi ini, Anda mungkin mengalami masalah.

Karena Anda menyebutkan file konfigurasi XML, saya mengambil kesempatan untuk melakukan rengekan. Ada alasan untuk tradisi Unix menggunakan file konfigurasi teks biasa. File-file konfigurasi biner tidak cocok dengan otomasi sistem, sehingga segala bentuk format biner akan memberi Anda masalah dan kemungkinan akan mengharuskan Anda membuat program untuk menangani konfigurasi. (Jika ada yang berpikir XML adalah format teks biasa, mereka harus memeriksa otak mereka.)

Sekarang, pada PostgreSQLmasalah spesifik Anda . PostgreSQLtidak mendukung conf.dtriknya. Pertama, saya akan memeriksa apakah shared_preload_librariesdapat ditentukan beberapa kali. Saya tidak menemukan petunjuk dalam dokumentasi yang bisa, tetapi saya masih akan mencobanya. Jika itu tidak dapat ditentukan beberapa kali, saya akan menjelaskan masalah saya kepada PostgreSQLorang - orang kalau-kalau mereka punya ide; ini adalah PostgreSQLmasalah dan bukan Ansiblemasalah. Jika tidak ada solusi dan saya benar-benar tidak dapat menggabungkan peran yang berbeda menjadi satu, saya akan menerapkan sistem untuk mengkompilasi konfigurasi pada host yang dikelola. Dalam hal ini, saya mungkin akan membuat script /usr/local/sbin/update_postgresql_configyang akan mengkompilasi /etc/postgresql/postgresql.conf.jinjamenjadi /etc/postgresql/9.x/main/postgresql.conf. Script akan membaca preload shared library dari /etc/postgresql/shared_preload_libraries.txt, satu perpustakaan per baris, dan memberikannya ke jinja.

Tidak jarang sistem otomasi melakukan hal ini. Contohnya adalah exim4paket Debian .

Antonis Christofides
sumber
PostgreSQL mendukung conf.dmekanisme include dan untungnya menggunakan file plaintext. Namun, ada beberapa opsi konfigurasi di mana banyak ekstensi mungkin memiliki pendapat tentang hal itu - misalnya "meningkatkan max_wal_senders sebesar 10 dari apa pun itu sebelumnya".
Craig Ringer
4
Sepertinya Anda mengatakan bahwa aplikasi harus diubah untuk mengatasi keterbatasan dalam sistem manajemen konfigurasi, atau saya harus menyerah karena memiliki peran yang dapat digunakan kembali.
Craig Ringer