Como depurar problemas com Ansible?

Às vezes, ansible não faz o que você quer. E aumentar a verbosidade não ajuda. Por exemplo, agora estou tentando iniciar o servidor de coturn , que vem com o script de boot no systemd operacional OS (Debian Jessie). Ansible considera que funciona, mas não é. Como eu olho para o que está acontecendo sob o capô? Quais comandos são executados e qual código de saída / saída?

Módulos de debugging

  • A maneira mais básica é rodar o ansible / ansible-playbook com um nível de verbosidade aumentado adicionando -vvv à linha de execução.

  • A maneira mais completa para os módulos escritos em Python (Linux / Unix) é executar o ansible / ansible-playbook com uma variável de ambiente ANSIBLE_KEEP_REMOTE_FILES definida como 1 (na máquina de controle).

    Isso faz com que o Ansible deixe a cópia exata dos scripts do Python executados (com sucesso ou não) na máquina de destino.

    O caminho para os scripts é impresso no log Ansible e, para tarefas comuns, eles são armazenados no diretório inicial do usuário do SSH: ~/.ansible/tmp/ .

    A lógica exata é incorporada nos scripts e depende de cada módulo. Alguns estão usando o Python com bibliotecas padrão ou externas, alguns estão chamando comandos externos.

Debugging playbooks

  • Similarmente aos módulos de debugging, o aumento do nível de verbosidade com o parâmetro -vvv faz com que mais dados sejam impressos no log Ansible

  • Desde o Ansible 2.1, um Depurador de Playbook permite depurar tarefas com falhas interativas: verificar, modificar os dados; execute novamente a tarefa.

Conexões de debugging

  • Adicionar o parâmetro -vvvv à ansible lista de ansible / ansible-playbook faz com que o log inclua as informações de debugging das conexões.

Aqui está o que eu inventei.

Ansible envia módulos para o sistema de destino e os executa lá. Portanto, se você alterar o módulo localmente, suas alterações entrarão em vigor ao executar o playbook. Nos meus módulos de máquina estão em /usr/lib/python2.7/site-packages/ansible/modules ( ansible-2.1.2.0 ). E o módulo de service está no core/system/service.py . Os módulos anisble (instâncias da class AnsibleModule declarada em module_utils/basic.py ) possuem o método log , que envia mensagens para o diário do systemd, se disponível, ou volta para o syslog . Portanto, execute journalctl -f no sistema de destino, adicione instruções de debugging ( module.log(msg='test') ) ao módulo localmente e execute seu playbook. Você verá instruções de debugging sob o nome da unidade ansible-basic.py .

Além disso, ao executar o ansible-playbook com -vvv , você poderá ver alguma saída de debugging no diário do systemd , pelo menos mensagens de chamada e mensagens de erro, se houver.

Só mais uma coisa, se você tentar depurar o código que está sendo executado localmente com o pdb ( import pdb; pdb.set_trace() ), você provavelmente irá executar a exceção BdbQuit . Isso porque o python fecha o stdin ao criar um thread ( ansible worker). A solução aqui é reabrir stdin antes de executar pdb.set_trace() como sugerido aqui :

 sys.stdin = open('/dev/tty') import pdb; pdb.set_trace() 

Depurando papéis / playbooks

Basicamente, a debugging de automação por meio de grandes inventários em redes grandes não é outra do que depurar um aplicativo de rede distribuída. Pode ser muito tedioso e delicado, e não há ferramentas suficientes para o usuário.

Assim, acredito que a resposta também à sua pergunta é uma união de todas as respostas antes da minha + pequena adição. Então aqui:

  • absolutamente obrigatório: você tem que querer saber o que está acontecendo, ou seja, o que você está automatizando, o que você está esperando que aconteça. Por exemplo, ansible falha ao detectar o serviço com a unidade do sistema como em execução ou como interrompido geralmente significa um bug no arquivo de unidade de serviço ou módulo de serviço, então você precisa 1. identificar o bug, 2. Relatar o bug para fornecedor / comunidade, 3. Fornecer seu solução alternativa com TODO e link para bug. 4. Quando o bug é corrigido – exclua sua solução alternativa

  • para tornar seu código mais fácil de depurar os módulos de uso, tanto quanto você puder

  • dê a todas as tarefas e variables ​​nomes significativos.

  • use ferramentas de análise de código estático como ansible-lint . Isso evita erros muito estúpidos.

  • utilizar bandeiras de verbosidade e caminho de log

  • usar o módulo de debug com sabedoria

  • “Conheça os seus fatos” – às vezes é útil despejar os dados da máquina-alvo no arquivo e puxá-lo para um mestre ansioso

    • use strategy: debug em alguns casos você pode cair em um debugger de tarefas com erro. Você então pode avaliar todos os parâmetros que a tarefa está usando e decidir o que fazer a seguir

    • o último recurso seria usar o depurador Python, anexando-o a uma execução ansible local e / ou ao Python remoto executando os módulos. Isso geralmente é complicado: você precisa permitir que uma porta adicional na máquina seja aberta, e se o código que abre a porta é o causador do problema?

Além disso, às vezes é útil “olhar de lado” – conectar-se a seus hosts de destino e aumentar sua debugging (log mais detalhado)

É claro que a coleta de registros facilita o rastreamento de mudanças que ocorrem como resultado de operações ansiosas.

Como você pode ver, como qualquer outro aplicativo e estrutura distribuída – a capacidade de debugging ainda não é a que gostaríamos.

Filtros / plugins

Isso é basicamente desenvolvimento Python, debugging como qualquer aplicativo Python

Módulos

