Currently in german only.

Was ist zu tun, wenn Build fehlgeschlagen?

Es gibt mehrere Möglichkeiten, warum ein Build fehlschlägt. Hier eine kleine Auswahl an bekannten Problemen:

Der Build-Prozess

Der in Jenkins definierte Build-Prozess besteht aus folgenden Teil-Schritten:

Jede Nacht um 0 Uhr beginnt der Build-Prozess, indem der Build "Odysseus Nightly Build" (und damit die Build-Pipeline) gestartet wird. Da das "fetchen" bzw. importieren der Target Platform recht lange dauert und sich diese nur selten ändert, wird der Teil-Build "Fetch and Build Target" nicht täglich ausgeführt, sondern muss beim Ändern der Target-Platform per Hand geändert werden. 

Zusätzlich erfolgt noch jede Stunde ein Test-Build:

 

Aufbau des Produkts: Platform + Hauptfeature

Problem ist, dass man das Kern-Produkt einer RCP-Anwendung nicht einfach durch Updates aktualisieren kann, da die Abhängigkeiten nicht aufgelöst werden können. Dies liegt u.a. daran, dass die Anwendung selbst noch läuft wenn man auf "check for updates" geht und es nicht möglich ist, eine Version zu aktualisieren, während die andere als Teil der RCP-Anwendung noch läuft.

Aus diesem Grund wird Odysseus so gebaut, dass es eine Basis-Platform als Hauptanwendung gibt, die nicht aktualisierbar ist und der Rest - als das komplette eigentliche Odysseus - als ein zusätzlichen Feature (Hauptfeature) hinzu installiert wird. Da das Hauptfeature hinzu installiert wird, ist es aktualisierbar und damit ist dann auch ganz Odysseus über die Updatesite aktualisierbar.

Also gibt es zwei Teile: eine fast leere Platform und ein Hauptfeature, dass Odysseus beinhaltet und je nach Produkt (Server, Studio, Server+Studio) andere Kombinationen von anderen Features enthält. Diese beiden Teile werden in der buckminster_product.properties definiert.

Wie erwähnt, enthält die Platform nur eine Basis zum Ausführen von Odyssues. Eine Product-Definition legt dabei die Platform fest. Dazu wird ein Platform-Feature verwendet, damit dieses Platform-Feature auch in anderen Product-Definitionen verwendet werden kann. Ein Platform-Feature beinhaltet letztlich nur die Platform (Equinox, ggf. RCP etc.) und zusätzlich ein starter-bundle. Dieses starter-Bundle beinhaltet die OSGi-Application, die Odysseus startet.Gestartet wird Odysseus im Prinzip dadurch, dass alle Bundles gestartet werden - also wird Odysseus nie direkt aufgerufen.

Wichtig ist hierbei jedoch, dass die Platform keine Abhängigkeiten zu Odysseus haben darf! Daher dürfen die Bundles rcp.starter, studio.starter und server.starter auch keine Abhängigkeiten zu Odysseus haben! Dies gilt natürlich auch in die andere Richtung.

Dies ist wichtig, da sonst die Platform ebenfalls bspw. ein odysseus-core benötigt, dass dann wieder Teil der Basis-Platform wäre und dann nicht mehr aktualisierbar ist.

Die ganzen Bundles von Odysseus (core, planmanagement etc.) werden über Hauptfeatures kombiniert. Jenkins installiert im Prinzip dieses Hauptfeature, als wenn der Benutzer "install new software" über das Menü verwendet hätte.

Der grobe Aufbau der Build-Prozesse (s.o.) zu den Teilen, ist dabei wie folgt (die Zuordnung wird über die buckminster_product.properties konfiguriert):

 

Man kann hierbei erkennen, dass Studio und Server+Studio sich nur dadruch unterscheiden, dass jeweils ein anderes Hauptfeature hinzu installiert wird.

Da das eigentliche Odysseus über das Hauptfeature "nachinstalliert" wird, startet das Product "Odysseus Product Platform Server.product" bzw. "Odysseus Product Platform Studio.product" nicht Odysseus - es kennt Odysseus nicht einmal und darf es auch nicht kennen!!! Das heißt, dass man zum Starten per Hand (z.B. aus Eclipse heraus zum Entwickeln) ein eigenes Produkt (a la das alte Memory Store Product) brauch, das sowohl das Platform-Feature als auch das Hauptfeature beinhaltet!!

 

