Konfigurationsmanagement auf SwitchesCumulus und der Salt Minion

Wir lieben Debian Linux. Und wir lieben Configuration Management mit Salt. Eigentlich alles gut, sollte man meinen - den Salt Minion auf unseren mit Cumulus Linux als Betriebssystem ausgestatteten Bare Metal Switches zu installieren, kam allerdings einer echten Detektivaufgabe gleich. Doch der Reihe nach.

Früher, ja, früher. Da hatte man noch seinen Switch von Cisco oder Juniper oder einem anderen Hersteller – die Frage nach dem darauf installierten Betriebssystem stellte sich gar nicht, Stichwort Vendor-Lock-In. Heute ist das - glücklicherweise - anders: So genannte Bare Metal Switches erlauben uns, die reine, qualitativ gleichwertige, neutrale Hardware selbst mit einem geeigneten Betriebssystem zu bestücken und zu konfigurieren.

Switch = Server

Eine der bekanntesten Linux-Distributionen für den Einsatz auf Bare Metal Switches ist Cumulus Linux, welches auf Debian basiert. Da wir im Server-Bereich hauptsächlich mit Debian arbeiten, liegt der Einsatz von Cumulus Linux als Switch-Betriebssystem für uns quasi auf der Hand.

Damit können wir unsere Switches genauso administrieren wie wir auch unsere Server administrieren. Tatsächlich ist ein Switch dank Cumulus Linux für uns nichts anderes als ein "Server" mit vielen Netzwerk-Interfaces. Allerdings findet das Switching in Hardware (ASIC) statt, wodurch unsere Bare Metal Switches mindestens ebenso performant sind wie Switches klassischer Hersteller.

Faulheit siegt

Und weil man selten nur eine Handvoll Switches zu konfigurieren hat und wir, wie alle IT-Profis, faul sind und daher alles Denkbare automatisieren möchten, setzen wir natürlich auch bezüglich Netzwerk-Infrastruktur auf unser geschätztes Konfigurationsmanagement-System Salt.

Wie bereits erwähnt, basiert Cumulus Linux auf Debian, genauer dem derzeitigen Oldstable Wheezy. Das Installieren von weiteren Paketen, auch über Dritt-Repositorys, sollte daher eigentlich kein Problem darstellen. Auch auf den Webseiten und Dokumenten von Cumulus wird Salt als eines der möglichen Konfigurationsmanagement-Systeme geführt, wobei Cumulus in Punkto Automatisierung wohl eher auf Ansible setzt.

Zwei CPU-Architekturen

Entscheidet man sich hingegen für Salt, wird man auf zwei Problemfelder stoßen. Das erste hat mit den beiden von uns eingesetzten CPU-Architekturen zu tun. Das zweite - und hier musste ich bis auf Quellcode-Ebene nach einer Lösung graben - mit den Python-Paketmodulen von Salt.

Auf unseren Bare Metal Switches verwenden wir AMD64 und PowerPC als CPU-Architekturen. Bei AMD64 lief alles erwartungsgemäß: Pakete installiert, das Salt-spezifische Paket-Repository angebunden, in der Paketverwaltung den Salt-Minion (Versionsnummer 2015.5.3) ausgewählt und installiert - lief wie am Schnürchen.

Ausnahme libzmq3

Nicht so bei PowerPC: Salt und zusätzlich benötigte Python Module sind architektur-unabhängig und können entsprechend auch auf PowerPC installiert und eingesetzt werden. Die Ausnahme bildet das ZeroMQ-Messaging-Framework libzmq3, welches Salt zur Kommunikation verwendet. Diese kompilierte C-Library muss mit installiert werden, damit der Salt Minion funktioniert. Das Salt-Repository bietet sie aber nicht für PowerPC an.

libzmq3 gibt es aber in einem anderen Repository, und zwar in den Wheezy Backports. Wenn man dieses in die Paketverwaltung einbindet, sollte libzmq3 zur Verfügung stehen. Die Lösung? Jein.

Saltstack Repo nicht nutzbar

Die Salt-Pakete aus dem Saltstack-eigenen Repository können installiert werden, weil sie dank Python-Code architektur-unabhängig sind; die architektur-abhängigen Pakete für PowerPC können aus den Wheezy Backports bedient werden.

