Jenkins Jobs laufen unendlich und lassen sich nicht abbrechen

Wenn du einen Jenkins Job (z.B. innerhalb einer Pipeline) haben solltest, welcher einfach unendlich lange läuft und sich auch nicht über die UI abbrechen/stoppen lässt, dann geh auf

[JENKINS_URL]/manage/script

und lass da folgendes Script laufen:

Jenkins.instance.getItemByFullName("[NAME_DES_JOBS]")
                .getBuildByNumber([NUMMER_DES_BUILDS])
                .finish(
                        hudson.model.Result.ABORTED,
                        new java.io.IOException("Aborting build")
                );

Dann einfach auf “ausführen” klicken und schon sollte der Job beendet sein.

Wie man den Zusammenbruch einer Zivilisation verhindert

In diesem extrem guten Vortrag geht Jonathan Blow auf die Problematik des Wissensverlustes von Zivilisationen ein. Er erklärt Anfangs das Grundproblem, warum viele alte Zivilisationen, die einst sehr mächtig und effizient waren, irgendwann einfach verschwunden sind – wie die Römer oder die Maya. In allen genannen Beispielen war es auf der einen Seite kein Untergang innerhalb eines Tages, sondern über viele Jahre, Jahrzehnte oder gar Jahrhunderte und sie hatten auf der anderen Seite vor allem eines gemeinsam: immer spielte der Verlust von Wissen die entscheidende Rolle.

Und mit diesen erkannten Prinzipien schwenkt er dann in die Neuzeit und münzt das Ganze auf die Problemantik, dass die moderne Welt nahezu komplett auf Hardware/Software basiert – was an sich ja erstmal nicht verkehrt ist. Allerdings befinden wir uns aktuell in einer Phase, in der nahezu viele Techniker zwar auf ihrem hohen Level sehr gut sind, aber die wenigsten noch die Grundlagen beherschen: wie funktioniert eine CPU bzw. wie baut man eine CPU, wie funktioniert ein Compiler im Detail, wie werden Daten im Speicher abgelegt und verwaltet und was exakt macht eine Garbage Collection? Das sind nur einzelne Bereiche, aber sie zeigen das Problem auf: je weniger Leute sich mit Basiswissen auskennen, desto höher die Wahrscheinlichkeit, dass dieses Basiswissen einmal verloren geht. Ja, natürlich kann man alles dokumentieren und archvieren. Trotzdem braucht es ja weiterhin Leute die dieses Wissen dann auch anwenden können.

Blow erklärt das sehr gut anhand der Situation in der Spielewelt (die Konferenz auf der er spricht ist eine Spielekonferenz) – genauer gesagt in der Welt der Indygames – in der es aktuell mehr oder weniger nur noch zwei führende Technologien gibt: Unity und Unreal. Keiner der entsprechenden Entwickler weiß, wie man selbst eine 3D Engine baut noch wie man absolut Low-Level einen Pixel auf den Bildschirm zeichen kann. Ich habe dafür mal von dem tollen Begriff des “Glue-Developers” gelesen: also ein Entwickler, der “nur noch” Libraries/Frameworks “zusammenklebt” und damit komplexe Applikationen baut. Das ist an sich etwas tolles, weil es effizient und wahrscheinlich sehr schnell ist. Aber was passiert, wenn es zu einem Fehler in einer darunter liegenden Library kommt?

Wie repariert man diesen Fehler bzw. wie findet man ihn überhaupt noch. NodeJS bzw. NPM ist ein gutes Beispiel wie absurd diese Abstraktion von Wissen werden kann, da dort selbst einfachste Funktionen in externe Libraries ausgelagert werden. Mit fatalen Konsequenzen.

Mich hat der Vortrag auf jeden Fall inspieriert, mal wieder einen Blick auf Basics zu werfen und lieber grundlegende Dinge wie Assembler/C Programmierung anzuschauen und mein Grundwissen da etwas auszubauen statt dem nächsten neuen Tech-Trend hinterherzueifern.

Wie man Featurebranches mit Jenkins baut

Meine Güte! Wie viel Zeit habe ich bereits in dieses Thema investiert und am Ende ist die Lösung meines Problems dann doch so simpel…

Aber fangen wir von vorn an. Der moderne Entwickler arbeitet in der Regel mit git und im optimalen Fall nach dem gitflow Konzept bzw. mit Featurebranches. Ist der Code fertig gestellt, wird ein für den Branch ein Review durchgeführt und davor bzw. gleichzeitig wird durch eine CI – in meinem Fall Jenkins – geprüft, ob dieser Branch denn so überhaupt noch lauffähig ist. Im konkreten Beispiel ist Atlassian Bitbucket dabei der Git host, es werden Pull Requests verwendet und um diese mergen zu können, muss Jenkins melden, dass der Code erfolgreich integriert werden konnte.