Kontrolle des Build-Prozesses

Per Browser

Man kann Jenkins unter
http://odysseus.informatik.uni-oldenburg.de:8080
aufrufen.

Unter Eclipse

Es gibt ein Eclipse-Plugin, welches normalerweise mit Mylyn mitinstaliert wird.
Wer mylyn noch nicht hat, der kann diese Update-site benutzen:
http://download.eclipse.org/mylyn/releases/latest
Dann gibt es unter Windows/ show views / Other / mylyn die view „builds“ – diese öffnen und dann kann man einen neuen Build-Server hinzufügen.
Dort dann http://odysseus.informatik.uni-oldenburg.de:8080 und seinen benutzer + password eintragen. Dann noch den harken bei Build Plans setzen, die man sehen will.
Damit kann man auch den Build aus Eclipse starten.

Features über Update-Site installieren

Wie oben beschrieben, kann man eine ausführbare Version von Odysseus unter downloads herunterladen und diese dann nachträglich um zusätzlichliche Features (z.B. CEP) erweitern, indem man die Updatesite über Help > Install New Software innerhalb von Odysseus verwendet. Odysseus lässt sich dann (wenn ein neuer Build gemacht wurde) auch aktualisieren.

Neues Feature zum Build-Prozess für Update-Site hinzufügen

Um ein zusätzliches Feature hinzuzufügen müssen  folgende Schritte gemacht werden:

Neues Feature

Die entsprechenden Features müssen in der feature.xml im Bundle de.uniol.inf.is.odysseus.update.p2 unter "Included Features" hinzugefügt werden. Damit werden sie schon automatisch mit in die Update-Site integriert und sind dann "nachinstallierbar" bzw. aktualisierbar (wie unten beschrieben). Man kann die Features bei Bedarf noch in der category.xml in kategorisieren. Hierbei darauf achten, dass das Feature eine andere ID (in der feature.xml unter Overview) als das Bundle hat (jede ID muss unique sein)! Also am besten wie das Bundle selbst auch auf ".feature" enden lassen.

Produkt ändern (Features hinzufügen)

Es gibt nur zwei Product-Definition, die von Jenkins benutzt werden (s.o. bei "Aufbau des Produkts"). In verschiedenen Konfigurationen werden dann nur die notwendigen Features hinzu installiert. Entsprechend gibt es bspw. ein Feature "de.uniol.inf.is.odysseus.product.server.feature", welches alle notwendigen Features für das Server-Product zusammenfasst. Dieses wird dann zu dem Basis-Produkt (Odysseus Product Platform Server.product) hinzugepackt. Dieses ist in der buckminster_product.properties in dem updatesite-Bundle definiert. Möchte man also sein Feature hinzufügen, muss folgendes gemacht werden:

Achtung!
Die Product-Konfigurationen (also alle *.product) werden von Jenkins ignoriert. Lediglich die "Odysseus Product Platform Studio.product"  und  "Odysseus Product Platform Server.product" werden als Basis verwendet. Diese Produkt darf jedoch nicht irgendwie abhängig zu Odysseus core oder anderen Features sein!!!

Man muss natürlich aufpassen, dass alle notwendigen Bundles/abhängigen Features angegeben sind und das sich das Ganze in trunk befindet oder Teil der Target-Platform sind.

Neues Produkt zum Build-Prozess hinzufügen

Wer ein komplett eigenes Produkt bauen lassen will, der sollte unter "Ein ganz neues Produkt bauen lassen" gucken. Wer nur seine eigene Konfiguration bzw. Zusammenstellung von Features auf Basis von Odysseus haben möchte, der sollte unter "Ein Odysseus-Produkt mit anderen Feature-Sets bauen lassen" schauen.

Ein Odysseus-Produkt mit anderen Feature-Sets bauen lassen

