====== CI/CD amb Jenkins, Django i Selenium ======
En el context de DevOps, els sistemes de CI/CD han esdevingut molt importants per evitar-nos de fer tasques repetitives de testeig d'aplicacions que necessiten una revisió i actualització constant.
https://jenkins.io és probablement el software d'automatització de testeig més popular. El provarem juntament amb un projecte web fet amb Django (conegut com "the web framework for perfectionists with deadlines"), concretament el [[https://github.com/aws2/BorsaDeTreball/|projecte de Borsa de Treball fet a l'institut Esteve Terradas de Cornellà]].
Els tests funcionals que es realitzen en aquest projecte es duen a terme amb [[https://es.wikipedia.org/wiki/Selenium|Selenium]], unes llibreries disponibles en diferents llenguatges que ens permeten automatitzar les accions del //browser// com si es tractés d'un usuari real. Com que és extern al projecte en sí, es pot fer en un llenguatge diferent del propi projecte (pel nostre cas estan integrats en els tests de Django, però podrien fer-se ben bé a part).
{{jenkins_logo.svg?150}}
{{django-logo.png?300}}
{{selenium-logo.png}}
{{tag> #FpInfor #Ciber #CiberMp03 #Ceti #CetiMp03 #Asix #DawMp08 DevOps CI CD CI/CD Jenkins Django Selenium }}
===== Servidor =====
Primer caldrà que disposem d'un servidor propi al núvol o en una VM a la màquina local. Preferentment ha de ser una VM Ubuntu 20.04 LTS, tot i que es pot fer amb qualsevol GNU/Linux.
També ho podeu instal·lar a la pròpia màquina local, però la idea d'aquest tutorial és poder instal·lar un servidor complert extern dedicat al testing.
Podeu crear la VM amb [[Vagrant]] amb el següent Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.hostname = "jenkinshost"
# A casa fixem la IP per poder seguir treballant després
# A l'insti vigileu de no col·lisionar les IP amb els vostres companys
config.vm.network "public_network", ip: "192.168.1.221"
# També podem accedir per localhost:8080
config.vm.network "forwarded_port", guest: 8080, host: 8080
# Configurem mes paràmetres
config.vm.provider "virtualbox" do |vb|
vb.name = "jenkinshost"
vb.gui = false
vb.memory = "2048"
vb.cpus = 2
end
end
\\
===== Instal·lar Jenkins =====
Per instal·lar Jenkins primer de tot ens cal disposar de Java:
$ sudo apt install default-jre
Després podeu seguir les [[https://pkg.jenkins.io/debian-stable/|instruccions estàndard de la web de Jenkins per a Debian/Ubuntu]].
Si ja tenim instal·lat Jenkins, podem accedir-hi via port 8080. Recordeu obrir el //firewall// si esteu utilitzant algun proveïdor al núvol.
http://elmeuserver.com:8080
Us demanarà que li entreu un token d'admin que podreu trobar en un arxiu del sistema (així s'assegura que és un //sysadmin// el qui ho està instal·lant).
==== Selenium Web Driver ====
A més, per poder fer testing web funcional, ens caldrà disposar d'un //browser//, pel que instal·larem Firefox. Com que es tracta d'un servidor //headless// (sense GUI) no es podrà posar en marxa de forma gràfica, però Selenium disposa del model //headless// en el //driver//.
Si tens Ubuntu:
$ sudo apt install firefox firefox-geckodriver
Si utilitzes Debian has de [[https://github.com/mozilla/geckodriver/releases|descarregar el darrer geckodriver]], descomprimir-lo i copiar-lo /bin, i instal·lar firefox-esr:
$ sudo apt install firefox-esr
$ wget https://github.com/mozilla/geckodriver/releases/download/v0.30.0/geckodriver-v0.30.0-linux64.tar.gz
$ tar xf geckodriver-v0.30.0-linux64.tar.gz
$ sudo cp geckodriver /bin
\\
===== Projecte Django =====
Provarem els tests implementats al [[https://github.com/aws2/BorsaDeTreball/|projecte de Borsa de Treball fet a l'institut Esteve Terradas de Cornellà]].
Abans caldrà que configurem la base de dades i les dependències necessàries per treballar amb Python.
Si estàs en Ubuntu:
$ sudo apt install git python3-venv mysql-server
Si utilitzes Debian:
$ sudo apt install git python3-venv mariadb-server
==== Configurar la BD ====
Crearem una BD "borsa" que no farem servir però que el projecte necessita per no donar error. També crearem l'usuari "admin" amb permisos per accedir a totes les BD:
$ sudo mysql
mysql> create database borsa;
mysql> create user admin@localhost identified by "admin123";
mysql> grant all on *.* to admin@localhost;
mysql> flush privileges;
==== Provar projecte en Shell ====
Ara ja podem clonar el projecte de Borsa De Treball, seguint les pròpies instruccions del README.
Si tens Ubuntu:
$ sudo apt-get install -y libmysqlclient-dev python3-dev gdal-bin python3-mysql.connector python3-mysqldb libssl-dev libjpeg-dev
Si tens Debian:
$ sudo apt-get install -y libmariadb-dev-compat gcc gdal-bin libjpeg-dev python3-venv python3-dev
Descarreguem l'aplicació:
$ git clone https://github.com/aws2/BorsaDeTreball.git
$ cd BorsaDeTreball
$ python3 -m venv env
$ source env/bin/activate
(env)$ pip install -U pip
(env)$ pip install -r requirements.txt
Fins aquí les passes indicades al README. El //prompt// ''(env)$'' ens indica que ara estem dins de l'entorn virtual "env".
Ara ens cal fer alguns ajustos per engegar el projecte. Primer de tot, necessitem un arxiu .env amb les variables d'entorn, però li traurem les 2 darreres línies on apareix la DATABASE_URL que cal ajustar:
(env)$ head -n -2 BorsaDeTreball/.env.example > BorsaDeTreball/.env
(env)$ echo "DATABASE_URL=mysqlgis://admin:admin123@localhost/borsa" >> BorsaDeTreball/.env
Ara fem uns checks abans de començar els tests:
(env)$ python manage.py check
Si no ha donat error, podem engengar els tests (ull, que pot arribar a trigar alguns minuts):
(env)$ python manage.py test
(env) vagrant@ubuntu:~/BorsaDeTreball$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
....
----------------------------------------------------------------------
Ran 4 tests in 240.708s
OK
Destroying test database for alias 'default'...
Quan el test està correcte s'ens mostra un punt ".", mentre que si és erroni ens apareix una "E" juntament amb el motiu de l'error.
=== Troubleshooting ===
Si us apareix algun d'aquests errors:
selenium.common.exceptions.WebDriverException: Message: Failed to decode response from marionette
selenium.common.exceptions.InvalidSessionIdException: Message: Tried to run command without establishing a connection
selenium.common.exceptions.NoSuchWindowException: Message: Browsing context has been discarded
selenium.common.exceptions.WebDriverException: Message: Failed to convert data to an object
En [[https://stackoverflow.com/questions/49734915/failed-to-decode-response-from-marionette-message-in-python-firefox-headless-s|aquest article de Stackoverflow]] s'indica que augmentant la RAM de la màquina de test fins a 2GB soluciona el problema.
Si apareixen errors de desenvolupament (s'ha introduït un error a la branca ''dev''), hauria de ser mes segur canviar a la branca de producció i provar de nou:
$ git chechout pro
$ python manage.py test
==== Provar tests amb GUI ====
Si vols provar els tests veient com Selenium realitza els clicks i accions sobre el navegador (Firefox), pots comentar el codi on es posa el //WebDriver// en mode //headless//, al menys el trobaràs a als arxius ''core/tests.py'' i ''borsApp/tests.py''. Comentar-les amb un # per tal de desactivar el mode //headless//.
#firefoxOptions.set_headless()
Per poder fer aquest pas necessitareu una màquina amb GUI o bé disposar de, com a mínim el paquet ''xorg'', i connectar-nos a la VM habilitant un túnel per les X-windows.
A la VM:
$ sudo apt install xorg
$ exit
Des de la màquina //host//:
$ ssh user@maquina -X
O si esteu utilitzant Vagrant:
$ vagrant ssh -- -X
Testejeu abans si podeu arrencar el firefox:
$ firefox
Això pot ser interessant per depurar alguns problemes i per curiositat de veure com funciona el WebDriver de Selenium.
\\
===== Automatitzar Jenkins =====
Si ens funcionen els tests en la màquina via //shell//, ara podrem automatitzar la seva execució amb Jenkins.
Accedim a Jenkins via port 8080 i ens loguem amb l'usuari administrador que hem configurat durant la instal·lació:
http://elmeuserver.com:8080
El què farem ara serà automatitzar totes les tasques que acabem de fer, posant-les en una tasca de Jenkins. Les passes a realitzar son les següents:
=== Crear tasca ===
Crear "item nou" del tipus "freestyle"
* Omplir Descripció amb "Borsa de Treball"
* Secció "Gestor de codi font"
* Git repo: ''https://github.com/aws2/BorsaDeTreball''
* Braches to build: ''*/dev''
* Secció ''Build -> Add Build Step -> Execute Shell'' i afegim el codi shell:
python -m venv env
. env/bin/activate
pip install -U pip
pip install -r requirements.txt
head -n -3 BorsaDeTreball/.env.example > BorsaDeTreball/.env
echo "DATABASE_URL=mysqlgis://admin:admin123@localhost/borsa" >> BorsaDeTreball/.env
python manage.py test
=== Executar tasca ===
- Anar a ''Dashboard -> Borsa de Treball -> Construir ara''
- Anar a build, pel primer cas serà el ''#1 -> Console Output''