Beim Versuch den Salt Minion zur Installation auszuwählen, zeigt sich, dass das Wheezy-Backports-Repository nur ältere Versionen zur Verfügung stellt (0.18). Das Saltstack-eigene Repository kann hingegen nicht genutzt werden, da es keinerlei Pakete für PowerPC bereithält:

http://debian.saltstack.com/debian/dists/wheezy-saltstack/Release

 0240f5f0a2cb6b177671304ffff9cf59 21238 main/binary-i386/Packages
 d417b04bf0648192c616d34ff7cf7c63 5027 main/binary-i386/Packages.gz
 5e55a9eafa39c3bd3eb9aeeea84fcf7d 145 main/binary-i386/Release
 f73621e46c1a72f8b5f473c11e068aa1 21248 main/binary-amd64/Packages
 741bd25688aa898d3fb3a2f5c031239b 5021 main/binary-amd64/Packages.gz
 a292412b342085353d25082a8c15ffdb 146 main/binary-amd64/Release
 ce0dd3da9c7fd3f17e23b34fe739918a 15609 main/binary-i686/Packages
 79f8a39310194aaad46fc8b6ccf4ab06 3739 main/binary-i686/Packages.gz
 5d04a4d1b5f5a702db3cad04539d607e 145 main/binary-i686/Release
 3c505c425043bb091866f010c1659c89 21260 main/binary-armhf/Packages
 2885d061390e982df4594777451a89e4 5034 main/binary-armhf/Packages.gz
 66a8b8ff451f98dbc4e704f2833cf129 146 main/binary-armhf/Release
 ce0dd3da9c7fd3f17e23b34fe739918a 15609 main/binary-mips/Packages
 79f8a39310194aaad46fc8b6ccf4ab06 3739 main/binary-mips/Packages.gz
 29fa1d124d1f9e1eac42664d65aeafec 145 main/binary-mips/Release
 c37c1f9bfc7356bc080464a998a65c1d 20948 main/binary-armel/Packages
 6c5333158b4d4cdcf36e2f11541f2719 5200 main/binary-armel/Packages.gz
 8a1f309ad7070859f6b66adf2706a085 146 main/binary-armel/Release
 3b402db5eb4865fb721664e4df274cc6 6744 main/source/Sources
 b42833c6d8f9a544e8b64fcb6e2a1d80 2362 main/source/Sources.gz
 8c304f10f5dfbc5f2b0734fe8d1f6983 147 main/source/Release.

Der einfache Weg wäre nun, die Salt-Pakete selbst herunterzuladen und manuell auf jedem Switch zu installieren, was natürlich suboptimal ist, weil es nach jedem Update wiederholt werden müsste - und wir sind schließlich faul (s.o.).

Der saubere Weg hingegen führt über ein eigenes Repository. Im Idealfall betreibt man ohnehin schon eines, weil man, wie wir, bereits eigene Software und Pakete bereitstellt (an Software benutzen wir hier übrigens Reprepro). In unserem Fall genügte es, die PowerPC-Architektur unserem Repository hinzuzufügen:

/srv/apt-repository/rep-debian-wheezy/conf/distributions
Origin: aiticon
Label: aiticon
Suite: stable
Codename: wheezy
Description: aiticon Repository for squeeze
Architectures: i386 amd64 powerpc source
Components: main contrib non-free
Log: /srv/apt-repository/rep-debian-wheezy/logs/reprepro.log
SignWith: B3C7B376

Die Salt-Pakete lassen wir über einen eigenen Build-Job in Atlassian Bamboo automatisch bauen und anschließend in unser eigenes Repository importieren.

Kurz gesagt: Wir binden zugleich das Wheezy-Backports-Repository und unser eigenes Repository ein, in dem die Salt-Pakete hinterlegt sind (und damit auch die Paket-Informationen für PowerPC, denn die fehlen ja im Saltstack-eigenen Repository) - und schon können die Pakete in der Paket-Verwaltung ausgewählt und die Abhängigkeiten erfolgreich aufgelöst und installiert werden.
Salt war also installiert, die Testfunktion

 (salt 'our-switch*' test.ping) 
