Introduzione a Jenkins

200 - featured image

Introduzione a Jenkins

DevOps “delicate” e  il nostro maggiordomo Jenkins

Agli inizi della mia carriera come sviluppatore mi sono imbattuto in una discussione (su una mailing list) tra altri sviluppatori che riguardava l’utilizzo di uno script bash particolarmente delicato su una macchina condivisa tra tutto il team di sviluppo. Questo script, per funzionare, richiedeva che fosse invocato con una speciale frase come parametro, tipo:

 
#./bash-script-particolarmente-delicato.sh "Ho letto tutta la documentazione e so cosa sto facendo"

Qualunque errore di battitura nella frase impediva l’avvio del processo, e la frase originale era MOLTO lunga!

La discussione era nata perché qualcuno si era stufato di dover inserire a mano quella frase e faceva copia e incolla tra le shell e quindi asseriva l’inutilità del controllo. A questa affermazione rispose uno degli autori originali dello script citando il numero di volte che era dovuto intervenire personalmente per risolvere i problemi scaturiti dall’esecuzione “impropria” del suddetto script e che quindi voleva mantenere quello stupido controllo come “moral suasion”.

Al giorno d’oggi i tool che ci aiutano nelle DevOps quotidiane sono molteplici e servono altrettante funzionalità: dalla gestione del codice condiviso alla compilazione parametrizzata, dalla produzione automatica della documentazione allo spostamento dei file binari nei vari repository.
Con il termine DevOps ci riferiamo a tutto l’insieme di operations di uso comune nel ciclo di sviluppo-test-rilascio. Quando queste sono troppo complesse (come lo script di cui parlavo) il rischio, per me, (a livello di progetto) è pari alla scarsa qualità del codice o alla poca sicurezza nella gestione dei dati.

In questo articolo vedremo come utilizzare alcuni strumenti che ci permetteranno di automatizzare alcune operazioni in modo da rendere affidabili e frequenti alcune delle operazioni meccaniche che svolgiamo tutti i giorni.

200 - jenkins logo Jenkins  è tra gli automation server, una delle scelte preferite in ambito Open Source e la sua estrema modularità è certamente uno dei motivi della sua popolarità. Jenkins è una evoluzione (fork) di un progetto chiamato Hudson nato in seno ad Oracle, che dal 2011 viene sviluppato dalla comunità Open Source.  Jenkins è sviluppato in Java e viene utilizzato principalmente per la compilazione di progetti Maven o Gradle, ma la vasta platea di plugin ne permette un uso molto variegato. Inoltre le esecuzioni dei job possono essere parametrizzate e anche schedulate.

Il numero di implementazioni dell'interfaccia ExtensionPoint è davvero impressionante!

Il numero di implementazioni dell’interfaccia ExtensionPoint è davvero impressionante!

Installazione e configurazione

Essendo Jenkins una web application (scritta in Java) ci sono diversi modi per installare il server:

  • tutti i sistemi: lancio manuale dell’eseguibile java -jar jenkins.war,
  • *nix: installazione da precompilato (dipende dalla distribuzione/packet manager),
  • servlet container: il .war puo’ essere deplyato all’interno di un webserver che supporti Servlet 2.4/JSP 2.0 o seguenti (es: da Tomcat 5 in avanti).

Personalmente, preferisco l’installazione di Jenkins come servizio separato anche nei casi la macchina abbia un servlet container, questo è utile anche per poter filtrare il traffico in ingresso e limitare l’accesso a Jenkins direttamente dal firewall.

Una volta installato il servizio può essere utile sbirciare al file di configurazione (in debian/ubuntu si trova in /etc/default/jenkins). In questo file ci sono tutte le impostazioni che vi potete aspettare (cartella home del servizio, porta http da usare, eseguibile java da utilizzare, file di log….).
Negli ambienti *nix la cartella home del servizio si trova generalmente in /var/lib/jenkins.

Appena connessi con un bowser alla porta configurata, si aprirà la famosa schermata home:

201 - jenkins home

Tra le prime impostazioni da controllare nella GUI: Configura Jenkins -> Configura sistema, ci sono:

  • # of executors: rappresentano il numero di job eseguibili contemporaneamente nel nodo, il valore di default è 2,
  • Jenkins Location: è l’URL pubblica di Jenkins stesso: <indirizzo IP>:<porta> se non avete un DNS, oppure :<nome DNS>:<porta>,
  • Maven Configuration : per poter eseguire job di tipo Maven è necessario averne installata almeno una versione,
  • JDK : elenco delle JDK da rendere disponibili come compilatori per i job.

Inoltre è caldamente consigliato impostare gli utenti (e i loro permessi) Configura Jenkins -> Configure Global Security.

I job di Jenkins

Dopo le dovute configurazioni possiamo passare alla creazione di un job. I job di Jenkins possono essere di vario tipo ma i principali sono 2:

Maven job: un job che comprende come passo principale l’invocazione di maven con un apposito pom.xml,
Generic job: un job che non prevede un passo principale (questo tipo di job è utile per eseguire operazioni diverse dalle build come invocare script shell o eseguire plugin specifici).

Le fasi di un job di tipo Maven sono:

  • Lettura dei parametri di input,
  • Gestione del codice sorgente,
  • Pre-build Steps,
  • Maven build,
  • Post-build Steps,
  • Azioni dopo la build,

