Uso de Ansible para verificar configuraciones

Ansible es una gran herramienta para configurar servidores en el estado que desee. Puede crear un libro de jugadas y, si está escrito correctamente, siempre produce el mismo estado sin importar cuántas veces lo ejecute. Esto se llama idempotencia. También puede ejecutar un libro de jugadas de Ansible con el --check y verifique qué cambiaría el libro de jugadas si se ejecuta para que no realice cambios inesperadamente cuando no los desee.

Pero, ¿qué sucede si necesita verificar la configuración de los servidores existentes que no se configuraron originalmente con Ansible? Existen herramientas para esto, como Chef's InSpec, testinfra y serverspec. Pero, si ya está familiarizado con Ansible, puede usar algunas de sus funciones integradas para hacer esto.

Ejemplo 1

En este ejemplo, tengo seis hosts de diferentes distribuciones y versiones de Linux. Dado que la memoria real informada puede variar, buscaré memoria entre 800 MB y 1100 MB. El objetivo es que los hosts que cumplan con los criterios tengan éxito con changed=0 y hosts que no cumplen con los criterios de salida changed=1:

- name: assert
  hosts: all

  tasks:

  - name: check if memory is between 800 and 1100MB
    assert:
      that:
        - ansible_memtotal_mb | int >= 800
        - ansible_memtotal_mb | int <= 1100
      fail_msg: "Memory is {{ ansible_memtotal_mb }}MB not 1024MB"
    register: result
    changed_when:
      - result.evaluated_to is defined
      - result.evaluated_to == False
    failed_when: False

Los resultados:

[[email protected] config-verify]$ ansible-playbook assert.yml


PLAY [assert] ****************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************************************************************
ok: [wookie]
ok: [ewok]
ok: [centurion]
ok: [web]
ok: [venture]
ok: [c3po]

TASK [check if memory is between 800 and 1100MB] *****************************************************************************************************************************************************************
ok: [venture] => {
    "changed": false,
    "failed_when_result": false,
    "msg": "All assertions passed"
}
ok: [ewok] => {
    "changed": false,
    "failed_when_result": false,
    "msg": "All assertions passed"
}
ok: [web] => {
    "changed": false,
    "failed_when_result": false,
    "msg": "All assertions passed"
}
changed: [centurion] => {
    "assertion": "ansible_memtotal_mb | int <= 1100",
    "changed": true,
    "evaluated_to": false,
    "failed_when_result": false,
    "msg": "Memory is 7737MB not 1024MB"
}
ok: [wookie] => {
    "changed": false,
    "failed_when_result": false,
    "msg": "All assertions passed"
}
ok: [c3po] => {
    "changed": false,
    "failed_when_result": false,
    "msg": "All assertions passed"
}

PLAY RECAP *******************************************************************************************************************************************************************************************************
c3po                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
centurion                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ewok                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
venture                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
wookie                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

acertar

la función de assert El módulo, según la documentación, es "afirmar que las expresiones dadas son verdaderas".

En este caso, cinco de los seis pasaron, uno falló porque el host centurion tenía más memoria que el rango que estaba verificando. usé el fail_msg opción de la assert módulo para proporcionar información útil sobre por qué falló. También hay opciones para mostrar siempre un mensaje personalizado con msg y para pasar un mensaje personalizado cuando pasa la aserción llamada success_msg.

cambiado_cuando

el changed_when La opción no es un módulo, sino una función integrada que cambia la forma en que se realiza el manejo de errores para una tarea. En este caso, registramos los resultados de la assert prueba en el result variable. Luego modificamos el changed valor basado en dos pruebas: 1) no evaluated_to la variable existe, y 2) ¿es falsa? Si existe y es falso, sabemos que la prueba falló y devolvemos el resultado como "modificado".

falló_cuando

Para evitar que el juego falle y finalice la ejecución del libro de jugadas, configure el failed_when opción a falso.

Ejemplo 2

Otra estrategia de comparación de configuración útil es utilizar una herramienta de suma de comprobación como md5sum para comparar archivos.

---
- name: compare
  hosts: all
  gather_facts: no
 
  vars:
 
    std_conf_crontab: 'c39252b11aad842fcb75e05c6a27eef8'
    std_conf_lvm: '2d90187abd40dbcb6fc6de41640fd022'
    std_conf_resolv: 'db323688118c844a76ebd6c70508b434'

  tasks:

  - name: compare config files
    stat:
      path: '{{ item.file }}'
      checksum_algorithm: md5
    register: result
    changed_when: item.md5sum != result.stat.checksum
    failed_when: False
    loop:
      - { file: /etc/crontab, md5sum: '{{ std_conf_crontab }}' }
      - { file: /etc/lvm/lvm.conf, md5sum: '{{ std_conf_lvm }}' }
      - { file: /etc/resolv.conf, md5sum: '{{ std_conf_resolv }}'}   

