Anexando a listas ou adicionando chaves aos dicionários no Ansible


34

(Relacionado a retornos de chamada ou ganchos e séries reutilizáveis ​​de tarefas, em funções Ansible ):

Existe uma maneira melhor de acrescentar uma lista ou adicionar uma chave a um dicionário no Ansible do que (ab) usando uma expressão de modelo jina2?

Eu sei que você pode fazer algo como:

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

mas não há realmente nenhum tipo de meta tarefa ou auxiliar para fazer isso?

Parece frágil, parece não estar documentado e depende de muitas suposições sobre como as variáveis ​​funcionam no Ansible.

Meu caso de uso são várias funções (extensões de servidor de banco de dados) que precisam fornecer alguma configuração a uma função base (o servidor de banco de dados). Não é tão simples quanto anexar uma linha ao arquivo de configuração do servidor db; cada alteração se aplica à mesma linha , por exemplo, as extensões bdre pg_stat_statementsdeve aparecer na linha de destino:

shared_preload_libaries = 'bdr, pg_stat_statements'

A maneira Ansible de fazer isso é apenas processar o arquivo de configuração várias vezes (uma vez por extensão) com uma regexp que extrai o valor atual, analisa e depois reescreve? Em caso afirmativo, como você torna esse idempotente em várias execuções?

E se a configuração for mais difícil do que isso para analisar e não for tão simples quanto acrescentar outro valor separado por vírgula? Pense nos arquivos de configuração XML.


Sabe o que mais? Eu gosto do corte de seu patíbulo side-effect-ful ☺
DomQ

Respostas:


13

Você pode mesclar duas listas em uma variável com +. Digamos que você tenha um group_varsarquivo com este conteúdo:

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

E é usado em um modelo pgsql.conf.j2como:

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

Em seguida, você pode anexar extensões aos servidores de banco de dados de teste como este:

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

Quando a função é executada em qualquer um dos servidores de teste, as extensões adicionais serão adicionadas.

Não tenho certeza de que isso funcione também para dicionários, e também tenha cuidado com os espaços e deixe uma vírgula pendente no final da linha.


Você pode, mas precisa fazer tudo group_vars, as funções não podem cuidar dos detalhes da configuração das extensões. É anexar vários dos papéis que estou procurando particularmente, para que um papel possa ser anexado a um var exposto por outro papel.
Craig Ringer

Sua função de base conhece cada função de extensão? Eu tive um caso semelhante em que fui capaz de deixar a concatenação em uma with_itemsfrase.
GnP 14/07/2015

não, e esse é realmente o problema. Em uma implantação do papel de base pode ser ai
Craig campainha

4
Parece que se você tentar fazer isso para concatenar duas listas, ele achará um modelo infinitamente recursivo, porque o lado esquerdo também está no lado direito. Estou entendendo mal como usar isso?
Ibrahim

2
@spectras Pelo menos a partir do Ansible 2.7, isso NÃO funciona. Como sugeriu Ibrahim, isso causa um erro: "loop recursivo detectado na cadeia de modelo".
Rluba # 25/18

35

Desde o Ansible v2.x, você pode fazer o seguinte:

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

tudo isso está documentado em: http://docs.ansible.com/ansible/playbooks_filters.html


1
caso de uso IV apenas anexadou'(': u\"'\"}"
ssc 25/02

1
obrigado, @ssc. Notei que não está funcionando com ansible 2.4.x(fixo)
Max Kovgan

de acordo com USECASE # 4, eu adicionei o valor padrão para lidar com o erro indefinido no meu cenário: set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'. O erro indefinido ocorre quando alguma filtragem é usada ou nenhum resultado é registrado.
SK Venkat

Sr. SK Venkat, o código de exemplo aqui demonstra apenas uma coisa muito específica (adição de itens de dicionário de tuplas). Se você precisar fazer outra coisa, esse código não é sua cópia e colagem.
Max Kovgan 18/09

3

você precisa dividir o loop em 2

--- 
- hosts: localhost
  tarefas: 
    - include_vars: pilhas
    - set_facts: functions = {{stacks.Roles | Dividido(' ')}}
    - inclua: addhost.yml
      with_items: "{{papers}}"