Tutte le fasi sono opzionali (tranne la fase Maven in un progetto di tipo Maven job) e i plugin contribuiscono ad arricchire gli steps con molte funzionalità aggiuntive. Ciascuno step che non venisse completato con successo può far fallire l’intero job.

Un tipico job orientato alla CI, prende in input una stringa con il nome di un tag o di una branch e recupera i sorgenti corrispondenti copiandoli nella cartella del job dentro il workspace di Jenkins. Esegue poi l’invocazione di maven in quell’ambiente, con le opzioni e i goal predisposti. Può essere utile configurare Maven con un binary repository interno in modo da poter deployare i pacchetti compilati e renderli disponibili a tutto il team di sviluppo.

Uso dei Plugin: seleniumhq e selenium html report

Vediamo ora, come Jenkins possa essere usato anche per scopi diversi dalla semplice CI, sfruttando alcuni tra i moltissimi plugins già disponibili. In questo esempio creeremo un test con Selenium IDE e lo eseguiremo come job.

Selenium è uno strumento per l’automazione dei browser. Permette infatti di simulare il rendering di una pagina, l’esecuzione di script “client” in essa contenuto e la definizione di assertion…. per quasi tutti i browser moderni. SeleniumIDE è la parte del progetto che permette di definire (senza l’utilizzo di un linguaggio di programmazione) azioni e test da eseguire. Possiamo costruire così semplici test End-to-End.

I plugin necessari

Per l’esecuzione di questo job utilizzeremo i seguenti plugin:

  • Hudson SeleniumHq: necessario per eseguire il test Selenium;
  • Selenium html report: utile per visualizzare in un report i risultati dell’esecuzione dei test di Selenium;
  • File System SCM: non usando un Source Code Management, utilizziamo questo plugin per copiare i sorgenti dalla cartella di sviluppo nel workspace (automaticamente).

203 - installazione plugins

Scriviamo il job

Per trovare un esempio completo ma sintetico, immagino di voler scrivermi un job che mi faccia da watchdog per il sito web di cosenonjaviste.it.
Utilizzeremo Selenium IDE per creare una suite con un unico test che verrà schedulato per essere eseguito automaticamente. Sempre grazie ai plugins di Jenkins faremo poi produrre al job un report “intelligente” sullo stato del servizio.

 

204 - selenium ide

Interfaccia di Selenium IDE

Nota: Esportare direttamente i file HTML contenenti suite e test case da Selenium IDE è una comodità che presto sarà preclusa. Con l’avvento della completa fusione tra i progetti WebDriver e Selenium diventerà obbligatorio passare per un vero linguaggio di programmazione. Per questa guida ho scelto comunque di mostrare questa funzionalità perché si presta a mostrare bene le potenzialità dei plugins in Jenkins.

Una volta scritto il test supponiamo di salvarlo in una directory del server che ospita l’installazione Jenkins.

Esecuzione

Prima di avviare l’esecuzione dobbiamo assicurarci che la macchina (nel nostro caso una linux-box senza GUI) sia in grado di eseguire tutte le operazioni.

Elementi da controllare:

  • xvfc (export DISPLAY): qualora Jenkins sia avviato su una macchina senza server grafico dobbiamo “simularne” uno per permettere a Firefox di avviarsi,
  • path selenium-server.jar: nella configurazione generale di Jenkins bisogna inserire il path del server selenium,
  • installazione Firefox e controllo delle profile directory: può essere necessario completare alcune operazioni “manuali” con un profilo di Firefox e successivamente utilizzare quel profilo per avviare la suite di test [esempio: accettazione di un certificato self-signed].

Una volta ultimata la configurazione globale del server possiamo creare il job e configurare opportunamente i plugins che abbiamo installato affinché ognuno svolga il proprio compito.205 - selenium conf

Ed infine ammiriamo il risultato del job:

206 - selenium result

In questo paragrafo abbiamo semplicemente utilizzato plugin esistenti, ma, come avete visto, essi ci hanno permesso di estendere Jenkins in svariati aspetti. Abbiamo: aggiunto nuovi passi al processo di build, aggiunto nuovi passi alla fase di post-build e anche l’interfaccia grafica del job ha subito una integrazione per poter mostrare i risultati aggregati del processo di test. Inoltre abbiamo visto apparire una nuova sezione nella pagina di configurazione generale. Questo, e molto altro, è possibile grazie alle varie implementazioni dell’interfaccia ExtensionPoint.

Plugin personalizzati

In un prossimo articolo, vedremo come creare dei plugin personalizzati per le nostre operations. Questo ci permetterà di sfruttare al meglio, tutte le potenzialità del nostro maggiordomo di fiducia. Stay tuned.

Risorse online

Davide Zambon

Mi sono laureato in Scienze Informatiche e da allora la programmazione è, per me, la ricerca del modo più elegante per esprimere un algoritmo. Lavoro come Team Leader e architetto in ambiente Java ma ho avuto esperienze in ambiti molto diversi della programmazione. Le mie strutture dati preferite sono gli alberi: red/black, B, B+, binary, di ricerca, decision tree.... Ho come passione il volo libero in parapendio.