ltcp/bericht/chef/chef-tests.tex

138 lines
6.4 KiB
TeX

\subsubsection{Verifikation}
\label{ssub:verifikation}
Wie auch Software müssen auch Provisionierungsskripte getestet werden. Dies
gestaltet sich oft als schwierig, weil nicht immer eine exakte 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 \href{http://www.jslint.com/}{JSlint}
oder \href{http://perl-critic.stacka.to/}{Perl::Critic}. Dabei wird der
Rubycode gegen einen Regelsatz getestet, um so schlechten Stil zu erkennen oder
um Codingstandards innerhalb eines Projekts einzuhalten. Dieser Regelsatz kann
durch eigene Regeln erweitern werden.
\textbf{Chefspec}
\label{chefspec}
Chefspec baut auf das in Ruby verbreitete Testframework
\href{http://rspec.info/}{RSpec} auf. Rspec ist ein Testframework, welches auf
\href{http://dannorth.net/2012/05/31/bdd-is-like-tdd-if/}{Behavior Driven
Development} (kurz BDD) basiert. Hierbei werden die Testcases in derartiger Form
auf geschrieben, dass sie sich selbst dokumentieren. RSpec kann aus den
Beschreibungen Sätze bilden und so im Falle eines fehlgeschlagen Tests schnell
darüber Auskunft zu geben, was der Test getestet hat und aus welchen Grund
dieser fehlgeschlagen ist. Chefspec erweitert dabei RSpec um die Möglichkeit
Cookbooks zu laden und stellt spezielle Matcher (RSpec-Terminologie für
Assertions) bereit, um diese zu testen. Wie bereits in
Abschnitt~\ref{ablauf_einer_provisionierung} 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
Resources. 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 zu
keinen Zeitpunkt Code auf dem System ausführt, sind weitere Integrationstest
unerlässlich.
Der folgende Test wurde aus dem selbst geschriebenen NTP-Cookbook
(\ref{ssub:einrichtung-der-netzwerkdienste}) entnommen.
\begin{lstlisting}[language=Ruby]
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, wurde
ein Rakefile geschrieben. \href{http://rake.rubyforge.org/}{Rake} ist das in Ruby
geschriebene Äquivalent zu Make, welches ein verbreitetes Buildprogramm auf
UNIX-Basierten Plattformen ist. Die Ausführung der Tests geschieht mit dem Befehl:
\shellcmd{rake test}
Dieser muss innerhalb Projektverzeichnis aufgerufen werden.
\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}[language=Ruby]
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 Bindcookbook,
welches in Abschnitt~\ref{ssub:einrichtung-der-netzwerkdienste} erwähnt wurde:
\begin{lstlisting}[language=Ruby]
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