Das freie Monitoring Tool Nagios kann so konfiguriert werden, dass Hosts im Netzwerk Abhängigkeiten hat, über die sie angeschlossen sind. So kann man festlegen, dass der Server server01 z.B. am Switch switch02 angeschlossen ist, der wiederum am Router router03 hängt. Bei solchen Abhängigkeiten spricht man von Children (fälschlicherweise im deutschen auch Childs genannt) und Parents. Das genannte Beispiel hätte dann die folgenden Abhängigkeiten:
--> --> ...ist Child von... ..ist Child von.. +------------------+----------------+ | | | server01 switch02 router03
Beziehungsweise umgedreht:
--> --> ..ist Parent von.. ..ist Parent von.. +------------------+----------------+ | | | router03 switch02 server01
Diese Abhängigkeiten, sofern man sie brav pflegt, lassen sich sehr gut dazu verwenden, um Probleme im Netzwerk festzustellen. Fällt switch02 aus, und es ist keine Abhängigkeit zu server01 konfiguriert, muss man sich ggf. die Informationen erst zusammen suchen, dass diese beiden Systeme in direkter Verbindung zu einander stehen. Wertvolle Zeit geht verloren.
Nun bietet Nagios schon selbst die Möglichkeit, Systeme auf einer automatisch generierten Karte darzustellen. Diese, finde ich, ist aber sehr unübersichtlich und lässt sich nicht filtern, z.B. nur Systeme anzeigen, die ein Problem haben. Wer nicht nur eine Hand voll Systeme im Monitoring hat, weiss wovon ich spreche. Per default bietet Nagios auch keine Möglichkeit, die Ergbenisse des Monitoring anderen Prozessen sinnvoll verfügbar zu machen.
Außer man konfiguriert sich MK Livestatus als Broker Modul. Damit lassen sich so ziemlich alle Informationen aus Nagios herausholen. Auf die Installation und Konfiguration möchte ich nicht weiter eingehen. Vielmehr möchte ich aber zeigen, wie man sich mit diesem nützlichen Modul seine eigene Nettzwerkkkarte baut.
Dazu habe ich ein Bash-Script geschrieben, welches alle Hosts die ein Problem haben (egal ob Host oder Service Probleme) auf einer Karte mit Abhängigkeiten darstellt.
#!/bin/bash unixcat_bin='/pfad/zum/mk/livestatus/bin/unixcat' unixcat_socket='/pfad/zum/mk/livestatus/var/rw/livestatus.sock' dot_file='/pfad/fuer/ausgabe/der/network_problem_map.dot' png_file='/pfad/fuer/ausgabe/der/network_problem_map.png' host_state_file='/pfad/fuer/ausgabe/der/network_problem_map.states' network_base="Internet" > ${host_state_file} function QueryOwnStateAndHostParent() { child=${1} state_parent=$(cat <<-EOF | ${unixcat_bin} ${unixcat_socket} GET hosts Columns: state parents Filter: host_name = ${child} EOF) host_state=$(echo ${state_parent} | awk -F";" '{print $1}') host_parent=$(echo ${state_parent} | awk -F";" '{print $2}') if ! ( echo ${child} | grep "," ) > /dev/null 2>&1 ; then if [ ${host_state} -eq 0 ] ; then host_state_color='limegreen' elif [ ${host_state} -eq 1 ] ; then host_state_color='firebrick' else host_state_color='goldenrod' fi echo ' "'${child}'" [shape = box, style = "rounded, filled", fillcolor = '${host_state_color}'];' >> ${host_state_file} fi if ( echo ${child} | grep "," ) > /dev/null 2>&1 ; then while read origin_child ; do child=${origin_child} while [ "${child}" != "${network_base}" ] ; do QueryOwnStateAndHostParent ${child} done done < <(echo ${child} | tr ',' '\n') else if ( echo ${host_parent} | grep "," ) > /dev/null 2>&1 ; then while read single_parent ; do echo ' "'${child}'" -> "'${single_parent}'";' done < <(echo ${host_parent} | tr ',' '\n') else echo ' "'${child}'" -> "'${host_parent}'";' fi child=${host_parent} fi } children_list=$(cat <<-EOF | ${unixcat_bin} ${unixcat_socket} GET hosts Columns: host_name Filter: state != 0 Filter: acknowledged = 0 EOF) children_list=$(echo ${children_list} ; cat <<-EOF | ${unixcat_bin} ${unixcat_socket} GET services Columns: host_name Filter: state != 0 Filter: acknowledged = 0 EOF) children_list=$(echo ${children_list} | tr ' ' '\n' | sort -u) for child in ${children_list} ; do while [ "${child}" != "${network_base}" ] ; do QueryOwnStateAndHostParent ${child} done done > ${dot_file} sort -u ${dot_file} > ${dot_file}.tmp echo 'digraph map {' > ${dot_file} echo ' node [ fontname=Arial, fontcolor=black, fontsize=35];' >> ${dot_file} echo ' label = "Last generated at '$(date +%Y-%m-%d" "%H:%M:%S)'";' >> ${dot_file} #echo ' rankdir = LR;' >> ${dot_file} cat ${host_state_file} >> ${dot_file} cat ${dot_file}.tmp >> ${dot_file} echo '}' >> ${dot_file} rm ${dot_file}.tmp rm ${host_state_file} dot -Tpng ${dot_file} -o ${png_file}
Im Endeffekt müssen nur die folgenden Variablen angepasst werden:
unixcat_bin - Pfad zum unixcat Binary, kommt bei MK Livestatus mit unixcat_socket - Pfad zum MK Livestatus Socket, wird in der Nagios Config beim Broker Modul angegebendot_file - Pfad für Graphviz Config, wird während des Script-Laufs erzeugtpng_file - Pfad für Ausgabe der Map, wird während des Script-Laufs erzeugthost_state_file - ein temporäres File für die Anzeige des Status in der Mapnetwork_base - letzter Parent im Netzwerk (darf keine weiteren Parents haben)Nach erfolgreicher Ausführung wird, für mein Beispiel, das folgende dot-File generiert:
digraph map { node [ fontname=Arial, fontcolor=black, fontsize=35]; label = "Last generated at 2012-01-09 19:14:04"; "router03" [shape = box, style = "rounded, filled", fillcolor = limegreen]; "server01" [shape = box, style = "rounded, filled", fillcolor = limegreen]; "switch02" [shape = box, style = "rounded, filled", fillcolor = limegreen]; "router03" -> "Internet"; "server01" -> "switch02"; "switch02" -> "router03"; }
Das damit generierte png-File sieht dann so aus: