Eine Runde mit dem Paternoster gefällig?

Wie ihr im aktuellen Blogpost der Uberspace-7-Reihe lesen könnt, ändert sich im Bereich unserer Shellscripts gerade eine ganze Menge. Aus Config-Dateien werden Ansible-Facts, aus Bash werden Playbooks oder Python-Skripte. Um all diese Teile wieder unter einen Hut zu bekommen, müssten wir einen Ausflug in die Softwareentwicklung machen.

Viele unserer Features - wie das allseits beliebte uberspace-add-domain - erfordern, dass wir euch mehr Rechte einräumen, als ihr eigentlich haben dürft. Auf diesem Weg könnt ihr beispielsweise mit uberspace-add-domain auf die Konfiguration unseres Webservers oder mit uberspace-add-port auf das iptables-Ruleset in engen Grenzen und indirekt, aber dennoch schreibend, zugreifen.

Unser derzeitiges Setup deckt diese Aufgaben mittels sorgfältig entwickelten und durch mehrere Personen revieweten Shellscripts ab. Diese kümmern sich jeweils selbständig um die notwendige Vorarbeit wie das Auslesen der Parameter mit getopt(1) sowie das Überprüfen derer Werte mittels Regulären Ausdrücken und diversen Helper-Funktionen. Zu guter Letzt wird natürlich die eigentliche Aufgabe, wie zum Beispiel das Anpassen einer Apache-vhost-Config, erledigt. Die erstgenannten Schritte ähneln sich in den verschiedenen Scripten sehr und sind nicht sonderlich komplex. Dennoch kommen bei uberspace-add-domain alleine für die initiale Parameterverarbeitung rund 100 Zeilen Bash zusammen.

Paternoster

In Zukunft wird eine von uns entwickelte Python-Library namens Paternoster diese Aufgaben übernehmen. Im Rahmen von Uberspace 7 - wo Dienste wie Webserver oder Firewall mittels Ansible konfiguriert werden - benötigten wir für unsere Scripts ein Framework, das damit kompatibel ist. Da Ansible eine Python-API anbietet, konnten wir mit diesen beiden Komponenten schnell Ergebnisse erzielen.

Zur Demonstration wollen wir euch hier eine verkürzte Version des neuen uberspace-add-domain zeigen:

#!/bin/env python2.7

import paternoster  
import paternoster.types

paternoster.Paternoster(  
  runner_parameters={'playbook': '/opt/playbooks/uberspace-add-domain.yml'},
  parameters=[
    ('domain', 'd', {
      'help': 'this is the domain to add to your uberspace',
      'type': paternoster.types.domain,
    }),
  ],
  success_msg='Your domain has been added successfully.',
).auto(become_root=True)

Wenn man von den beiden import-Statements absieht, ist hier von den erwähnten 100 Bash-Zeilen kaum noch Python-Code übrig geblieben. Ein Großteil der Datei besteht aus der Parameter-Definition, die - wie bereits erwähnt - innerhalb der Library zu einer argparse-Konfiguration umgemünzt wird. Unterstützt wird diese durch eigene Typen (z.B. paternoster.types.domain), um auch kompliziertere Werte als nur "Eingabe ist eine Zahl" prüfen zu können. So ist es zum Beispiel möglich die Länge oder den Zeichensatz eines Strings mit paternoster.types.restricted_str zu beschränken. Sobald die Werte eingelesen und überprüft wurden, werden sie über die Ansible-API an ein Playbook weitergegeben. Wie genau das funktioniert, könnt ihr allerdings selbst nachlesen, denn...

OpenSource

... der Paternoster ist Open Source!

Bei der Umsetzung haben wir darauf geachtet, den Code sowie den Funktionsumfang so allgemein wie sinnvoll möglich zu halten. So soll die Library auch für andere Projekte, Firmen oder Spielereien von Nutzen sein. Wenn unter diesem Gesichtspunkt etwas fehlt oder euch zu uberspace-spezifisch vorkommt, lasst es uns bitte in einem GitHub-Issue wissen. Wahrscheinlich kommen wir dann gemeinsam auf einen grünen Zweig.

Abgesehen davon, seid ihr alle herzlichst dazu eingeladen einen Blick auf das zukünftige Fundament aller Uberspace-Scripte zu werfen. Wir freuen uns sehr über eure Anregungen, Bugreports oder vielleicht sogar Pullrequests zum Code. Wenn ihr dafür nicht GitHub verwendet wollt, könnt ihr eure Patches oder Bugreports natürlich auch wie gewohnt per Mail an hallo@uberspace.de schicken.

Security

Dass wir als Namensgeber ein nicht gerade als sicher bekanntes Beförderungsmittel gewählt haben, kommt nicht von Ungefähr. Uns ist bewusst, dass diese Library an einem neuralgischen Punkt in unserem Setup sitzt. Jedes unserer bisherigen Shellscripts wurde selbstverständlich von mehreren Mitarbeitern auf seine Tauglichkeit und Sicherheit überprüft. Beim Paternoster wollen wir dieses Vorgehen natürlich fortführen, aber auch durch die Veröffentlichung des Sourcecodes, sowie einer unabhängigen Überprüfung verstärken.

Die Zukunft

Neue Helferlein auf Uberspace 6 werden, sofern möglich, unter dem hier präsentierten Schema entwickelt. Das Austauschen der alten Bash-Scripts unter Uberspace 6 ist auch geplant, kann aber eine Weile dauern, da wir dort bei den User-Konfigurationen nicht vollständig auf Ansible setzen.

Die Shelltools, welche in Rahmen von Uberspace 7 entwickelt werden, basieren von Anfang an auf unserem Paternoster. Das bedeutet, dass hier keine Umstellung notwendig ist und wir somit gleich mit Vollgas starten können.


Die Zeichnung des Paternosters stammt aus den Wiki-Commons und ist Public Domain.