e addhost.yml

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

1

Não tenho certeza quando eles adicionaram isso, mas pelo menos para dicionários / hashes (NOT lists / matrizes), você pode definir a variável hash_behaviour , assim: hash_behaviour = mergeno seu ansible.cfg.

Levei algumas horas para acidentalmente tropeçar nessa configuração: S


isso é muito útil, mas tenha cuidado para habilitá-lo e2e na base de código existente. pode quebrar alguns ovos.
precisa saber é o seguinte

0

Quase todas as respostas aqui exigem alterações nas tarefas, mas eu precisava mesclar dinamicamente dicionários na definição de vars, não durante a execução.

Por exemplo, eu quero definir alguns vars compartilhados all group_varse depois quero estendê-los em algum outro groupou host_vars. Muito útil ao trabalhar para funções.

Se você tentar usar os filtros combineou unionsubstituindo a variável original nos arquivos var, você terminará em loop infinito durante a modelagem, por isso criei essa solução alternativa (não é solução).

Você pode definir várias variáveis ​​com base em algum padrão de nome e carregá-las automaticamente na função.

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

snippet de código de função

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

É apenas um trecho, mas você deve ter uma ideia de como funciona. note: lookup ('varnames', '') está disponível desde o ansible 2.8

Eu acho que também seria possível mesclar todas as variáveis dictionary_of_bla.*em um dicionário durante o tempo de execução usando a mesma pesquisa.

A vantagem dessa abordagem é que você não precisa definir listas exatas de nomes de variáveis, mas apenas o padrão e o usuário podem configurá-lo dinamicamente.


-4

Ansibleé um sistema de automação e, no que diz respeito ao gerenciamento de arquivos de configuração, não é muito diferente apt. A razão pela qual mais e mais softwares oferece o recurso de ler trechos de configuração de umconf.d diretório é permitir que esses sistemas de automação tenham diferentes pacotes / funções que adicionem configuração ao software. Acredito que não é a filosofia de Ansiblefazer o que você tem em mente, mas sim usar o conf.dtruque. Se o software que está sendo configurado não oferecer essa funcionalidade, você poderá estar com problemas.

Como você menciona os arquivos de configuração XML, aproveito a oportunidade para reclamar. Há uma razão para a tradição do Unix de usar arquivos de configuração de texto sem formatação. Os arquivos de configuração binária não se prestam bem à automação do sistema; portanto, qualquer tipo de formato binário causará problemas e provavelmente exigirá que você crie um programa para lidar com a configuração. (Se alguém pensa que XML é um formato de texto sem formatação, deve examinar seu cérebro.)

Agora, sobre o seu PostgreSQLproblema específico . PostgreSQLsuporta o conf.dtruque. Primeiro, eu verificaria se shared_preload_librariespode ser especificado várias vezes. Não encontrei nenhuma dica na documentação que possa, mas ainda a tentaria. Se não puder ser especificado várias vezes, eu explicaria meu problema para os PostgreSQLcaras, caso eles tenham idéias; isso é um PostgreSQLproblema e não um Ansibleproblema. Se não houver solução e eu realmente não puder mesclar as diferentes funções em uma, implementaria um sistema para compilar a configuração no host gerenciado. Neste caso, eu provavelmente criar um script /usr/local/sbin/update_postgresql_configque compile /etc/postgresql/postgresql.conf.jinjaem /etc/postgresql/9.x/main/postgresql.conf. O script lê as bibliotecas compartilhadas de pré-carregamento de /etc/postgresql/shared_preload_libraries.txt, uma biblioteca por linha, e as fornece ao jinja.

Não é incomum os sistemas de automação fazerem isso. Um exemplo é o exim4pacote Debian .


O PostgreSQL suporta um conf.dmecanismo de inclusão e, felizmente, usa arquivos de texto sem formatação. No entanto, existem algumas opções de configuração em que várias extensões podem ter opiniões sobre isso - por exemplo, "aumente max_wal_senders em 10 do que era antes".
Craig Ringer

4
Parece que você está dizendo que o aplicativo deve ser alterado para solucionar as limitações do sistema de gerenciamento de configuração ou que eu deveria desistir de ter funções reutilizáveis.
Craig Ringer
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.