\subsubsection{Verifikation} \label{ssub:verifikation} Wie auch Software müssen auch Provisionierungsskripte getestet werden. Dies gestaltet sich oft als schwierig, weil nicht immer eine Kopie des aktuellen Produktionssystem zur Verfügung steht. Mit steigender Komplexität steigt der Aufwand geschriebene Cookbooks manuell zu testen. Im Folgenden werden verschiedene Möglichkeiten aufgeführt, wie dies automatisiert werden kann. Die erste und einfachste Methode ist der Befehl: \shellcmd{knife cookbook test [COOKBOOKS...]} Dieser überprüft den Rubyquellcode und die Templates des Cookbooks auf Syntaxfehler. Allerdings treten viele Fehler erst zur Laufzeit auf, insbesonderen da Ruby eine dynamische Programmiersprache. Ein anderes Programm ist foodcritic. Dies ist eine statische Codeanalyse ähnlich jslint oder perlcritics. Dabei wird der Rubycode gegen Regelsatz getestet, um so schlechten Stil zu erkennen oder um Codeingstandards innerhalb eines Projekts einzuhalten. Diesen Regelsatz kann man durch eigene Regeln erweitern. \textbf{Chefspec} \label{chefspec} Chefspec baut auf das in Ruby verbreitete Testframework Rspec auf. Dies ist ein Vertreter des BDD (TODO mehr Infos zu BDD, Integration von Chefspec). Wie bereits in Abschnitt ~\ref{durchlauf_eines_recipes} erwähnt, gibt es 2 Phasen bei der Ausführung von Chef. Bei Chefspec wird Provisionierungsprozess nur bis zur Convergingphase, durchlaufen. Die eigenen Tests überprüfen nur die erzeugten Resourcen. Dies hat den Vorteil, das Tests sehr schnell durchlaufen werden, da keine Änderungen an einem System vorgenommen werden müssen. Dies hat Vorteile beim Entwickeln, weil man auf diese Weise schnell Feedback bekommt. Das Zusammenspiel mehrerer Cookbooks lässt sich dadurch gut testen. Außerdem ermöglicht es verschiedene Konfigurationen/Betriebssysteme durchzutesten, ohne das diese (zeit)aufwendig aufgesetzt werden müssen. Da Chefspec allerdings nicht wirklich Code auf dem System ausführt, sind weitere Integrationstest unerlässlich. Der folgende Test wurde aus dem NTP-Cookbook (~\ref{ssub:einrichtung-der-netzwerkdienste}) entnommen. \begin{lstlisting} require_relative '../spec_helper' describe 'ntp::default' do let(:chef_run) do ChefSpec::Runner.new do |node| node.set["ntp"]["subnets"] = ["::1", "127.0.0.1", "172.28.128.0 mask 255.255.255.0 nomodify notrap nopeer"] end.converge(described_recipe) end it "should setup ntp" do chef_run.should install_package("ntp") chef_run.should render_file("/etc/ntp.conf").with_content("172.28.128.0") end end \end{lstlisting} Im \emph{chef\_run}-Block wird der fiktiven Node Attribute zugewiesen und das zu testende Cookbook ausgeführt. Das Ergebnis wird in diesem Beispiel in dem Objekt \emph{chef\_run} gespeichert. Gegen dieses Objekt wird getestet, ob bestimmte Resourcen korrekt initialisiert wurden. In diesem Fall wird überprüft, ob das Packet ntp installiert werden soll und ob das Subnetz in dem Template für Konfigurationsdatei \emph{/etc/ntp.conf} richtig gesetzt wird. Die Tests werden mit dem Befehl \emph{rspec} ausgeführt. Wenn keine weiteren Argumente angegeben sind, führt dieses Programm alle Dateien unterhalb des Ordners \emph{spec} aus, dessen Dateinamen auf \emph{\_spec.rb} enden. Um alle drei obgenannten Testmethoden gleichzeitig ausführen zu lassen, gibt es eine Rakefile (das in Ruby geschriebene Äquivalent zu GNU Make). Mithilfe des Befehls: TODO \textbf{Minitest Handler} \label{minitest_handler} \href{https://github.com/btm/minitest-handler}{Minitest Handler} hingegen wird nach jedem Provisionierungsdurchgang ausgeführt. Im Gegensatz zu Chefspec nutzt es das Minitest Framework, welches schon mit Ruby mitgeliefert wird. Allerdings kann man durch einbinden, der Zeile: \begin{lstlisting} require "minitest/spec" \end{lstlisting} eine Rspec sehr ähnliche Syntax benutzen. Um Minitest Handler zu nutzen, muss das Recipe aus minitest-handler-cookbook als erstes Recipe in der node geladen werden. Minitest Handler durchsucht beim Durchlauf in jedem anderen cookbook, in den Unterordnern in \emph{files/} nach dem Verzeichnis \emph{test} und lädt alle Tests aus diesem Verzeichnis. Über die Beschreibungszeile: \begin{lstlisting} describe_recipe "ntp::default" do # #... end \end{lstlisting} wird angeben für, welches Recipe der Test gedacht ist (In diesem Fall das Defaultrecipe aus dem NTP-Cookbook). Wenn das entsprechende Recipe von der Node ausgeführt wird, wird der dazugehörige Test nach dem Provisionierunsdurchlauf ebenfalls ausgeführt. Minitest Handler erweitert Rspec um nützliche Methoden um den Status des Systems zu überprüfen. Hier ein Beispiel aus dem bind cookbook, welches in Abschnitt~\ref{ssub:einrichtung-der-netzwerkdienste} erwähnt wurde: \begin{lstlisting} describe_recipe 'bind::default' do it "starts the named daemon" do service("bind9").must_be_running end it "should resolve dns" do assert_sh("dig localhost @localhost") end end \end{lstlisting} Die Methode \emph{assert\_sh} überprüft den Exitstatus eines Befehls und schlägt fehl, wenn dieser ungleich Null ist, während die \emph{service}-Methode den Status eines Systemdienst sicherstellt. Es gibt noch weitere Testmethoden, wie das Überprüfen von Verzeichnissen, Inhalte von Dateien oder Mountpoints. Viele Fehler werden in der Regel schon von den Provider erkannt und festgestellt. Mit Minitest Handler kann dies Erweitern um zum Beispiel protokollspezifische Tests durchzuführen. % vim: set spell spelllang=de_de