Cómo probar la implementación de Ansible con InSpec y Kitchen

El autor seleccionó el Fondo de Diversidad en Tecnología para recibir una donación como parte del programa Write for DOnations.
Introducción
InSpec es un marco de auditoría y pruebas automatizadas de código abierto que se utiliza para describir y probar problemas, recomendaciones o requisitos normativos. Está diseñado para ser legible por humanos y no depende de ninguna plataforma. Los desarrolladores pueden trabajar con InSpec localmente o mediante SSH, WinRM o Docker para ejecutar pruebas, por lo que no es necesario instalar ningún paquete en la infraestructura que se está probando.
Aunque con InSpec puedes ejecutar pruebas directamente en tus servidores, existe la posibilidad de que se produzcan errores humanos que podrían causar problemas en tu infraestructura. Para evitar este escenario, los desarrolladores pueden usar Kitchen para crear una máquina virtual e instalar un sistema operativo de su elección en las máquinas donde se ejecutan las pruebas. Kitchen es un ejecutor de pruebas, o una herramienta de automatización de pruebas, que te permite probar el código de infraestructura en una o más plataformas aisladas. También es compatible con muchos marcos de prueba y es flexible con una arquitectura de complemento de controlador para varias plataformas como Vagrant, AWS, DigitalOcean, Docker, contenedores LXC, etc.
En este tutorial, escribirás pruebas para tus playbooks de Ansible ejecutándose en un Droplet de DigitalOcean Ubuntu 18.04. Usarás Kitchen como ejecutor de pruebas e InSpec para escribir las pruebas. Al finalizar este tutorial, podrás probar la implementación de tu playbook de Ansible.
Prerrequisitos
Antes de comenzar con esta guía, necesitará una cuenta de DigitalOcean además de lo siguiente:
- Una instalación local
Rubyen su máquina. Puede instalar Ruby siguiendo el tutorial correspondiente a su distribución en la serie: Cómo instalar y configurar un entorno de programación local para Ruby. - Chef Development Kit (ChefDK) instalado en su máquina.
- Las claves SSH se configuran en su máquina siguiendo los pasos 1 y 2 de Cómo configurar claves SSH. Para cargar su clave pública SSH en su cuenta de DigitalOcean, puede seguir nuestro tutorial Cómo agregar claves SSH a una cuenta de DigitalOcean.
- Un token de acceso personal de lectura y escritura de DigitalOcean. Asegúrese de registrar el token en un lugar seguro; lo usará más adelante en este tutorial. Esto le permite crear un Droplet en DigitalOcean, que es donde se ejecutarán las pruebas en este tutorial.
Paso 1: Configuración e inicialización de la cocina
Ha instalado ChefDK como parte de los requisitos previos que vienen incluidos con Kitchen. En este paso, configurará Kitchen para que se comunique con DigitalOcean.
Antes de inicializar Kitchen, creará un directorio de proyecto y se trasladará a él. En este tutorial, lo llamaremos ansible_testing_dir.
Ejecute el siguiente comando para crear el directorio:
- mkdir ~/ansible_testing_dir
Y luego pasar a ello:
- cd ~/ansible_testing_dir
Utilice gemla instalación del kitchen-digitaloceanpaquete en su máquina local. Esto le permite indicarle kitchenque use el controlador de DigitalOcean al ejecutar pruebas:
- gem install kitchen-digitalocean
Dentro del directorio del proyecto, ejecutará el kitchen initcomando especificando ansible_playbookcomo aprovisionador y digitaloceancomo controlador al inicializar Kitchen:
- kitchen init --provisioner=ansible_playbook --driver=digitalocean
Verás el siguiente resultado:
Outputcreate kitchen.ymlcreate chefignorecreate test/integration/default
Esto ha creado lo siguiente dentro del directorio de su proyecto:
-
test/integration/defaultEs el directorio donde guardarás tus archivos de prueba. -
chefignorees el archivo que usarías para garantizar que ciertos archivos no se carguen al servidor Chef Infra, pero no lo usarás en este tutorial. -
kitchen.ymles el archivo que describe su configuración de prueba: lo que desea probar y las plataformas de destino.
Ahora, debe exportar sus credenciales de DigitalOcean como variables de entorno para tener acceso a la creación de Droplets desde su CLI. Primero, comience con su token de acceso de DigitalOcean ejecutando el siguiente comando:
- export DIGITALOCEAN_ACCESS_TOKEN="YOUR_DIGITALOCEAN_ACCESS_TOKEN"
También debe obtener el número de identificación de su clave SSH; tenga en cuenta que YOUR_DIGITALOCEAN_SSH_KEY_IDSdebe ser el ID numérico de su clave SSH, no el nombre simbólico. Con la API de DigitalOcean, puede obtener el ID numérico de sus claves con el siguiente comando:
- curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN"
Con este comando verás una lista de tus claves SSH y los metadatos relacionados. Lee el resultado para encontrar la clave correcta e identificar el número de identificación dentro del resultado:
Output... {"id":your-ID-number,"fingerprint":"fingerprint","public_key":"ssh-rsa your-ssh-key","name":"your-ssh-key-name"...
Nota: Si desea que su salida sea más legible para obtener sus identificadores numéricos, puede buscar y descargar jqsegún su sistema operativo en la página de descarga de jq. Ahora, puede ejecutar el comando anterior incluido jqde la siguiente manera:
- curl -X GET https://api.digitalocean.com/v2/account/keys -H "Authorization: Bearer $DIGITALOCEAN_ACCESS_TOKEN" | jq
Verá la información de su clave SSH con un formato similar al siguiente:
Output{ "ssh_keys": [ { "id": YOUR_SSH_KEY_ID, "fingerprint": "2f:d0:16:6b", "public_key": "ssh-rsa AAAAB3NzaC1yc2 example@example.local", "name": "sannikay" } ],}
Una vez que haya identificado sus ID numéricas SSH, expórtelas con el siguiente comando:
- export DIGITALOCEAN_SSH_KEY_IDS="YOUR_DIGITALOCEAN_SSH_KEY_ID"
Ha inicializado kitcheny configurado las variables de entorno para sus credenciales de DigitalOcean. Ahora, podrá crear y ejecutar pruebas en sus Droplets de DigitalOcean directamente desde la línea de comandos.
Paso 2: creación del manual de Ansible
En este paso, creará un playbook y roles que configuran Nginx y Node.js en el Droplet creado en kitchenel siguiente paso. Las pruebas se ejecutarán en el playbook para garantizar que se cumplan las condiciones especificadas en el playbook.
Para comenzar, cree un rolesdirectorio para los roles Nginx y Node.js:
- mkdir -p roles/{nginx,nodejs}/tasks
Esto creará una estructura de directorio como la siguiente:
roles├── nginx│ └── tasks└── nodejs └── tasks
Ahora, crea un main.ymlarchivo en el roles/nginx/tasksdirectorio usando tu editor preferido:
- nano roles/nginx/tasks/main.yml
En este archivo, cree una tarea que configure e inicie Nginx agregando el siguiente contenido:
roles/nginx/tareas/main.yml
---- name: Update cache repositories and install Nginx apt: name: nginx update_cache: yes- name: Change nginx directory permission file: path: /etc/nginx/nginx.conf mode: 0750- name: start nginx service: name: nginx state: started
Una vez que haya agregado el contenido, guarde y salga del archivo.
En roles/nginx/tasks/main.yml, se define una tarea que actualizará el repositorio de caché de su Droplet, lo que equivale a ejecutar el apt updatecomando manualmente en un servidor. Esta tarea también cambia los permisos del archivo de configuración de Nginx e inicia el servicio Nginx.
También vas a crear un main.ymlarchivo roles/nodejs/taskspara definir una tarea que configure Node.js:
- nano roles/nodejs/tasks/main.yml
Agregue las siguientes tareas a este archivo:
roles/nodejs/tareas/main.yml
---- name: Update caches repository apt: update_cache: yes- name: Add gpg key for NodeJS LTS apt_key: url: "https://deb.nodesource.com/gpgkey/nodesource.gpg.key" state: present- name: Add the NodeJS LTS repo apt_repository: repo: "deb https://deb.nodesource.com/node_{{ NODEJS_VERSION }}.x {{ ansible_distribution_release }} main" state: present update_cache: yes- name: Install Node.js apt: name: nodejs state: present
Guarde y salga del archivo cuando haya terminado.
En roles/nodejs/tasks/main.yml, primero se define una tarea que actualizará el repositorio de caché de su Droplet. Luego, con la siguiente tarea, se agrega la clave GPG para Node.js que sirve como medio para verificar la autenticidad del aptrepositorio de Node.js. Las dos tareas finales agregan el repositorio de Node.js apte instalan Node.js.
Ahora definirá sus configuraciones de Ansible, como las variables, el orden en el que desea que se ejecuten sus roles y la configuración de privilegios de superusuario. Para ello, creará un archivo llamado playbook.yml, que sirve como punto de entrada para Kitchen. Cuando ejecuta sus pruebas, Kitchen comienza desde su playbook.ymlarchivo y busca los roles que se ejecutarán, que son sus archivos roles/nginx/tasks/main.ymly .roles/nodejs/tasks/main.yml
Ejecute el siguiente comando para crear playbook.yml:
- nano playbook.yml
Añade el siguiente contenido al archivo:
directorio_de_pruebas_ansible/playbook.yml
--- - hosts: all become: true remote_user: ubuntu vars: NODEJS_VERSION: 8
Guardar y salir del archivo.
Ha creado los roles del libro de estrategias de Ansible contra los cuales ejecutará sus pruebas para garantizar que se cumplan las condiciones especificadas en el libro de estrategias.
Paso 3: Cómo escribir las pruebas InSpec
En este paso, escribirá pruebas para verificar si Node.js está instalado en su Droplet. Antes de escribir su prueba, veamos el formato de una prueba InSpec de ejemplo. Al igual que con muchos marcos de prueba, el código InSpec se parece a un lenguaje natural. InSpec tiene dos componentes principales, el sujeto a examinar y el estado esperado del sujeto:
Bloque A
describe 'entity' do it { expectation }end
En el bloque A, las palabras clave doy enddefinen un conjunto de pruebas, que contienen casos de prueba. La blockpalabra clave se utiliza para definir los casos de prueba.describeit
entityes el objeto que desea examinar, por ejemplo, un nombre de paquete, servicio, archivo o puerto de red. expectationEspecifica el resultado deseado o el estado esperado, por ejemplo, Nginx debe estar instalado o debe tener una versión específica. Puede consultar la documentación de InSpec DSL para obtener más información sobre el lenguaje InSpec.
Otro ejemplo de bloque de prueba InSpec:
Bloque B
control 'Can be anything unique' do impact 0.7 title 'A human-readable title' desc 'An optional description' describe 'entity' do it { expectation } endend
La diferencia entre el bloque A y el bloque B es el controlbloque. El controlbloque se utiliza como medio de control, recomendación o requisito regulatorio. El controlbloque tiene un nombre, generalmente un identificador único, metadatos como desc, title, impacty finalmente agrupa describebloques relacionados para implementar las verificaciones.
desc, title, y define impactmetadatos que describen completamente la importancia del control, su propósito, con una descripción sucinta y completa. impactdefine un valor numérico que va desde 0.0hasta 1.0donde se clasifica como sin impacto, se clasifica como de bajo impacto, se clasifica como de impacto medio, se clasifica como de alto impacto, se clasifica como control crítico.0.00.010.010.40.40.70.70.90.91.0
Ahora, para implementar una prueba, utilizará la sintaxis del bloque A y utilizará packageel recurso de InSpec para probar si Node.jsestá instalado en el sistema. Creará un archivo con el nombre sample.rben su test/integration/defaultdirectorio para sus pruebas.
Crear sample.rb:
- nano test/integration/default/sample.rb
Añade lo siguiente a tu archivo:
prueba/integración/predeterminado/muestra.rb
describe package('nodejs') do it { should be_installed }end
Aquí su prueba utiliza el packagerecurso para verificar que Node.js esté instalado.
Guarde y salga del archivo cuando haya terminado.
Para ejecutar esta prueba, debe editar kitchen.ymlpara especificar el libro de estrategias que creó anteriormente y agregarlo a sus configuraciones.
Abra su kitchen.ymlarchivo:
- nano ansible_testing_dir/kitchen.yml
Reemplace el contenido de kitchen.ymlpor lo siguiente:
directorio_de_pruebas_ansible/kitchen.yml
---driver: name: digitaloceanprovisioner: name: ansible_playbook hosts: test-kitchen playbook: ./playbook.ymlverifier: name: inspecplatforms: - name: ubuntu-18 driver_config: ssh_key: PATH_TO_YOUR_PRIVATE_SSH_KEY tags: - inspec-testing region: fra1 size: 1gb private_networking: false verifier: inspec_tests: - test/integration/defaultsuites: - name: default
Las platformopciones incluyen lo siguiente:
-
name:La imagen que estás usando. -
driver_config: Su configuración de Droplet de DigitalOcean. Está especificando las siguientes opciones paradriver_config:ssh_key: Ruta aYOUR_PRIVATE_SSH_KEY. SuYOUR_PRIVATE_SSH_KEYse encuentra en el directorio que especificó al crear susshclave.tags:Las etiquetas asociadas a tu Droplet.region:Elregionlugar donde quieres que se aloje tu Droplet.size:La memoria que quieres que tenga tu Droplet.
-
verifier:Esto define que el proyecto contiene pruebas InSpec.- La
inspec_testsparte especifica que las pruebas existen en eltest/integration/defaultdirectorio del proyecto.
- La
Tenga en cuenta que namey regionutilizan abreviaturas. Puede consultar la test-kitchendocumentación para saber qué abreviaturas puede utilizar.
Una vez que haya agregado su configuración, guarde y salga del archivo.
Ejecute el kitchen testcomando para ejecutar la prueba. Esto comprobará si Node.js está instalado. Esto fallará intencionalmente porque actualmente no tiene la función Node.js en su playbook.ymlarchivo:
- kitchen test
Verá un resultado similar al siguiente:
Output: failing test results----- Starting Kitchen (v1.24.0)----- Cleaning up any prior instances of default-ubuntu-18----- Destroying default-ubuntu-18... DigitalOcean instance 145268853 destroyed. Finished destroying default-ubuntu-18 (0m2.63s).----- Testing default-ubuntu-18----- Creating default-ubuntu-18... DigitalOcean instance 145273424 created. Waiting for SSH service on 138.68.97.146:22, retrying in 3 seconds [SSH] Established (ssh ready) Finished creating default-ubuntu-18 (0m51.74s).----- Converging default-ubuntu-18...$$$$$$ Running legacy converge for 'Digitalocean' Driver----- Installing Chef Omnibus to install busser to run tests PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [localhost] PLAY RECAP ********************************************************************* localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Downloading files from default-ubuntu-18 Finished converging default-ubuntu-18 (0m55.05s).----- Setting up default-ubuntu-18...$$$$$$ Running legacy setup for 'Digitalocean' Driver Finished setting up default-ubuntu-18 (0m0.00s).----- Verifying default-ubuntu-18... Loaded tests from {:path=". ansible_testing_dir.test.integration.default"}Profile: tests from {:path="ansible_testing_dir/test/integration/default"} (tests from {:path="ansible_testing_dir.test.integration.default"})Version: (not specified)Target: ssh://root@138.68.97.146:22 System Package nodejs × should be installed expected that System Package nodejs is installedTest Summary: 0 successful, 1 failure, 0 skipped ------Exception------- Class: Kitchen::ActionFailed Message: 1 actions failed. Verify failed on instance default-ubuntu-18. Please see .kitchen/logs/default-ubuntu-18.log for more details ---------------------- Please see .kitchen/logs/kitchen.log for more details Also try running `kitchen diagnose --all` for configuration 4.54s user 1.77s system 5% cpu 2:02.33 total
El resultado indica que la prueba falla porque no tienes Node.js instalado en el Droplet que aprovisionaste kitchen. Solucionarás la prueba agregando el nodejsrol a tu playbook.ymlarchivo y ejecutando la prueba nuevamente.
Edite el playbook.ymlarchivo para incluir el nodejsrol:
- nano playbook.yml
Agregue las siguientes líneas resaltadas a su archivo:
directorio_de_pruebas_ansible/playbook.yml
--- - hosts: all become: true remote_user: ubuntu vars: NODEJS_VERSION: 8 roles: - nodejs
Guarde y cierre el archivo.
Ahora, volverá a ejecutar la prueba usando el kitchen testcomando:
- kitchen test
Verás el siguiente resultado:
Output......Target: ssh://root@46.101.248.71:22 System Package nodejs ✔ should be installedTest Summary: 1 successful, 0 failures, 0 skipped Finished verifying default-ubuntu-18 (0m4.89s).----- Destroying default-ubuntu-18... DigitalOcean instance 145512952 destroyed. Finished destroying default-ubuntu-18 (0m2.23s). Finished testing default-ubuntu-18 (2m49.78s).----- Kitchen is finished. (2m55.14s) 4.86s user 1.77s system 3% cpu 2:56.58 total
Tu prueba ahora pasa porque tienes Node.js instalado usando el nodejsrol.
A continuación se muestra un resumen de lo que está haciendo Kitchen en Test Action:
- Destruye la gota si existe
- Crea la gota
- Converge la gota
- Verifica la gota con InSpec
- Destruye la gota
Kitchen abortará la ejecución de su Droplet si encuentra algún problema. Esto significa que si su manual de Ansible falla, InSpec no se ejecutará y su Droplet no se destruirá. Esto le da la oportunidad de inspeccionar el estado de la instancia y solucionar cualquier problema. El comportamiento de la acción de destrucción final se puede anular si lo desea. Consulte la ayuda de CLI para obtener el --destroyindicador ejecutando el kitchen help testcomando.
Ha escrito sus primeras pruebas y las ha ejecutado en relación con su libro de estrategias, pero una instancia falló antes de solucionar el problema. A continuación, ampliará su archivo de prueba.
Paso 4: Agregar casos de prueba
En este paso, agregará más casos de prueba a su archivo de prueba para verificar si los módulos Nginx están instalados en su Droplet y si el archivo de configuración tiene los permisos correctos.
Edite su sample.rbarchivo para agregar más casos de prueba:
- nano test/integration/default/sample.rb
Agregue los siguientes casos de prueba al final del archivo:
prueba/integración/predeterminado/muestra.rb
. . .control 'nginx-modules' do impact 1.0 title 'NGINX modules' desc 'The required NGINX modules should be installed.' describe nginx do its('modules') { should include 'http_ssl' } its('modules') { should include 'stream_ssl' } its('modules') { should include 'mail_ssl' } endendcontrol 'nginx-conf' do impact 1.0 title 'NGINX configuration' desc 'The NGINX config file should owned by root, be writable only by owner, and not writeable or and readable by others.' describe file('/etc/nginx/nginx.conf') do it { should be_owned_by 'root' } it { should be_grouped_into 'root' } it { should_not be_readable.by('others') } it { should_not be_writable.by('others') } it { should_not be_executable.by('others') } endend
Estos casos de prueba comprueban que nginx-modulesen su Droplet se incluyan http_ssl, stream_ssly mail_ssl. También se comprueban los /etc/nginx/nginx.confpermisos de archivo.
Estás utilizando las palabras claves ity itspara definir tu prueba. La palabra clave itssolo se utiliza para acceder a las propiedades de los recursos. Por ejemplo, moduleses una propiedad de nginx.
Guarde y salga del archivo una vez que haya agregado los casos de prueba.
Ahora ejecute el kitchen testcomando para probar nuevamente:
- kitchen test
Verás el siguiente resultado:
Output...Target: ssh://root@104.248.131.111:22 ↺ nginx-modules: NGINX modules ↺ The `nginx` binary not found in the path provided. × nginx-conf: NGINX configuration (2 failed) × File /etc/nginx/nginx.conf should be owned by "root" expected `File /etc/nginx/nginx.conf.owned_by?("root")` to return true, got false × File /etc/nginx/nginx.conf should be grouped into "root" expected `File /etc/nginx/nginx.conf.grouped_into?("root")` to return true, got false ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installedProfile Summary: 0 successful controls, 1 control failure, 1 control skippedTest Summary: 4 successful, 2 failures, 1 skipped
Verás que algunas de las pruebas fallan. Para solucionarlas, agrega la nginxfunción a tu archivo de libro de estrategias y vuelve a ejecutar la prueba. En la prueba que falla, estás verificando nginxlos módulos y los permisos de archivos que actualmente no están presentes en tu servidor.
Abra su playbook.ymlarchivo:
- nano ansible_testing_dir/playbook.yml
Añade la siguiente línea resaltada a tus roles:
directorio_de_pruebas_ansible/playbook.yml
---- hosts: all become: true remote_user: ubuntu vars: NODEJS_VERSION: 8 roles: - nodejs - nginx
Guarde y cierre el archivo cuando haya terminado.
Luego ejecuta tus pruebas nuevamente:
- kitchen test
Verás el siguiente resultado:
Output...Target: ssh://root@104.248.131.111:22✔ nginx-modules: NGINX version ✔ Nginx Environment modules should include "http_ssl" ✔ Nginx Environment modules should include "stream_ssl" ✔ Nginx Environment modules should include "mail_ssl" ✔ nginx-conf: NGINX configuration ✔ File /etc/nginx/nginx.conf should be owned by "root" ✔ File /etc/nginx/nginx.conf should be grouped into "root" ✔ File /etc/nginx/nginx.conf should not be readable by others ✔ File /etc/nginx/nginx.conf should not be writable by others ✔ File /etc/nginx/nginx.conf should not be executable by others System Package nodejs ✔ should be installedProfile Summary: 2 successful controls, 0 control failures, 0 controls skippedTest Summary: 9 successful, 0 failures, 0 skipped
Después de agregar el nginxrol al libro de estrategias, todas las pruebas pasan. El resultado muestra que los módulos http_ssl, stream_ssly mail_sslestán instalados en su Droplet y que se establecieron los permisos correctos para el archivo de configuración.
Una vez que hayas terminado, o ya no necesites tu Droplet, puedes destruirlo ejecutando el kitchen destroycomando para eliminarlo después de ejecutar tus pruebas:
- kitchen destroy
Si sigue este comando verá un resultado similar al siguiente:
Output----- Starting Kitchen (v1.24.0)----- Destroying default-ubuntu-18... Finished destroying default-ubuntu-18 (0m0.00s).----- Kitchen is finished. (0m5.07s) 3.79s user 1.50s system 82% cpu 6.432 total
Ha escrito pruebas para su playbook, las ha ejecutado y ha corregido las pruebas que fallaron para garantizar que todas las pruebas funcionen correctamente. Ahora está preparado para crear un entorno virtual, escribir pruebas para su playbook de Ansible y ejecutar la prueba en el entorno virtual con Kitchen.
Conclusión
Ahora tienes una base flexible para probar tu implementación de Ansible, lo que te permite probar tus playbooks antes de ejecutarlos en un servidor activo. También puedes empaquetar tu prueba en un perfil. Puedes usar perfiles para compartir tu prueba a través de Github o Chef Supermarket y ejecutarla fácilmente en un servidor activo.
Para obtener detalles más completos sobre InSpec y Kitchen, consulte la documentación oficial de InSpec y la documentación oficial de Kitchen.

Deja una respuesta