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