Diese Schritte bieten sich an, wenn man nur - z.B. im Vergleich zum Server+Studio-Product - zusätzliche Features hat, die immer automatisch vorinstalliert sein sollen.

  1. Ein Feature erstellen, das unter "Included Features" alle Features enthält, die man haben möchte. Je nachdem ob man einen Client, Server oder Monolithic haben will, sollte man hier eines der drei folgenden Features dort aufnehmen, um die jeweilige Basis-Funktionalitäten von Odysseus bereits zu haben:
    1. Für Server: de.uniol.inf.is.odysseus.server.feature
    2. Für Client: de.uniol.inf.is.odysseus.client.feature
    3. Für Monolithic: de.uniol.inf.is.odysseus.monolithic.feature
  2. Dann fügt man seine eigenen Features unter "Included Features" hinzu.
  3. Das Feature muss eine eindeutige ID haben - z.B. "my.example.feature"
  4. In der "buckminster_product.propertiers" im Ordner tooling im Bundle "*.updatesite" brauch man einen neuen Eintrag, der als "key=value"-Pair gesehen werden kann. Entsprechend sollte der Key in der Datei stets unique sein.
    1. Das Pair gibt die Liste (kann auch leer sein) von Features an, die hinzuinstalliert werden sollen. Der Key sei bspw. "product.example.features". Ein Feature-Eintrag entspricht dabei immer der ID des Features mit dem Anhang ".feature.group".
      Hier geben wir also "product.example.features=myexample.feature.feature.group" an.
    2. Optional kann man noch eine Location angeben, die das Zielverzeichnis angibt, wohin das fertige Produkt abgelegt wird. Sonst wird "product.destination" für das gebaute Produkt und "product.zipdestination" für das gepackte als root-Verzeichnis verwendet (später kommt eh noch ein Unterordner hinzu). Man muss dann natürlich eigene Keys definieren.
  5. Dann die buckminster.cspex öffnen. Hier gehören im Wesentlichen immer zwei Einträge (die <public> Einträge) zusammen. Eins baut das Produkt mit Hilfe von Ant und das andere packt es dann in einem ZIP-File. Ob man letzteres brauch, muss man jeweils entscheiden - macht zum herunterladen jedoch Sinn...
  6. Am besten kopiert man sich ein Paar. Dies sollte abhängig von der Produkt-Art sein: Client, Server oder Monolithic - also in Abhängigkeit von Schritt 1!
    1. Für Server kopiert man sich die Einträge "create.server.product" und "create.server.product.zip"
    2. Für Client kopiert man sich die Einträge "create.studio.product" und "create.studio.product.zip"
    3. Für Monolithic kopiert man sich die Einträge "create.serverandstudio.product" und "create.serverandstudio.product.zip"
  7. Im Folgenden nehmen wir Monolithic als Basis an und nehmen daher die beiden Einträge "create.serverandstudio.product" und "create.serverandstudio.product.zip".
  8. Nach dem kopieren nennen wir diese um - z.B. in "create.example.product" und "create.example.product.zip".
  9. Dann muss man das ganze noch anpassen, in dem man die variablen (die ${...} Dinger (wink)) mit den Werten ersetzt, die man zuvor in der buckminster_product.properties gewählt hat.
    1. Dies ist im Wesentlichen die Feature-Liste, wie sie unter Schritt 3a definiert haben. So wird aus <property key="features" value="${product.serverandstudio.features}" /> wird dann <property key="features" value="${product.example.features}" />
    2. Wenn man oben noch eigene Locations definiert hat, muss man hier noch "${product.destination}" und "${product.zipdestination}" ändern - so, wie man den key unter 4b gewählt hat.

    3. In der create.example.product.zip muss nun der Eintrag <attribute name="create.serverandstudio.product" />  in <attribute name="create.example.product" />  geändert werden, damit beim Auslösen von create.example.product.zip automatisch create.example.product vorher gestartet wird.

    4. Des Weiteren sollte der Name des Produkts, wie es nachher auf der Platte liegt, geändert werden, damit es nicht andere überschreibt! Also z.B. in

      <products alias="action.output" base="${product.zipdestination}/example"> 

              <path path="odysseus.example.${target.ws}.${target.os}.${target.arch}.zip" /> 

      </products>
      Das erste gibt dann den Unterordner an, der unter Schritt 4b erwähnt wird.

    5. Nur zum Verständnis: Das "iu" ist die sogenannte "installable unit". Hier verwenden wir das existierende wieder. Bauen wir also ein monolithic-Produkt mit unseren eigenen Features, dann nehmen wir auch hier das Produkt "product.serverandstudio.id". "product.serverandstudio.id" ist wiederum in der buckminster_product.properties definiert und ist das Produkt mit der ID "de.uniol.inf.is.odysseus.product.studio". Das entspricht dann der "Odysseus Product Platform Studio.product" im Bundle "der.uniol.inf.is.odysseus.ci.products" - Dieses Produkt ist so nicht ausführbar und enthält im Wesentlichen nur einen leeren OSGi-Container (also Equinox) + RCP, GEF etc.Hinweis: Dieses Produkt kennt Odysseus nicht und hat auch keine Abhängigkeiten! Dies ist notwendig, damit die hinzuinstallierten Features, die man unter Schritt 1 angibt, nichts mit dem Produkt hier zu tun haben und einfach nur "hinzuinstalliert" werden - dadurch können die hinzuinstallierten Features über den Updatemechanismus konfliktfrei aktualisiert werden.
  10. Das ganze dann commiten.
  11. Dann Jenkins öffnen und am besten einen "neuen Job anlegen" und die Option "Kopiere bestehenden Job" auswählen. Dort "Build Odysseus Server+Studio" (oder entsprechend Server oder Client - je nach Schritt 1) auswählen und "OK" klicken.
  12. Im Step "Run Buckminster" im Feld "Kommandos" ändert man nun die Einträge mit "perform" ab. Der Teil am Ende hinter dem # gibt das Kommando entsprechend aus der buckminster.cspex an, das ausgeführt werden soll. Entsprechend ändert man diese wie folgt ab:
    1. der Eintrag, der auf "#site.p2.publish" endet, kann entfernt werden - dieser sorgt nur dafür, dass die Updatesite aktuell ist - welches jedoch schon von anderen Build-Jobs gemacht wird.
    2. Dann gibt es für jedes Betriebssystem für jeweils 32 und 64bit einen Eintrag, der jeweils auf #create.server.product.zip endet. Diese ändert man am Ende auf den Namen aus Schritt 8 um - also hier auf "create.example.product.zip"
    3. Möchte man nur ein bestimmtes Setting - z.B. Windows mit 64bit, dann kann man die anderen 5 Einträge auch löschen.
  13. Hat man eine andere Ausgabe-Location in der buckminster.cspex bzw. in der buckminster_product.properties gewählt, dann muss man noch ggf. den ersten Schritt im Job "Shell ausführen" anpassen, sodass auch dort die entsprechenden Ordner bereinigt werden.
  14. Das ganze Speichern und den Job ausführen.