El resultado:

[[email protected] config-verify]$ ansible-playbook compare.yml

PLAY [compare] ****************************************************************************************************************************

TASK [compare config files] ***************************************************************************************************************
changed: [wookie] => (item={'file': '/etc/crontab', 'md5sum': 'c39252b11aad842fcb75e05c6a27eef8'})
ok: [centurion] => (item={'file': '/etc/crontab', 'md5sum': 'c39252b11aad842fcb75e05c6a27eef8'})
ok: [web] => (item={'file': '/etc/crontab', 'md5sum': 'c39252b11aad842fcb75e05c6a27eef8'})
changed: [wookie] => (item={'file': '/etc/lvm/lvm.conf', 'md5sum': '2d90187abd40dbcb6fc6de41640fd022'})
ok: [centurion] => (item={'file': '/etc/lvm/lvm.conf', 'md5sum': '2d90187abd40dbcb6fc6de41640fd022'})
ok: [venture] => (item={'file': '/etc/crontab', 'md5sum': 'c39252b11aad842fcb75e05c6a27eef8'})
ok: [wookie] => (item={'file': '/etc/resolv.conf', 'md5sum': 'db323688118c844a76ebd6c70508b434'})
ok: [ewok] => (item={'file': '/etc/crontab', 'md5sum': 'c39252b11aad842fcb75e05c6a27eef8'})
ok: [centurion] => (item={'file': '/etc/resolv.conf', 'md5sum': 'db323688118c844a76ebd6c70508b434'})
ok: [web] => (item={'file': '/etc/lvm/lvm.conf', 'md5sum': '2d90187abd40dbcb6fc6de41640fd022'})
changed: [venture] => (item={'file': '/etc/lvm/lvm.conf', 'md5sum': '2d90187abd40dbcb6fc6de41640fd022'})
ok: [web] => (item={'file': '/etc/resolv.conf', 'md5sum': 'db323688118c844a76ebd6c70508b434'})
changed: [ewok] => (item={'file': '/etc/lvm/lvm.conf', 'md5sum': '2d90187abd40dbcb6fc6de41640fd022'})
ok: [ewok] => (item={'file': '/etc/resolv.conf', 'md5sum': 'db323688118c844a76ebd6c70508b434'})
ok: [venture] => (item={'file': '/etc/resolv.conf', 'md5sum': 'db323688118c844a76ebd6c70508b434'})
ok: [c3po] => (item={'file': '/etc/crontab', 'md5sum': 'c39252b11aad842fcb75e05c6a27eef8'})
changed: [c3po] => (item={'file': '/etc/lvm/lvm.conf', 'md5sum': '2d90187abd40dbcb6fc6de41640fd022'})
ok: [c3po] => (item={'file': '/etc/resolv.conf', 'md5sum': 'db323688118c844a76ebd6c70508b434'})

PLAY RECAP ********************************************************************************************************************************
c3po                       : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
centurion                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ewok                       : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
venture                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web                        : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
wookie                     : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

En este ejemplo, definimos variables para el md5sums de tres archivos cuya consistencia queremos comprobar. Nuestra tarea entonces usa el stat módulo para calcular el checksum MD5 de cada archivo y compararlo con la variable definida. Nuevamente usamos el changed_when función para hacer la comparación y mostrar un estado "modificado" cuando no hay coincidencia.

Ejemplo 3

Mi último ejemplo es una forma de verificar el contenido de un archivo para un elemento específico. Una forma de hacer esto es usar el shell módulo y uso grep.

---
- name: grep
  hosts: all
  gather_facts: no

  tasks:

  - name: grep for nameserver
    shell: grep 'nameserver 192.168.0.1' /etc/resolv.conf
    register: result
    changed_when: result.rc != 0
    failed_when: False

El resultado:

[[email protected] config-verify]$ ansible-playbook grep.yml

PLAY [grep] *******************************************************************************************************************************

TASK [grep for nameserver] ****************************************************************************************************************
ok: [wookie]
ok: [web]
ok: [centurion]
ok: [ewok]
changed: [venture]
ok: [c3po]

PLAY RECAP ********************************************************************************************************************************
c3po                       : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
centurion                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ewok                       : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
venture                    : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
web                        : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
wookie                     : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

De nuevo, usamos la combinación de changed_when y failed_when manipular la salida para que sea útil. Al registrar la salida de grep a la result variable, entonces podemos verificar el código de retorno del comando y saber si el valor deseado nameserver la cadena está presente. Se pueden usar comandos más complejos si es necesario.

Conclusión

Espero que otros encuentren útiles estos consejos. Puede usar Ansible no solo como una herramienta para configurar los servidores en el estado deseado, sino también como una herramienta de investigación para verificar la configuración de los servidores o posiblemente como una herramienta de monitoreo ad hoc.

Artículos de interés

Subir