A la hora de agilizar el desarrollo, una buena idea es tratar de automatizar procesos que se realicen de forma manual. Obviamente, aquellos que requieran intervención humana no podrán automatizarse (o al menos, no totalmente), pero otros procesos como la ejecución de tests sobre un proyecto o realización de operativas como recargas de entorno, despliegues u otro tipo de acciones, pueden ahorrar bastante tiempo (y algo de salud mental a los desarrolladores: ejecutar manualmente tareas repetitivas suele ser muy frustrante).
Es en este punto donde entra en juego una herramienta como Jenkins. Jenkins es un software de automatización de código abierto que permite implementar tareas de integración continua como procesos automáticos para desplegar entornos, testear diferentes ramas u otras operativas sobre los diferentes sitios de un proyecto.
Jenkins, el maestro de las tareas
La unidad básica de Jenkins son las tareas, jobs o proyectos, términos que se pueden usar indistintamente. Cada job es una tarea gestionada por Jenkins, y gracias a la flexibilidad de Jenkins puede ser casi cualquier cosa: ejecutar tests, recargar entornos, limpiar ficheros temporales de otros procesos o cualquier otro proceso automatizable. Por ejemplo, imaginemos un proyecto Drupal: un sitio Drupal ofrece una serie de operativas que normalmente requieren o acceso de administrador al sitio o acceso a la consola del servidor (o servidores) donde se ejecuta. Con Jenkins podríamos crear tareas para cada una de estas operativas, de forma que para realizarlas solo hace falta acceder al servidor Jenkins. Si concentramos las operativas de nuestros proyectos en Jenkins la complejidad para acceder a las operativas de todos nuestros sitios se reduce a acceder a Jenkins (bueno, y a establecer una política de seguridad en Jenkins de acceso a los jobs, pero eso es materia de otro artículo).
Por ejemplo, pongamos que un proyecto ofrece las siguientes operativas por cada entorno:
- Obtener un enlace de login.
- Limpiar cachés.
- Lanzar la ejecución de cron.
- Obtener el estado.
- Desplegar nuevo código.
- Recargar el entorno con datos de otro (normalmente la fuente será el entorno de producción).
- Realizar un backup.
- Ejecutar smoking tests.
- Ejecutar tests sobre una rama de código.
Interesante, ¿no? Lo que es menos interesante es tener que configurar cada una de estas tareas. Si solo tuviésemos un proyecto en desarrollo no habría problema: se configura una vez y listo. Pero cuando tenemos varios o muchos proyectos en marcha resulta tedioso y propenso a errores el tener que crear manualmente mediante el interfaz de Jenkins las mismas tareas por cada proyecto. Un momento, ¿no hemos dicho que para agilizar el desarrollo una buena idea es automatizar procesos? ¡Pues la creación de los jobs en Jenkins tiene toda la pinta de ser un proceso manual automatizable!
Job DSL plugin, el hacedor de jobs
Entre los muchos plugins de Jenkins encontramos Job DSL. Este plugin permite crear varios jobs de forma automática a partir de un job principal llamado seed. Se denomina así por ser la semilla de la que se crean otros jobs. De esta forma evitamos tener que volver a crear los mismos jobs para cada nuevo proyecto que precise de tareas similares, pudiendo montar todas las tareas para cada proyecto simplemente ejecutando la tarea semilla. No solo eso, si modificamos la tarea semilla y volvemos a ejecutarla Jenkins actualizará los jobs ya creados. Así, podríamos actualizar un único job (nuestra tarea semilla) y actualizar automáticamente todos los proyectos que usen las tareas generadas por esa semilla. Fantástico, ¿no?
La tarea semilla consta básicamente de un fichero con un script de Groovy dónde se definen las tareas a crear de forma automática. Aunque no hayas usado nunca Groovy no debes preocuparte, existen muchos ejemplos y su sintaxis es muy similar a otros lenguajes que seguro conoces o te suenan. Además, puedes contar con la ayuda el plugin XML JOB to Job DSL, que exporta tareas ya existentes a formato Groovy, lo que nos podrá servir de base para crear nuevas tareas partiendo de este código exportado automáticamente.
Creando una tarea semilla
A continuación vamos a mostrar un ejemplo de cómo generar un job básico usando el plugin Job DSL. Lo primero que se debe hacer es crear un nuevo job de tipo libre (Freestyle):
Una vez creado, debemos añadir un paso de tipo «Process Job DSLs» a la sección Build. Esta sección es dónde se le dice a Jenkins en qué consiste la tarea y qué pasos debe realizar para completarla. Jenkins ofrece varios tipos de pasos que no comentaremos aquí porque se sale del alcance de este artículo. Baste saber que aquí debemos indicar a Jenkins dónde está el fichero Groovy que debe ejecutar:
De dónde sale es archivo ya depende de cómo tengáis montado Jenkins. Normalmente se suele configurar un repositorio de código que Jenkins consulta y descarga que contendrá el fichero Groovy, pero podemos escribir directamente el script en la configuración de la tarea o fijar una ruta en el sistema de ficheros donde vayamos a situar el script DSL si preferimos usar un fichero. El mecanismo es secundario, pero al final Jenkins siempre acabará disponiendo del script Groovy con las instrucciones para crear los jobs.
Un ejemplo de script Groovy
¿Y cómo sería un script de Groovy que sirva para una tarea semilla? Veamos un ejemplo de cómo crear un contenedor de tareas en Jenkins, con el método folder (es decir, una carpeta donde poner tareas o jobs, que es lo mismo), y dentro de dicha carpeta crear una tarea de tipo pipeline (es uno de los tipos de job que ofrece Jenkins):
String basePath = 'dsljobs'
String repo = 'git@repo:name/project'
folder(basePath) {
description 'DSL generated folder.'
}
pipelineJob("$basePath/status") {
description()
definition {
cpsScm {
scm {
git {
remote {
url(repo)
}
branch("*/dev")
}
}
scriptPath("Jenkinsfile.status")
}
}
}
La creación de la carpeta es lógicamente el bloque que empieza por folder. El siguiente bloque, pipelineJob, crea el job de tipo pipeline. El tipo no es relevante, pero usamos extensivamente este tipo de job por lo que lo usamos aquí como ejemplo. En la tarea de tipo pipeline creada se define una URL a un repositorio de código y un Jenkinsfile, que es el fichero que realmente contiene las instrucciones que componen el job que se creará. Por supuesto, el propio fichero DSL puede contener los detalles de la tarea a ejecutar en vez de referenciar otro fichero, pero es que no teníamos un ejemplo más sencillo a mano.
Dentro del fichero DSL podemos hacer uso de muchas funciones que ofrece el plugin como parte de su API.
Una vez creada la tarea semilla podremos acceder a ella desde la interfaz de Jenkins, y si pulsamos «Construir ahora» (o «Build now» si el interfaz de Jenkins está en inglés) se ejecutará y creará la tarea que hemos definido dentro. Obviamente nuestro ejemplo es pobre: Job DSL es realmente útil cuando crea varias tareas, como el listado de operativas del principio del artículo, pero la idea es la misma: crear tareas de forma automática.
Por cierto, la ejecución de la tarea semilla puede fallar debido a un mecanismo de seguridad de Jenkins que evita la ejecución de ficheros Groovy que no han sido aprobados. Para ello hay que ir a la configuración de Jenkins, a la sección «In-process script Approval». Una vez aprobado el script de Groovy, le daremos a construir la tarea de nuevo y deberá funcionar. Esto hay que hacerlo cada vez que cambie el script por cuestiones de seguridad. Aunque se puede deshabilitar, no es recomendable hacerlo si queremos mantener un Jenkins seguro.
Y eso todo por hoy. Jenkins y Job DSL tienen muchas más funcionalidades, aquí solo hemos arañado un poco la superficie, pero creo que con lo visto en este artículo es suficiente para ver las grandes posibilidades que ofrece a la hora de automatizar la creación de tareas para nuestros proyectos.