Acrescentar a listas ou adicionar chaves a dicionários no Ansible

27

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

Existe alguma maneira melhor de acrescentar uma lista ou adicionar uma chave a um dicionário no Ansible 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 ajudante para fazer isso?

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

Meu caso de uso tem várias funções (extensões de servidor de banco de dados), cada uma delas precisa fornecer alguma configuração para uma função básica (o servidor de banco de dados). Não é tão simples quanto acrescentar uma linha ao arquivo de configuração do servidor db; cada alteração aplica-se à mesma linha , por ex. as extensões bdr e pg_stat_statements devem aparecer em uma linha de segmentação:

shared_preload_libaries = 'bdr, pg_stat_statements'

É a maneira Ansible de fazer isso apenas para processar o arquivo de configuração várias vezes (uma vez por extensão) com um regexp que extrai o valor atual, analisa-o e, em seguida, o 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 é tão simples quanto acrescentar outro valor separado por vírgula? Pense nos arquivos de configuração XML.

    
por Craig Ringer 26.04.2015 / 16:17

5 respostas

12

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

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

E é usado em um modelo pgsql.conf.j2 como:

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

Você pode adicionar extensões aos servidores de banco de dados de teste da seguinte forma:

---
# 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 sei se isso também funciona para os dicionários e também seja cuidadoso com espaços e deixe uma vírgula pendente no final da linha.

    
por 26.06.2015 / 18:51
26

Como o Ansible v2.x você pode fazer isso:

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

todos os itens acima estão documentados em: link

    
por 09.12.2016 / 10:28
3

você precisa dividir o loop em 2

--- 
- hosts: localhost
  tasks: 
    - include_vars: stacks
    - set_facts: roles={{stacks.Roles | split(' ')}}
    - include: addhost.yml
      with_items: "{{roles}}"

e addhost.yml

- set_facts: groupname={{item}}
- set_facts: ips={{stacks[item]|split(' ')}}
- local_action: add_host hostname={{item}} groupname={{groupname}}
  with_items: {{ips}}
    
por 15.03.2016 / 18:05
0

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

Demorei algumas horas para encontrar acidentalmente essa configuração: S

    
por 08.08.2018 / 12:51
-4

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

Como você mencionou os arquivos de configuração XML, aproveito a oportunidade para fazer algumas reclamações. Há uma razão para a tradição do Unix de usar arquivos de configuração de texto simples. Os arquivos de configuração binários não se prestam bem à automação do sistema, portanto, qualquer tipo de formato binário causará problemas e provavelmente exigirá a criação de um programa para lidar com a configuração. (Se alguém acha que XML é um formato de texto simples, eles devem ter seus cérebros examinados.)

Agora, no seu problema específico de PostgreSQL . PostgreSQL suporta o truque conf.d . Primeiro, gostaria de verificar se shared_preload_libraries pode ser especificado várias vezes. Eu não encontrei nenhuma dica na documentação que possa, mas eu ainda tentaria. Se não puder ser especificado várias vezes, eu explicaria meu problema para os PostgreSQL , caso eles tenham ideias; Este é um problema de PostgreSQL e não um problema de Ansible . Se não houver solução e realmente não conseguir mesclar os diferentes papéis em um, eu implementaria um sistema para compilar a configuração no host gerenciado. Nesse caso, provavelmente criaria um script /usr/local/sbin/update_postgresql_config que compilaria /etc/postgresql/postgresql.conf.jinja em /etc/postgresql/9.x/main/postgresql.conf . O script leria as bibliotecas de pré-carregamento compartilhadas de /etc/postgresql/shared_preload_libraries.txt , uma biblioteca por linha, e as forneceria ao jinja.

Não é incomum que os sistemas de automação façam isso. Um exemplo é o pacote Debian exim4 .

    
por 28.04.2015 / 09:01