Jenkins ist dabei so eingestellt, dass es einen Job gibt, der auf sämtliche Branches eines Repositories lauscht. Sobald es einen Push gibt, checkt Jenkins diesen Code-Stand aus und baut ihn. Wenn alles gut ist meldet er das an Bitbucket zurück. Das Problem ist nun: was ist, wenn der Build wegen eines Problems auf der Buildnode, fehlendem Internet oder warum auch immer fehlschlägt? Dann wird man nie den Merge vollziehen können, da die Rückmeldung von Jenkins fehlt. Man kann nun einfach irgendeinen weiteren Commit machen, diesen pushen und es geht von neuem los. Oder aber, man macht es folgendermaßen:

Der ursprüngliche Job (“Job-01”), der auf alle Branches gelauscht hat, wird so umgebaut, dass er parametrisiert ist (Parametername “Branchname” z.B.) und im git Bereich wird angegeben , dass nur der Branch “$Branchname” gebaut werden soll. Anschließen legt man einen weiteren Job an (“Job-02”), der auf das gleiche repo sowie Veränderungen in allen Branches lauscht.

Dieser Job wiederum macht nichts anderes, als bei einer erkannten Änderung den parametrisierten Job  (“Job-01”) auszuführen und den entprechenden Branch als Parameter zu übergeben.

Nun haben wir erstmal den gleichen Zustand wie vorher – aber zusätzlich die Möglichkeit, den parametrisierten Job von Hand und unter Angabe des gewünschten Branches zu bauen. Also eben z.B., wenn der Job vorher fehlgeschlagen ist. Dieser wiederum kann dann seinen Status auch an Bitbucket melden.

Wenn der 3D Drucker auf einmal mit Licht zeichnen kann und wunderbare Videos zaubert

An dieser Stelle fehlen mir wirklich die Worte – so begeistert bin ich vom Projekt von Josh Sheldon. Er hat einen 3D Drucker so modifiziert, dass dieser in Langzeitaufnahmen mit Licht zeichnet. Und das in einem Automatisierungsgrad und einem Professionalitätslevel, der einen einfach nur sprachlos werden lässt. Aber schaut es euch selbst an:

python pip läuft nicht mehr wegen OpenSSL lib Fehler

Heute hat mich pip mit der Fehlermeldung

AttributeError: 'module' object has no attribute 'SSL_ST_INIT'

begrüßt. Da nach diesem Fehler sämtliche pip Operationen nicht mehr funktionieren, muss man etwas nachhelfen. Genauer gesagt: zwei Python OpenSSL Module müssen entfernt und nochmal neu installiert werden:

rm -rf /usr/lib/python2.7/dist-packages/OpenSSL
rm -rf /usr/lib/python2.7/dist-packages/pyOpenSSL-0.15.1.egg-info
sudo pip install pyopenssl

Danach sollte pip wieder wie gewohnt funktionieren.

PS: bitte achte drauf, dass du die korrekte Python Version bereinigst, das gleiche gilt für die pyOpenSSL Version!

Am einfachsten findest du die Version heraus, indem du dir per

which pip

den Pfad zu pip geben lässt, dann mit einem vi/nano /[PATH_TO_PIP]/pip in der obersten Zeile anschaust, welcher Interpreter verwendet wird, diesen Pfad kopierst und dann mit

/PATH_TO_PYTHON/python --version

die korrekte Version herausbekommst.

Wie man das 5 Sekunden boot Delay beim Digispark / Digistump attiny85 entfernt

Neben den ESP8266 Microcontrollern hatte ich mir zum Herumspielen auch ein Dreierpack attiny85 Microcontroller von Digispark bestellt. Diese sind sehr klein, stromsparend und können für verschiedenste kleine Aufgaben herangezogen werden. Der entsprechend installierte Bootloader macht die Entwicklung dabei besonders einfach, weil man mit der Arduino IDE arbeiten kann und das Gerät einfach nur anstecken muss und nicht irgendwelche Programmer benötigt oder so.

Diese Einfachheit hat allerdings einen Nachteil: immer, wenn man den attiny85 mit dem Strom verbindet, wartet der Bootloader 5-6 Sekunden lang, ehe das installierte Programm startet. Und hier möchte ich euch nun zeigen, wie ihr den Bootloader so modifizieren könnt, dass er direkt das Programm startet und statt der 5s Wartezeit mittels Jumper in den Programmier-Modus gebracht wird.

Dazu benötigt ihr:

Neuer Bootloader:
https://github.com/micronucleus/micronucleus/blob/v1.11/upgrade/releases/micronucleus-1.11-entry-jumper-pb0-upgrade.hex

