Hallo,
ich möchte meinen Nagios-Config-Generator auf IPv6 erweitern und bei
dieser Gelegenheit noch einige Luxufeatures dazuimplementieren. Bisher
habe ich das mit perl und template-toolkit implementiert, habe mich
aber entschlossen, die neue Version "zum warmwerden" in ruby zu
programmieren.
Meine Arbeit erfordert im Moment sowieso, dass ich etwas firmer in
ruby werde. Außerdem finde ich den Ansatz, innerhalb der Templates
dieelbe Programmiersprache zu benutzen wie im eigentlichen Code,
erheblich eleganter als ständig zwischen perl und dieser komischen
Template-Toolkit-Sprache hin- und her zu wechseln.
Hier mein vorläufiger Code:
#!/usr/bin/ruby
require 'json'
require 'pp'
require 'erb'
require 'resolv'
# parse JSON input data
file = File.open("example.json", "r")
data = file.read
parsed = JSON.parse(data)
defaults = parsed["defaults"]
hosts = parsed["host"]
# templates
hostdefinitiontemplate = %q{
define host
use <%= hostdata["use"] %>
host_name <%= hostdata["name"] %>_<%= hostdata["thisip"]
%>
hostgroups <% last=hostdata["groups"].shift %><%= last
%><% hostdata["groups"].each do |group| %>, <%= group %><% end %>
alias <%= hostdata["name"] %> (<%=
hostdata["thisip"] %>)
address <%= hostdata["thisip"] %>
parents <%= hostdata["parents"] %>
}.gsub(/^ /, '')
# iterate through hosts
hosts.keys.each do |hostname|
# save us from writing "hosts[hostname]"
puts hostname.pretty_inspect if $DEBUG
hostdata=hosts[hostname]
puts hostdata.pretty_inspect if $DEBUG
# allow identical handling for host name and other properties
hostdata["name"] ||= hostname
# pull in defaults from defaults stanza
hostdata["use"] ||= defaults["use"]
hostdata["parents"] ||= defaults["parents"]
hostdata["groups"] = hostdata["services"]
# pull all host's IPs from DNS
hostdata["ip"] = []
dns = Resolv::DNS.new
dns.getresources(hostdata["name"],
Resolv::DNS::Resource::IN::A).collect do |r|
hostdata["ip"] << r.address
end
dns.getresources(hostdata["name"],
Resolv::DNS::Resource::IN::AAAA).collect do |r|
hostdata["ip"] << r.address
end
puts hostdata.pretty_inspect if $DEBUG
# expand variable once per IP address
hostdata["ip"].each do |ip|
hostdata["thisip"] = ip
template = ERB.new(hostdefinitiontemplate, 0, "%<>")
output = template.result(binding)
puts output
end
end
(leider sind die Zeilenumbrüche da hineingerutscht, das krieg ich
kurzfristig mit meinem Newsreader nicht anders hin; die Alternative
wäre das ganze Zeug mit | zu quoten, dann könnt Ihr kein cut&paste
mehr machen).
Hier sind Test-Eingabedaten:
$ cat example.json
{
"defaults" : {
"use": "mh-servers",
"hostcheck": "ping",
"hostgroups": [ "mh-servers" ],
"parents": [ "internet" ]
},
"host": {
"
torres.zugschlus.de": {
"use": "bla",
"services": [ "ping", "smtp", "ssh" ],
"service": [
{
"name": "ping",
"target": [ "85.214.131.164" ]
}
],
"alias": ""
},
"
q.bofh.de": {
"services": [ "ping", "ssh", "smtp", "http" ],
"alias": ""
},
"
twoaddresses.zugschlus.de": {
"services": [ "ping", "ssh" ],
"alias": ""
}
}
}
Mein Zielsystem ist Debian squeeze, ich habe also nicht die
allerneuste Software zur Verfügung.
Nun meine Fragen:
Ich habe immer Schwierigkeiten, die Trennstelle zwischen dem
"eigentlichen Code" und der Template zu finden. Die beiden Extreme
sind natürlich nicht sinnvoll, aber ob ich hier (eine
Template-Expansion pro Hostdefinition) den richtigen Kompromiss
gefunden habe, lässt mich zweifeln
In den meisten ERB-Beispielen, die ich gefunden habe, wird eine
Extraklasse mit den Daten für die Template definiert. Ich vermute, in
so einem Setup kommt man in der Template ohne das ständige
'hostdata["foo"]' aus, und kann stattdessen einfach <%= foo %>
schreiben. Aber: Wie muss mein Code dafür aussehen?
Geht meine Konstruktion zum Bau einer kommagetrennten Liste
| <% last=hostdata["groups"].shift %><%= last %><% hostdata["groups"].each do |group| %>, <%= group %><% end %>
auch etwas eleganter?
Gibt es eine JSON-Library, deren "Pingeligkeit" man reduzieren kann?
In perl gibt es JON::XS->new->relaxed->decode, wo man Listen mit
Extrakommas abschließen kann, wo man Kommentare schreiben kann und
grundsätzlich etwas laxer mit der Syntax sein kann, ohne dass man
direkt einen Parse Error um die Ohren geworfen bekommt. Gibt es sowas
auch für Ruby? Kann man die Ruby-JSON-Library irgendwie dazu bewegen,
etwas genauere Fehlermeldungen zu produzieren, und mir wenigstens zu
sagen, in welcher Zeile der Eingabe der 'parse error near {'
aufgetreten ist?
In vielem Ruby-Code gibt es Konstruktionen wie object[:index] - hat
der Doppelpunkt eine besondere Bewandtnis?
Natürlich stehe ich auch stylistischen Kommentaren offen gegenüber,
ich habe noch nicht viel Gefühl für die Sprache.
Vielen Dank für Eure Mühe.
Grüße
Marc, hoffend, dass immer noch Leute mitlesen.
--
-------------------------------------- !! No courtesy copies, please !! -----
Marc Haber | " Questions are the | Mailadresse im Header
Mannheim, Germany | Beginning of Wisdom " |
http://www.zugschlus.de/
Nordisch by Nature | Lt. Worf, TNG "Rightful Heir" | Fon: *49 621 72739834