erfolgreich ausgeführt. Als wir dann jedoch die ersten States mittels state.highstate auf den Switch anwenden wollten, war plötzlich Schluss. Unsere States schlugen fehl, weil die Ausführung von Paket-Installationen in unseren States auf einen Fehler lief.
our-switch0:
    The minion function caused an exception: Traceback (most recent call last):
      File "/usr/lib/python2.7/dist-packages/salt/minion.py", line 1161, in _thread_return
        return_data = func(*args, **kwargs)
      File "/usr/lib/python2.7/dist-packages/salt/modules/state.py", line 523, in highstate
        whitelist=kwargs.get('whitelist')
      File "/usr/lib/python2.7/dist-packages/salt/state.py", line 2968, in call_highstate
        return self.state.call_high(high)
      File "/usr/lib/python2.7/dist-packages/salt/state.py", line 2067, in call_high
        ret = dict(list(disabled.items()) + list(self.call_chunks(chunks).items()))
      File "/usr/lib/python2.7/dist-packages/salt/state.py", line 1623, in call_chunks
        running = self.call_chunk(low, running, chunks)
      File "/usr/lib/python2.7/dist-packages/salt/state.py", line 1769, in call_chunk
        self._mod_init(low)
      File "/usr/lib/python2.7/dist-packages/salt/state.py", line 612, in _mod_init
        self.states['{0}.{1}'.format(low['state'], low['fun'])]  # pylint: disable=W0106
      File "/usr/lib/python2.7/dist-packages/salt/utils/lazy.py", line 90, in __getitem__
        raise KeyError(key)
    KeyError: 'pkg.installed'

Kurioserweise bestand dieses Problem aber nicht nur auf den PowerPC-, sondern auch auf den AMD64-Switches - nahe lag also die Vermutung, dass es diesmal nicht an der CPU-Architektur lag. Da sich das Problem aber auf die Switches beschränkte - auf unseren Servern lief weiterhin alles einwandfrei - musste es mit Cumulus zusammenhängen.

Es folgten zähe Stunden der Log- und Quellcode-Analyse - die schließlich des Rätsels Lösung ergaben. Die entscheidende Stelle im Code ist diese hier:

https://github.com/saltstack/salt/blob/2015.5/salt/modules/aptpkg.py#L85

def __virtual__():
'''
Confirm this module is on a Debian based system
'''
if __grains__.get('os_family', False) == 'Kali':
return __virtualname__
elif __grains__.get('os_family', False) == 'Debian':
return __virtualname__
return False

Das pkg-Module für apt steht nur dann zur Verfügung, wenn auf dem System mittels des Grain os_family  entweder Kali oder Debian erkannt wurde. Leider identifiziert sich die Debian-Distribution Cumulus nicht als Debian, sondern als Cumulus.

salt 'our-switch*' grains.item os_family
our-switch0:
    ----------
    os_family:
        Cumulus

Was also tun? Wir überschreiben das Grain OS_family mit Hilfe einer zusätzlichen Konfigurationsdatei (/etc/salt/grains).

os_family: Debian

Wir stoppen den Salt-Minion, leeren vorsichtshalber den Cache (/var/cache/salt/minion) und starten den Salt Minion wieder. Das Grain stimmt jetzt:

salt 'our-switch' grains.item os_family
our-switch:
    ----------
    os_family:
        Debian

Und endlich laufen unsere States und Formulas auch auf unseren Switches mit Cumulus Linux. Voilà.

Configuration Management von Bare-Metal-Switches mittels Salt ist also kein Hexenwerk. Hat man die beiden beschriebenen Fallstricke unserer Anleitung folgend gelöst, übernimmt das Configuration Management die weitere Arbeit: das Anlegen weiterer administrativer Benutzer, das Optimieren der Kerneleinstellungen oder die Installation und Konfiguration zusätzlicher Services wie z.B. BIRD (Internet Routing Daemon für BGP). Hier spielt die Kombination aus Salt und Cumulus Linux ihre Stärken aus. Der alten Cisco-IOS-Shell weint spätestens jetzt niemand mehr eine Träne nach.

Diese Geschichte bestätigt uns zudem einmal mehr in unserer Überzeugung von Open Source: Im Falle des Falls ist man auch selbst in der Lage zu analysieren und Lösungen zu finden und die Erkenntnis mit der Gemeinschaft zu teilen - was hiermit geschehen ist.

Sie sind interessiert? Bitte melden Sie sich!

Tweet

@aiticon

Besuchen Sie uns

Frankfurt