Nối vào danh sách hoặc thêm khóa vào từ điển trong Ansible


34

(Liên quan đến Callbacks hoặc hook và chuỗi nhiệm vụ có thể sử dụng lại, trong vai trò Ansible ):

Có cách nào tốt hơn để thêm vào danh sách hoặc thêm khóa vào từ điển trong Ansible hơn (ab) bằng biểu thức mẫu jina2 không?

Tôi biết bạn có thể làm một cái gì đó như:

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

Nhưng thực sự không có loại nhiệm vụ meta hay người trợ giúp để làm điều này?

Nó cảm thấy mong manh, dường như không có giấy tờ và dựa vào rất nhiều giả định về cách các biến hoạt động trong Ansible.

Trường hợp sử dụng của tôi là nhiều vai trò (phần mở rộng máy chủ cơ sở dữ liệu) mà mỗi vai trò cần cung cấp một số cấu hình cho vai trò cơ sở (máy chủ cơ sở dữ liệu). Nó không đơn giản như nối thêm một dòng vào tệp cấu hình máy chủ db; mỗi thay đổi áp dụng cho cùng một dòng , ví dụ: các phần mở rộng bdrpg_stat_statementscả hai phải xuất hiện trên một dòng đích:

shared_preload_libaries = 'bdr, pg_stat_statements'

Có phải cách Ansible để làm điều này chỉ là xử lý tệp cấu hình nhiều lần (một lần cho mỗi phần mở rộng) với một biểu thức chính để trích xuất giá trị hiện tại, phân tích cú pháp và sau đó viết lại? Nếu vậy, làm thế nào để bạn thực hiện idempotent đó qua nhiều lần chạy?

Điều gì xảy ra nếu cấu hình khó phân tích hơn và không đơn giản như nối thêm một giá trị được phân tách bằng dấu phẩy? Hãy suy nghĩ các tệp cấu hình XML.


Bạn biết gì? Tôi thích cách cắt giảm hiệu ứng phụ của bạn ☺
DomQ

Câu trả lời:


13

Bạn có thể hợp nhất hai danh sách trong một biến với +. Giả sử bạn có một group_varstệp có nội dung này:

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

Và nó được sử dụng trong một mẫu pgsql.conf.j2như:

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

Sau đó, bạn có thể nối các phần mở rộng vào các máy chủ cơ sở dữ liệu thử nghiệm như thế này:

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

Khi vai trò được chạy trong bất kỳ máy chủ thử nghiệm nào, các tiện ích mở rộng quảng cáo sẽ được thêm vào.

Tôi không chắc điều này cũng hiệu quả với từ điển, và cũng cẩn thận với khoảng trắng và để lại dấu phẩy lơ lửng ở cuối dòng.


Bạn có thể, nhưng bạn phải thực hiện tất cả group_vars, các vai trò không thể quan tâm đến các chi tiết của việc thiết lập các tiện ích mở rộng. Đó là nối các vars từ các vai trò mà tôi đặc biệt tìm kiếm, vì vậy một vai trò có thể nối vào một var bị phơi bày bởi một vai trò khác.
Craig Ringer

Vai trò cơ sở của bạn có biết về từng vai trò mở rộng không? Tôi đã có một trường hợp tương tự khi tôi có thể để lại phần nối cho đến một with_itemscâu.
GnP

không, và đó thực sự là vấn đề Trong một lần triển khai, vai trò cơ sở có thể là al
Craig Ringer

4
Có vẻ như nếu bạn cố gắng làm điều này để nối hai danh sách, nó nghĩ rằng đó là một mẫu đệ quy vô hạn vì phía bên trái cũng nằm ở phía bên tay phải. Tôi có hiểu lầm làm thế nào để sử dụng này?
Ibrahim

2
@spectras Ít nhất là từ Ansible 2.7, điều này KHÔNG hoạt động. Như Ibrahim đã đề xuất, điều này gây ra lỗi: "vòng lặp đệ quy được phát hiện trong chuỗi mẫu".
rluba

35

Vì Ansible v2.x, bạn có thể thực hiện các thao tác sau:

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

tất cả những điều trên được ghi lại trong: http://docs.ansible.com/ansible/playbooks_filters.html


1
trường hợp sử dụng IV chỉ cần nối thêmu'(': u\"'\"}"
ssc

1
cảm ơn, @ssc. Tôi nhận thấy nó không hoạt động với ansible 2.4.x(CỐ ĐỊNH)
Max Kovgan

theo usecase # 4, tôi đã thêm giá trị mặc định để xử lý lỗi không xác định trong kịch bản của mình : set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. Lỗi không xác định xuất hiện khi một số bộ lọc được sử dụng hoặc không có kết quả nào được đăng ký.
SK Venkat

Ông SK Venkat, mã mẫu ở đây chỉ thể hiện điều rất cụ thể (thêm các mục từ điển từ bộ dữ liệu). Nếu bạn cần phải làm một cái gì đó khác, mã này không phải là bản sao dán của bạn.
Tối đa

3

bạn cần chia vòng lặp thành 2

--- 
- máy chủ: localhost
  nhiệm vụ: 
    - bao gồm: các ngăn xếp
    - set_facts: vai trò = {{stacks.Roles | chia ('')}}
    - bao gồm: addhost.yml
      with_items: "{{vai trò}}"

và addhost.yml

- set_facts: groupname = {{item}}
- set_facts: ips = {{ngăn xếp [mục] | split ('')}}
- local_action: add_host hostname = {{item}} groupname = {{groupname}}
  with_items: {{ips}}

