Nach erfolgreichem Abschluss meiner Ausbildung zum Fachinformatiker für Anwendungsentwicklung habe ich gemeinsam mit einer Arbeitskollegin als Dankeschön für die Betreuung und Unterstützung während der Ausbildung ein kleines Geschenk für meinen Ausbilder gebastelt . Überlegt haben wir uns, angeregt von früheren Ideen aus der Abteilung, eine Lampe zu bauen, die den Build-Status vom Jenkins anzeigt. Wie ich das umgesetzt habe, möchte ich in diesem Beitrag einmal zeigen.
Hintergrund
Beim Jenkins handelt es sich um “ein erweiterbares, webbasiertes Software-System zur kontinuierlichen Integration von Komponenten zu einem Anwendungsprogramm”(Wikipedia). Es wird im Rahmen eines sogenannten Builds der aktuelle Source-Code aus einem Repository ausgecheckt und überprüft, ob die Anwendung kompiliert werden kann, ob alle Tests funktionieren und verschiedene andere Dinge. So kann man schnell sehen, wenn eine Änderung eine ungewollte Folge nach sich gezogen hat. Um dies noch besser visuell darzustellen, war die Idee, eine Lampe zu bauen, die grün leuchtet, wenn der Build erfolgreich durchläuft, gelb leuchtet, wenn der Build-Prozess aktiv läuft und rot wird, sollte der Build fehlschlagen.
Bauen einer solchen Lampe
Da ich in DIY-Projekten noch relativ wenig Erfahrung habe, war ich sehr glücklich eine leicht verständliche Anleitung auf dordnung.de gefunden zu haben, wie eine solche Lampe gebaut werden kann, die durch einen Raspberry gesteuert wird. Wie genau das geht, kann unter dem Link nachgelesen werden. An dieser Stelle möchte ich nur einmal alle verwendeten Bestandteile auflisten und verlinken.
- Raspberry Pi 3 Model B
- Micro SD Speicherkarte (Speicher für den Raspberry)
- Micro USB Ladekabel und USB-Ladegerät (Stromversorgung für den Raspberry)
- LED-Strip
- Steckbrett
- Steckbrücken Male-Male
- Steckbrücken Male-Female
- Transistoren
- Netzteil 12v (Stromversorgung, Anschluss an das Steckbrett)
- Stromadapter (zum Anschließen des Netzteils an das Steckbrett)
Architektur
Nach dem Befolgen der Anleitung können die LED’s über den Raspberry angesprochen werden. Dieser Raspberry darf aber in diesem Fall nicht direkt in das Unternehmens-Netz gehängt werden, um Sicherheitsrisiken zu vermeiden. Deswegen kann ich nicht direkt den Jenkins ansprechen, der nur im internen Netz erreichbar ist.
Die API vom Jenkins frage ich über ein Skript ab, dass auf einem internen Linux-Server ausgeführt wird. Je nach Build-Status wird eine Webseite aufgerufen, die auf meinem vServer von 1blu läuft. Dort führt ein PHP-Skript ein Kommandozeilenbefehl aus, wodurch der Inhalt einer Text-Datei angepasst wird. Diese Datei kann ebenfalls aus dem Internet erreicht werden. Diese Datei ruft der Raspberry dann nämlich auf und entscheidet je nach Inhalt, wie die LEDs leuchten sollen.
Abfragen der Jenkins API
Glücklicherweise bietet der Jenkins-Server von sich aus schon verschiedene APIs an. Ich habe mich dazu entschieden, die JSON-API zu benutzen. Zuerst bestimme ich an einem Projekt, welche die aktuelle Build-Nummer ist. Sobald ich diese ermittelt habe, frage ich die Informationen zu diesem ab. Je nachdem, was sich in diesem JSON-String nun befindet, rufe ich die oben beschriebene Webseite mit dem jeweiligen Statuscode als Parameter auf.
#!/bin/bash
jenkinsUrl="http://jenkins.intern"
projectName="Test"
branch="master"
website="https://example.com/"
urlJob=$jenkinsUrl"/job/"$projectName"/job/"$branch"/api/json"
jsonJob=$(curl $urlJob)
nextBuildString=$(sed -n 's/.*\("nextBuildNumber":[0-9]*\).*/\1/p' <<< $jsonJob)
nextBuild=${nextBuildString:18}
currentBuild=$(($nextBuild-1))
urlBuild=$jenkinsUrl"/job/"$projectName"/job/"$branch"/"$currentBuild"/api/json?pretty=true"
jsonBuild=$(curl $urlBuild)
# Projekt wird noch gebaut
case "$jsonBuild" in *'"building" : true'*)
curl $website"/?status=1"
esac
# Projekt kann nicht gebaut werden
case "$jsonBuild" in *'"result" : "FAILURE"'*)
curl $website"/?status=2"
esac
# Projekt kann gebaut werden
case "$jsonBuild" in *'"result" : "SUCCESS"'*)
curl $website"/?status=3"
esac
Verarbeiten dieses GET-Requests
Auf meinem Server muss ich diese GET-Anfrage nun verarbeiten und nutze dazu wie oben beschrieben PHP. Dabei lese ich eigentlich nur den übergebenen GET-Parameter status aus und führe dann mittels shell_exec() einen Kommandozeilen-Befehl aus. Dadurch ändert sich der Inhalt der Textdatei, die – wenn wir bei dem Code-Beispiel folgen – unter “https://example.com/status.txt” erreichbar ist. Aufgerufen wird die URL “https://example.com/?status=1”, wobei der Status auch 2 oder 3 sein kann.
<?php
$status = $_GET['status'];
if($status == 1){
echo shell_exec("/path/to/script/building.sh");
}
if($status == 2){
echo shell_exec("/path/to/script/failure.sh");
}
if($status == 3){
echo shell_exec("/path/to/script/success.sh");
}
?>
Das ausgeführte Skript building.sh sieht beispielsweise wie folgt aus.
#!/bin/bash
sed -i "s/.*/1/g" /path/to/file/status.txt
Es wird also der gesamte Inhalt der Datei durch – in diesem Fall – eine “1” ersetzt.
Abfragen dieser Text-Datei
Diese Text-Datei ruft der Raspberry dann auf und muss anhand dessen entscheiden, wie die Lampen leuchten sollen. Im Grunde ist der Code dazu recht simpel. Wichtig dabei ist, dass pigpiod gestartet wurde, um mit dem pigs-Befehl die Pins vom Raspberry ansprechen zu können.
#!/bin/bash
sudo pigpiod
status=$(curl https://example.com/status.txt)
case $status in
"1")
# building = yellow light
pigs p 17 255 # red
pigs p 22 255 # green
pigs p 24 0 # blue
;;
"2")
# failed = red light
pigs p 17 255
pigs p 22 0
pigs p 24 0
;;
"3")
# succeded = green light
pigs p 17 0
pigs p 22 255
pigs p 24 0
;;
*)
;;
esac
Automatisierung
Damit ich nicht jedes Mal, wenn ich den Build-Status abfragen möchte, beide Skripte manuell starten muss, habe ich jeweils einen Cronjob eingerichtet, der jede Minute läuft. So hat das Licht zwar eventuell eine Verzögerung von einer Minute. Da ein Build aber etwa eine Viertelstunde dauert, dürfte das ganz okay sein!
Ein Gedanke zu “Bauen einer Jenkins-Lampe zur Anzeige des Build-Status”