Dependendo da tecnologia, e complicado pelo fato de você precisar ver o que acontece local e remotamente, é melhor escolher um idioma fácil de depurar remotamente.

Você pode usar o módulo de registro e o módulo de debugging para imprimir os valores de retorno. Por exemplo, eu quero saber qual é o código de retorno da minha execução de script chamado “somescript.sh”, então terei minhas tarefas dentro da peça, como:

 - name: my task shell: "bash somescript.sh" register: output - debug: msg: "{{ output.rc }}" 

Para valores de retorno completos, você pode acessar no Ansible, você pode verificar esta página: http://docs.ansible.com/ansible/latest/common_return_values.html

Existem vários níveis de debugging que você pode precisar, mas o mais fácil é adicionar a variável de ambiente ANSIBLE_STRATEGY=debug , que ANSIBLE_STRATEGY=debug o depurador no primeiro erro.

Depuração As tarefas com problemas podem ser quase impossíveis se as tarefas não forem suas. Ao contrário do que afirma o site da Ansible.

Não são necessárias habilidades especiais de codificação

Ansible requer habilidades de programação altamente especializadas , porque não é YAML ou Python, é uma mistura confusa de ambos.

A ideia de usar linguagens de marcação para programação já foi tentada anteriormente. O XML era muito popular na comunidade Java ao mesmo tempo. O XSLT também é um bom exemplo.

Conforme os projetos Ansible crescem, a complexidade cresce exponencialmente como resultado. Tomemos por exemplo o projeto OpenShift Ansible que tem a seguinte tarefa:

 - name: Create the master server certificate command: > {{ hostvars[openshift_ca_host]['first_master_client_binary'] }} adm ca create-server-cert {% for named_ca_certificate in openshift.master.named_certificates | default([]) | lib_utils_oo_collect('cafile') %} --certificate-authority {{ named_ca_certificate }} {% endfor %} {% for legacy_ca_certificate in g_master_legacy_ca_result.files | default([]) | lib_utils_oo_collect('path') %} --certificate-authority {{ legacy_ca_certificate }} {% endfor %} --hostnames={{ hostvars[item].openshift.common.all_hostnames | join(',') }} --cert={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.crt --key={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.key --expire-days={{ openshift_master_cert_expire_days }} --signer-cert={{ openshift_ca_cert }} --signer-key={{ openshift_ca_key }} --signer-serial={{ openshift_ca_serial }} --overwrite=false when: item != openshift_ca_host with_items: "{{ hostvars | lib_utils_oo_select_keys(groups['oo_masters_to_config']) | lib_utils_oo_collect(attribute='inventory_hostname', filters={'master_certs_missing':True}) }}" delegate_to: "{{ openshift_ca_host }}" run_once: true 

Acho que todos podemos concordar que isso é programação em YAML. Não é uma boa ideia. Este snippet específico pode falhar com uma mensagem como

fatal: [master0]: FALHA! => {“msg”: “A verificação condicional ‘item! = openshift_ca_host’ falhou. O erro foi: erro ao avaliar condicional (item! = openshift_ca_host): ‘item’ é indefinido \ n \ nO erro parece ter sido em ‘ /home/user/openshift-ansible/roles/openshift_master_certificates/tasks/main.yml ‘: linha 39, coluna 3, mas pode \ nser em outro lugar no arquivo, dependendo do problema exato da syntax. \ n \ nA linha ofensiva parece estar : \ n \ n \ n- name: crie o certificado do servidor master \ n ^ aqui \ n “}

Se você acertar uma mensagem como essa, você está condenado. Mas nós temos o depurador certo? Ok, vamos dar uma olhada no que está acontecendo.

 master0] TASK: openshift_master_certificates : Create the master server certificate (debug)> p task.args {u'_raw_params': u"{{ hostvars[openshift_ca_host]['first_master_client_binary'] }} adm ca create-server-cert {% for named_ca_certificate in openshift.master.named_certificates | default([]) | lib_utils_oo_collect('cafile') %} --certificate-authority {{ named_ca_certificate }} {% endfor %} {% for legacy_ca_certificate in g_master_legacy_ca_result.files | default([]) | lib_utils_oo_collect('path') %} --certificate-authority {{ legacy_ca_certificate }} {% endfor %} --hostnames={{ hostvars[item].openshift.common.all_hostnames | join(',') }} --cert={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.crt --key={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.key --expire-days={{ openshift_master_cert_expire_days }} --signer-cert={{ openshift_ca_cert }} --signer-key={{ openshift_ca_key }} --signer-serial={{ openshift_ca_serial }} --overwrite=false"} [master0] TASK: openshift_master_certificates : Create the master server certificate (debug)> exit 

Como isso ajuda? Não faz.

O ponto aqui é que é uma péssima idéia usar o YAML como uma linguagem de programação. É uma bagunça. E os sintomas da bagunça que estamos criando estão em toda parte.

Alguns fatos adicionais A provisão da fase de pré-requisitos no Azure do Openshift Ansible leva em +50 minutos. A fase de implantação leva mais de 70 minutos. Cada vez! Primeira execução ou execuções subseqüentes. E não há como limitar a provisão para um único nó. Esse problema de limit fazia parte da Ansible em 2012 e ainda faz parte da Ansible hoje. Este fato nos diz algo.

O ponto aqui é que Ansible deve ser usado como pretendido. Para tarefas simples sem a programação YAML. Ótimo para muitos servidores, mas não deve ser usado para tarefas complexas de gerenciamento de configuração.

Ansible é uma ferramenta não Infraestrutura como Código (IaC).

Se você perguntar como depurar problemas com Ansible, você o está usando de uma maneira que não deveria ser usado. Não use isso como uma ferramenta IaC.