Upload Software:
https://github.com/digistump/DigistumpArduino/tree/master/tools

Ladet euch das für euer Betriebsystem passende tar.gz herunter und entpackt es. In den entpackten Ordner könnt ihr der Einfachheit halber direkt die Hex Datei packen.

Der Upload ist dann eigentlich ganz leicht:

chmod +x micronucleus <-- die Binary ist nicht ausführbar, muss man also einmalig erledigen...
./micronucleus micronucleus-1.11-entry-jumper-pb0-upgrade.hex

Ihr werdet nun aufgefordert, den attiny85 anzustecken. Sobald das erledigt ist, wird der neue Bootloader gebrannt. Anschließend müsst ihr ca. 30s warten, dann das Gerät vom USB abziehen und den Pin GND mit Pin P0 verbinden. Nun zurück zur Arduino IDE wechseln, erneut den Upload des Programmes starten und wenn ihr aufgefordert werdet steckt ihr den attiny85 mit der GND-P0 Verbindung an. Nachdem die Firmware geschrieben wurde, zieht ihr das Teil wieder ab und trennt die Verbindung zwischen GND und P0. Wenn er nun wieder mit dem Strom verbunden wird, sollte der attiny85 sofort und ohne Pause das Programm starten.

Beim Ausführungen von Java jnlp Anwendungen erscheint ein Access Denied Fehler

Beim Ausführen einer Java Anwendung mit einer jnlp Datei bekam ich komischerweise immer wieder Fehlermeldungen „java.io.FilePermission“ für die Datei „/usr/bin/xprop“. Die Datei war im System vorhanden und durfte auch von jedem ausgeführt werden, selbst mit Sudo kam der Fehler.

Die Lösung des Problems ist zwar relativ leicht, aber mal wieder sehr ärgerlich: es ist ein Fehler in der OpenJDK und in meinem Fall der icedtea-netx Implementierung. Und um diesen zu umgehen muss man leider die original Oracle JAVA JRE runterladen und installieren.

Wichtig hierbei: man muss wohl zwingend die tar.gz Variante und nicht die RPM Variante nehmen, da nur diese „javasw“ enthält.

Das Vorgehen für die Installation ist:

  • openjdk und co vom System schmeissen (es geht auch anders, aber man muss die Sache ja nicht unnötig verkomplizieren)
  • unter http://www.oracle.com/technetwork/java/javase/downloads/index.html den Download Button unter „JRE“ anklicken und auf der folgenden Seite die AGB akzeptieren und dann die entsprechende tar.gz für 64bit oder 32bit herunterladen
  • tar.gz entpacken und den Ordner nach /usr/java/[ORDNER_NAME] verschieben
  • anschließend (keine Ahnung ob das der richtige Weg ist, aber er funktioniert) unter /usr/bin per Link die java und javasw Binaries verlinken:
cd /usr/bin
ln -s /usr/java/[ORDNER_NAME]/bin/java
ln -s /usr/java/[ORDNER_NAME]/bin/javasw

Nun könnt ihr die jnlp Datei einfach per
javasw [DATEI].jnlp aufrufen.

[Quicktip] Befehl für den Reset / Restart eines ESP 12 / 32 Microcontrollers

Normalerweise kann man einen ESP8266 per Pin „Kurzschluss“ oder einfach über die entsprechende Taste auf dem Board Neustarten. Ich wollte das ganze aber per Code machen, und die Suche nach der Lösung hatte mich etwas verzweifeln lassen. Dabei ist es doch so einfach 🙂

esp_restart();

Python MySQL connector liefert in einer Endlossschleife immer das gleiche Query Ergebnis

Für ein Projekt habe ich einen Runner laufen, der in bestimmten Intervallen eine MySQL Datenbank abfragt, ob es neue Jobs für ihn zu tun gibt. Letztendlich handelt es sich einfach um eine Endlos-While-Schleife, in der immer wieder die Query ausgeführt wird.

Das Problem war aber nun: der Runner hat im aktuellen Lauf scheinbar immer nur das Ergebnis des ERSTEN Durchlaufs der Schleife aus dem Cache gelesen. Dabei handelt es sich wohl nicht um einen Fehler auf Python Seite, sondern in MySQL selbst. Die Lösung ist zwar technisch nicht gerade schön gelöst, aber sie funktioniert: man muss einfach nur die Autocommit-Funktion für die aktuelle Verbindung zum MySQL Server aktivieren. Und das geht so:

cnx = mysql.connector.connect(...)
cnx.autocommit = True

Durch dieses Setting wird dem MySQL Server ein “set autocommit=1;” übertragen, was dann dazu führt, dass der Query Cache komplett umgangen wird.