1

Không chắc chắn khi họ thêm phần này, nhưng ít nhất là cho từ điển / băm (KHÔNG liệt kê / mảng), bạn có thể đặt biến hash_behaviour , như vậy: hash_behaviour = mergetrong của bạn ansible.cfg.

Mất một vài giờ để tôi vô tình vấp ngã trong cài đặt này: S


điều này rất tiện dụng, nhưng hãy cẩn thận để kích hoạt nó e2e trên cơ sở mã hiện có. có thể làm vỡ một số trứng.
Max Kovgan

0

Hầu như tất cả các câu trả lời ở đây đều yêu cầu thay đổi trong các nhiệm vụ, nhưng tôi cần phải tự động hợp nhất các từ điển trong định nghĩa vars, chứ không phải trong khi chạy.

Ví dụ: tôi muốn xác định một số vars được chia sẻ trong all group_varsvà sau đó tôi muốn mở rộng chúng trong một số khác grouphoặc host_vars. Rất hữu ích khi làm việc cho các vai trò.

Nếu bạn cố gắng sử dụng combinehoặc unioncác bộ lọc ghi đè biến ban đầu trong các tệp var, bạn sẽ kết thúc trong vòng lặp vô hạn trong khi tạo khuôn mẫu, vì vậy tôi đã tạo ra cách giải quyết này (đó không phải là giải pháp).

Bạn có thể xác định nhiều biến dựa trên một số mẫu tên và sau đó tự động tải chúng trong vai trò.

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

đoạn mã vai trò

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

Nó chỉ là một đoạn trích, nhưng bạn sẽ có ý tưởng về cách nó hoạt động. lưu ý: tra cứu ('varnames', '') có sẵn vì ansible 2.8

Tôi đoán cũng có thể hợp nhất tất cả các biến dictionary_of_bla.*vào một từ điển trong thời gian chạy bằng cách sử dụng cùng một tra cứu.

Ưu điểm của phương pháp này là bạn không cần thiết lập danh sách chính xác các tên biến, nhưng chỉ có mẫu và người dùng có thể thiết lập nó một cách linh hoạt.


-4

Ansiblelà một hệ thống tự động hóa, và, liên quan đến quản lý tập tin cấu hình, nó không khác lắm apt. Lý do ngày càng nhiều phần mềm cung cấp tính năng đọc đoạn cấu hình từ một conf.dthư mục là để cho phép các hệ thống tự động hóa đó có các gói / vai trò khác nhau thêm cấu hình vào phần mềm. Tôi tin rằng đó không phải là triết lý Ansibleđể làm những gì bạn có trong đầu, mà thay vào đó là sử dụng conf.dmánh khóe. Nếu phần mềm đang được cấu hình không cung cấp chức năng này, bạn có thể gặp rắc rối.

Vì bạn đề cập đến các tệp cấu hình XML, tôi tận dụng cơ hội để thực hiện một số lời than vãn. Có một lý do cho truyền thống Unix sử dụng các tệp cấu hình văn bản thuần túy. Các tệp cấu hình nhị phân không tự cho vay tốt để tự động hóa hệ thống, do đó, bất kỳ loại định dạng nhị phân nào cũng sẽ gây rắc rối cho bạn và có thể sẽ yêu cầu bạn tạo chương trình để xử lý cấu hình. (Nếu bất cứ ai nghĩ rằng XML là một định dạng văn bản đơn giản, họ nên đi kiểm tra bộ não của họ.)

Bây giờ, về PostgreSQLvấn đề cụ thể của bạn . PostgreSQLkhông hỗ trợ các conf.dmẹo. Đầu tiên, tôi sẽ kiểm tra xem shared_preload_librariescó thể được chỉ định nhiều lần không. Tôi không tìm thấy bất kỳ gợi ý nào trong tài liệu mà nó có thể, nhưng tôi vẫn sẽ thử nó. Nếu nó không thể được chỉ định nhiều lần, tôi sẽ giải thích vấn đề của mình cho PostgreSQLmọi người trong trường hợp họ có ý tưởng; Đây là một PostgreSQLvấn đề và không phải là một Ansiblevấn đề. Nếu không có giải pháp và tôi thực sự không thể hợp nhất các vai trò khác nhau thành một, tôi sẽ triển khai một hệ thống để biên dịch cấu hình trên máy chủ được quản lý. Trong trường hợp này, có lẽ tôi sẽ tạo một tập lệnh /usr/local/sbin/update_postgresql_configsẽ biên dịch /etc/postgresql/postgresql.conf.jinjathành /etc/postgresql/9.x/main/postgresql.conf. Kịch bản sẽ đọc các thư viện tải trước được chia sẻ từ /etc/postgresql/shared_preload_libraries.txt, một thư viện trên mỗi dòng và cung cấp chúng cho jinja.

Không có gì lạ khi các hệ thống tự động hóa làm điều này. Một ví dụ là exim4gói Debian .


PostgreSQL hỗ trợ một conf.dcơ chế bao gồm và rất may sử dụng các tệp văn bản gốc. Tuy nhiên, có một số tùy chọn cấu hình trong đó nhiều tiện ích mở rộng có thể có ý kiến ​​về nó - ví dụ: "tăng max_wal_senders lên 10 so với trước đây".
Craig Ringer

4
Có vẻ như bạn đang nói rằng ứng dụng nên được thay đổi để khắc phục những hạn chế trong hệ thống quản lý cấu hình hoặc tôi nên từ bỏ việc có các vai trò có thể sử dụng lại.
Craig Ringer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.