138 lines
6.4 KiB
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
|