Ein ganz neues Produkt bauen lassen

Um ein komplett eigenes Produkt von Jenkins bauen zu lassen, muss folgendes gemacht werden. Achtung: Teile des Produkts sind möglicherweise nicht über den Update-Mechanismus aktualisierbar!

  1. Dem Produkt (also der *.product Datei) eine unique ID geben (z.B. "mein.example.product"), die bisher noch nicht von einem anderen Product verwendet wird (Paketnamen + product hat sich hier bewährt).
  2. In der "buckminster_product.propertiers" unter tooling im Bundle updatesite brauch man zwei neue einträge, die jeweils als "key=value" pair gesehen werden können. Entsprechend sollte der Key unique sein.
    1. Man brauch einen Key, um die Product-ID zu definieren, z.b. "product.example.id". die ID ist dann gleich mit dem aus der *.product-Datei. Das ergibt dann "product.example.id=mein.example.product"
    2. Ein zweiter Key ist eine Liste (kann auch leer sein) von Features, die hinzuinstalliert werden sollen. Der Key sei bspw. "product.example.features". Ein Feature-Eintrag entspricht dabei immer der ID des Features mit dem Anhang ".feature.group".
      Nur die hinzuinstallierten Features sind später aktualisierbar!
    3. Optional kann man noch eine Location - also ein Zielverzeichnis angeben, sonst wird "product.destination" für das gebaute Produkt und "product.zipdestination" für das gepackte verwendet. Man muss dann natürlich eigene Keys definieren.
  3. Dann die buckminster.cspex öffnen. Hier gehören im wesentlichen immer zwei einträge zusammen. Eins baut das Produkt mit Hilfe von ant und das andere packt es dann in einem ZIP-File. Ob man letzteres brauch, muss man jeweils entscheiden.
  4. Am besten man kopiert sich einmal die beiden einträge "create.serverandstudio.product" und "create.serverandstudio.product.zip" und nennt sie um - z.B. in "create.example.product" und "create.example.product.zip". Dann muss man das ganze noch anpassen, in dem man die variablen (die ${...} Dinger (wink)) mit den Werten ersetzt, die man zuvor in der buckminster_product.properties gewählt hat.
    1. also aus <property key="iu" value="${product.serverandstudio.id}" /> wird dann  <property key="iu" value="${product.example.id}" />
    2. und aus <property key="features" value="${product.serverandstudio.features}" /> wird dann <property key="features" value="${product.example.features}" />
    3. Wenn man oben noch eigene locations definiert hat, muss man hier noch "${product.destination}" und "${product.zipdestination}" angeben.

    4. In der create.example.product.zip muss nun der Eintrag <attribute name="create.serverandstudio.product" />  in <attribute name="create.example.product" />  geändert werden, damit beim Auslösen von create.example.product.zip automatisch create.example.product vorher gestartet wird.

    5. Des Weiteren sollte der Name des Produkts, wie es nachher auf der Platte liegt, geändert werden, damit es nicht andere überschreibt! Also z.B. in

      <products alias="action.output" base="${product.zipdestination}/example"> 

              <path path="odysseus.example.${target.ws}.${target.os}.${target.arch}.zip" /> 

      </products>

  5. Das ganze dann commiten.
  6. Dann Jenkins öffnen und am besten einen "neuen Job anlegen" und die Option "Kopiere bestehenden Job" auswählen. Dort "Build Odysseus Server" auswählen und "OK" klicken.
  7. Im Step "Run Buckminster" im Feld "Kommandos" ändert man nun die Einträge mit "perform" ab. Der Teil am Ende hinter dem # gibt das Kommando entsprechend aus der buckminster.cspex an, das ausgeführt werden soll. Entsprechend ändert man diese wie folgt ab:
    1. der Eintrag, der auf "#site.p2.publish" endet, kann entfernt werden - dieser sorgt nur dafür, dass die Updatesite aktuell ist - welches jedoch schon von anderen Build-Jobs gemacht wird.
    2. Dann gibt es für jedes Betriebssystem für jeweils 32 und 64bit einen Eintrag, der jeweils auf #create.server.product.zip endet. Diese ändert man am Ende auf den Namen aus Schritt 4 um - also hier auf "create.example.product.zip"
    3. Möchte man nur ein bestimmtes Setting - z.B. Windows mit 64bit, dann kann man die anderen 5 Einträge auch löschen.
  8. Hat man eine andere Ausgabe-Location in der buckminster.cspex bzw. in der buckminster_product.properties gewählt, dann muss man noch ggf. den ersten Schritt im Job "Shell ausführen" anpassen, sodass auch dort die entsprechenden Ordner bereinigt werden.
  9. Das ganze Speichern.

Interne Funktionsweise

Im Folgenden noch ein paar Informationen zum Aufbau und zur Funktionsweise.

Der grobe Ablauf des Builds ist dann wie folgt:

 

Wird "Fetch and Build Target Platform" manuell ausgeführt, dann wird zunächst

 

Additional Build Processes

In addition to the aforementioned build processes, Jenkins performs the following builds.

Docker Image

This build job takes a Dockerfile and creates a Docker image of the latest stable build. To do so, a custom file is defined in Config File Management that contains all processing steps (see Manage Jenkins -> Managed files -> Custom file). This custom file is copied to the workspace during the build as Dockerfile. The build process starts a Docker build by issuing the following command:

docker build -t odysseus/latest .

After a successful build, the artifact will remain in the workspace. Marco Grawunder can we copy the artifact somewhere to provide it as a download or pull it to dockerhub?