Alle diese Fragen gab es schon immer im Softwaretest. Man kann sie sowohl organisatorisch als auch technisch beantworten. Der organisatorische Ansatz, zum Beispiel durch definierte Zeitfenster für die Installationen und eine Dokumentation aller Änderungen, ist natürlich zu bevorzugen. In diesem Artikel geht es jedoch um eine technische Antwort.
Automatisierte Überwachung der Installationen
In der „voragilen“ Zeit mit geplanten festen Installationszeitpunkten war es noch relativ einfach. Nach der Installation hatte man diese zu überprüfen. In den Zeiten von Continuous Integration (CI) und Continuous Delivery (CD) merkt der Tester jedoch oft nicht einmal, dass eine neue Version installiert wurde. Und dies hat besonders in größeren Projekten mit unterschiedlichen Teststufen und Testsystemen sowie im Systemintegrationstest eine gewisse Brisanz für die Testplanung und Kostenschätzung. Auch die Validität der Testaussage und die Qualität der Fehlermeldungen können negativ beeinflusst werden, wenn es Unsicherheiten hinsichtlich Installation und Konfiguration gibt.
Um diese Unsicherheiten in „Echtzeit“ auszuräumen, eine Installation oder Konfigurationsänderung sicher zu bemerken und sich entsprechend darauf einstellen zu können, ist eine automatisierte Überwachung der Installationen unabdingbar. Leider ist es aber aufgrund von Firmenrichtlinien oft nicht möglich, eine eigene spezialisierte Lösung zu installieren, oder auch aus Kostengründen nicht wirtschaftlich.
Was spricht aber dagegen, sich die ohnehin oft schon vorhandenen Instrumente und Methoden der Kollegen aus der Entwicklung und dem Bereich DevOps zunutze zu machen? Ich möchte dies hier exemplarisch mit den Anwendungen Git, Jenkins und Ansible zeigen. Dabei gehe ich nur soweit technisch ins Detail, als es für das Verständnis des Workflows notwendig ist. Alles andere würde den Umfang dieses Artikels bei Weitem überschreiten.
„Git“ ist eine freie Software zur verteilten Versionsverwaltung. Diese wird für die Verwaltung der Testskripte verwendet. Der „Jenkins“ ist ein im CI-Umfeld oft verwendetes Build-Tool, kann aber prinzipiell zur Ansteuerung der unterschiedlichsten Tasks in der Softwareentwicklung und im Test verwendet werden. Aufgrund der guten Integration von „Git“ in „Jenkins“ werden beide oft zusammen verwendet. „Ansible“ ist ein freies Automatisierungswerkzeug für die Konfiguration und Automatisierung von Abläufen auf einem Computer.
Ansible zeichnet sich besonders dadurch aus, dass es „agentless“ arbeitet. Das heißt, auf dem Zielsystem muss im einfachsten Fall lediglich ein SSH-Server vorhanden sein. Möchte man alle Funktionen nutzen, ist jedoch eine neuere Python-Installation (2.x) zwingend. Diese Voraussetzungen bringen aber fast alle modernen Linux-Server mit.
Der Aufbau des Testsystems
Es gibt verschiedene Möglichkeiten, ein Testsystem für eine Automatisierungslösung auf Basis von Git, Jenkins und Ansible zu erstellen. Ich habe mich für eine Variante entschieden, die jeder nachbauen kann (siehe Abbildung 1). Grundlage ist ein Notebook mit Windows 10. Als Virtualisierungssoftware kommt VirtualBox von Oracle zum Einsatz. Als Host-VM für Jenkins und Ansible verwende ich ein weit verbreitetes aktuelles Linux, Fedora 28, eng verwandt mit Red Hat Enterprise Linux. Dazu kommen noch zwei „Anwendungsserver-VMs“, ebenfalls mit Fedora-Linux 28 als Betriebssystem. Die CI/ CD-Server der Lieferanten sind aus QA-Sicht völlig austauschbar und werden darum nicht näher beschrieben.
Abb. 1: Schematische Darstellung des Testsystems
Installation und Konfiguration des Testsystems
Oracle VirtualBox wurde ohne Änderungen mit den Vorgabeeinstellungen installiert. Die drei Linux-VMs haben zusätzliche virtuelle Netzwerkadapter erhalten, damit sie untereinander und mit dem Host ein eigenes Subnet bilden können.
Die VMs im Einzelnen:
- QA-Ansible-Master-01.Local als Host-VM für Jenkins und Ansible,
- QA-AUT-01.Local als erste Server-VM für die „Anwendung unter Test“ (AUT),
- Qa-AUT-02.local als zweite Server-VM für die AUT.
Als Repository für die Testskripte kommt Git-Hub zum Einsatz. Prinzipiell kann aber auch jedes andere Backend für Git verwendet werden.
Da der mit Fedora Linux 28 gelieferte Jenkins nicht ohne Nacharbeit funktionierte, bin ich auf den aktuellen Jenkins, Version 2.121.3, für die Server-Varianten von Red Hat Enterprise Linux ausgewichen. Diesen bindet man in Fedora-Linux wie in Listing 1 gezeigt ein.
Nach der Installation des Jenkins sind gegebenenfalls noch Firewall-Einstellungen anzupassen, wenn man auf das Webinterface des Jenkins zugreifen möchte. Danach kann man den Jenkins wie gewohnt verwenden. Zur Installation und Konfiguration der Ansible-Plug-ins für den Jenkins später mehr.
Listing 1: Einbindung des Jenkins in Fedora-Linux
Auf dem QA-Ansible-Master-01 wurde das mit Fedora 28 gelieferte Ansible ohne Änderungen mittels yum installiert (siehe Listing 2).
Listing 2: Ansible-Version
Um unter anderem lesenden Zugriff auf das Dateisystem der „Testserver“ (AUT) zu erhalten, ist auf jeder der drei Linux-VMs ein „Technical User“ hilfreich. Der „Technical User“ des QA-Ansible-Master-01 soll sich via SSH und Ansible sicher auf den „Testservern“ anmelden und mit den Identitäten der dortigen „Technical User“ arbeiten. Für dieses kleine System aus drei VMs ist diese Konfiguration ausreichend. Andere Systeme benötigen eine erweiterte Benutzerverwaltung. Wurden die drei Benutzer (technicaluser@ qa-ansible--master-01.local; technicaluser@ qa-aut-01.local; technicaluser@qa-aut-02. local) erzeugt, kann man für den technicaluser@qa-ansible-master-01.local mittels ssh-keygen ein Paar Keys zur passwortlosen Anmeldung via SSH und Ansible auf den Testserver-VMs erzeugen. Dabei wird der Vorgabepfad übernommen und kein zusätzliches Passwort vergeben.
Der technicaluser@qa-ansible-master-01 meldet sich am System an und erzeugt das Schlüsselpaar. Anschließend konfiguriert er die passwortlose Anmeldung mittels ssh-copy-id. Listing 3 zeigt dies als Beispiel für den ersten „Testserver“.
Listing 3: Die SSH-Keys des „Technical User“ werden auf die Testserver kopiert
An dieser Stelle können wir davon ausgehen, dass die SSH-Authentifizierung mittels Schlüsselpaar für den technicaluser@qa-ansible-master-01.local auf beiden Testservern funktioniert und sich die Ansible-Plug-ins für den Jenkins installieren und konfigurieren lassen.
In der Plug-in-Verwaltung des Jenkins suchen wir das Ansible-Plug-in in Version 1.0. und installieren es. Anschließend wird es wie im in Abbildung 2 dargestellten Screenshot konfiguriert. Da die mit yum installierte Standardversion von Ansible verwendet wird, muss kein besonderer Pfad angeben werden.
Abb. 2: Die Konfiguration des Ansible-Plug-ins ist einfach
Alle Jobs des Jenkins-Service und alle von diesen erzeugten Dateien laufen mit den Rechten des Accounts „jenkins“. Ohne die generelle Änderung dieser Einstellung ist es nicht möglich, zum Beispiel einen Job mit den Rechten des „technicaluser“ auszuführen. Zum Glück bietet aber das Ansible-Plug-in 1.0 die Möglichkeit, trotzdem mit dem Account des „technicaluser“ zu arbeiten, indem man den Inhalt der Datei /home/technicaluser/.ssh/id_rsa wie in dem in Abbildung 3 dargestellten Screenshot in das dafür vorgesehene Formular (/credentials/store/system/domain/_/) einfügt. In der Buildkonfiguration eines Jobs, im Drop-Down-Feld „Credentials“, wählt man dann einfach „technicaluser“ aus.
Abb. 3: Die Ansible-Jobs arbeiten mit den Rechten eines „technicaluser“
Die Verwendung von Ansible mit dem Jenkins-Ansible-Plug-in
Jetzt möchte ich die beiden wichtigsten Arten von Ansible-Jobs, die das Jenkins-Ansible-Plug-in zur Verfügung stellt, beschreiben. Es handelt sich um die Jobtypen „Ansible Ad-Hoc Command“ und „Ansible Playbook“.
Mithilfe des „Ansible Ad-Hoc Command“-Jobs können ohne die Verwendung von „Ansible-Playbooks“ auf den entfernten Computern Programme und Skriptdateien parallel ausgeführt werden. Das spart Schreibaufwand für die Erstellung eigener Playbooks und ermöglicht so, zum Beispiel auch bereits vorhandene Shell-Skripte zum Schnittstellentest, zum Parsen von Logund Konfigurationsdateien oder zum Check von Diensten einfach weiterzuverwenden. Um das Deployment eventuell vorhandener Skripte auf die Testserver kümmert sich der Job selbst aber nicht.
Der Dialog zur Einrichtung eines „Ansible Ad-Hoc Command“ (siehe Abbildung 4) ist übersichtlich.
Abb. 4: Mit dem „Ansible Ad-Hoc Command“ können einzelne Befehle oder z. B. auch Shell-Skripte gestartet werden
Zuerst wird die Ansible-Installation angegeben. Da es in diesem Szenario nur eine Installation gibt, können wir die Vorgaben für das Textfeld „Ansible installation“ akzeptieren. Im Textfeld „Host pattern“ wird der Name der Gruppe von Zielrechnern, „AUT-Servers“, eingetragen, auf denen das „Ad-Hoc Command“ ausgeführt werden soll. Diese Gruppe von Zielrechnern wird in der Datei /etc/ansible/hosts definiert und umfasst im Beispiel die beiden Test-VMs QA-Ansible-01.local und QA-Ansible-02. local.
Die Einstellungen unter Inventory können einfach übernommen werden. Als Ansible-Modul wird hier „raw“ angegeben. Dieses Modul hat eine Sonderstellung unter den Ansible-Modulen. Man kann zum Beispiel versuchen, es dann zu verwenden, wenn auf den Zielrechnern kein Python installiert ist. Wichtig ist, dass der Job die Identität des „technicaluser“ verwendet. Diese Identität muss ausgewählt werden.
Wurde der Job ausgeführt, sieht der wesentliche Output wie in Listing 4 aus. Man sieht, dass die Kommandos auf beiden Test-VMs praktisch parallel ausgeführt wurden. Die zurückgelieferten Informationen werden als Block dargestellt. Mehr dazu später.
Listing 4: Output Ansible „Ad-Hoc Command“-Job
Der „Ansible-Playbook-Job“ verwendet als Input ein „Playbook“, das heißt eine als YAML formatierte Datei mit Befehlen und Parametern. In die Syntax muss man sich einarbeiten. Dokumentation und Beispiele findet man unter anderem auf der Website von Ansible. Der größte Vorteil der Verwendung des Playbook-Jobs ist, dass sich der Job beziehungsweise Ansible darum kümmert, wie „das Playbook“ auf die Zielrechner gelangt, und dass nach der Anwendung keine Dateien auf dem Zielrechner verbleiben.
Listing 5 zeigt nun ein Beispiel für ein Playbook. Der Inhalt des Playbooks ist relativ selbsterklärend. Interessant ist in diesem Zusammenhang, dass der von einem Befehl auf der Konsole ausgegebene Text bei Verwendung von Playbooks unterdrückt wird. Mithilfe der Debug-Statements wird der Text dann aber doch sichtbar.
Listing 5: Beispiel für ein Playbook
Die zurückgelieferten Informationen werden befehlsweise sortiert und nicht als ein Block pro Test-VM. Man beachte den Unterschied zur Verwendung des „Ad-Hoc Command“-Jobs. Listing 6 zeigt ein Beispiel. Der Dialog zum Einrichten eines Playbook-Jobs ist ebenfalls fast selbsterklärend (siehe Abbildung 5). Vor jedem Run des Jobs wird durch die Verwendung von Git eine aktuelle Version der „getInfo_playbook_debug.yml“ in das Arbeitsverzeichnis des Jenkins-Jobs kopiert. Aus diesem Grund muss nicht der volle Pfad angegeben werden.
Listing 6: Output „Ansible Playbook“-Job
Abb. 5: Die Konfiguration eines „Ansible Playbook“-Jobs ist ähnlich simpel wie die des „Ad-Hoc Command“
Fazit
Die Kombination aus Git, Jenkins und Ansible ist vielfältig im Test einsetzbar. Zur Überwachung von Installationen und Services, zum Parsen von Log- und Konfigurationsdateien bis hin zum Test von Schnittstellen.
Die Unsicherheiten bezüglich des Zustandes einer aktuellen Installation können zeitnah ausgeräumt werden. Testmanagement und Tester haben Planungssicherheit. Die Qualität der Fehlermeldungen erhöht sich, da Fehler, die auf falsche Konfiguration zurückzuführen sind, schneller erkannt werden. Bei Verwendung eines Git-Servers mit Webschnittstelle, wie GitHub, ist es möglich, die Tests überwiegend remote zu entwickeln und auszuführen. Alles, was man benötigt, ist ein moderner Webbrowser. Eine zusätzliche Möglichkeit der Zeit- und Kosteneinsparung kann natürlich auch darin bestehen, die Administration und Konfiguration der Testserver in die Verantwortung der QA zu übergeben. Der Effekt des Wissensaufbaus im QA-Team und die damit einhergehenden Synergieeffekte sind nicht zu unterschätzen. Organisatorisch ist dies zum Beispiel im Rahmen von Testservices möglich, die eine Umgebungsbetreuung der verwendeten Testtechnik mit einschließen.