4
# $Id: Munin.pm.in,v 1.3 2004/01/29 18:19:58 jimmyo Exp $
6
# $Log: Munin.pm.in,v $
7
# Revision 1.3 2004/01/29 18:19:58 jimmyo
8
# Made Munin compatible with perl 5.005_03 (patch by Lupe Christoph) (SF#884622)
10
# Revision 1.2 2004/01/15 15:20:01 jimmyo
11
# Making things workable after name change. Upping for test verwion.
13
# Revision 1.1 2004/01/02 18:50:01 jimmyo
14
# Renamed occurrances of lrrd -> munin
16
# Revision 1.1.1.1 2004/01/02 15:18:07 jimmyo
17
# Import of LRRD CVS tree after renaming to Munin
19
# Revision 1.29 2003/12/12 18:59:30 jimmyo
20
# Change \1 to to make lrrd-update shut up.
22
# Revision 1.28 2003/12/10 11:59:39 jimmyo
23
# Enable/disable notifications at any level
25
# Revision 1.27 2003/12/06 20:19:55 jimmyo
28
# Revision 1.26 2003/12/06 19:12:57 jimmyo
29
# Added max_processes config variable. Also, removed zombie-generation code. :-P
31
# Revision 1.25 2003/12/06 17:13:56 jimmyo
32
# Can now escape #. Can now use \ to join lines.
34
# Revision 1.24 2003/12/02 11:48:56 jimmyo
37
# Revision 1.23 2003/12/02 10:14:43 jimmyo
38
# Moved some functions to LRRD.pm, since other programs use them as well.
40
# Revision 1.22 2003/11/24 16:25:51 jimmyo
41
# Make sure LRRD doesn't write any illegal lines to the datafile
43
# Revision 1.21 2003/11/24 14:22:10 jimmyo
44
# 0.9.9 release 2. Fixes a couple of stupid (minor) bugs
46
# Revision 1.20 2003/11/24 12:58:01 jimmyo
47
# minor bugfix - no noise about "extinfo"
49
# Revision 1.19 2003/11/16 11:33:16 jimmyo
52
# Revision 1.18 2003/11/15 13:26:01 jimmyo
53
# Added warn to legal options
55
# Revision 1.17 2003/11/15 11:10:29 jimmyo
58
# Revision 1.16 2003/11/10 16:09:00 jimmyo
59
# Be nice to Nagios - don't DOS it.
61
# Revision 1.15 2003/11/07 23:57:05 jimmyo
62
# Remove trailing whitespace from config file
64
# Revision 1.14 2003/11/07 22:58:09 jimmyo
65
# Documentation of new features/changes
67
# Revision 1.13 2003/11/07 20:46:12 jimmyo
68
# Only require Config::General if using old config format.
70
# Revision 1.12 2003/11/07 20:12:02 jimmyo
71
# datafile now saved in new config format
73
# Revision 1.11 2003/11/07 17:43:16 jimmyo
74
# Cleanups and log entries
81
@EXPORT = ('munin_trend',
96
'munin_get_filename');
100
use Fcntl qw(:DEFAULT :flock);
104
my $nsca = new IO::Handle;
108
my $configfile="@@CONFDIR@@/munin.conf";
110
my @legal = ("tmpldir", "ncsa", "ncsa_server", "ncsa_config", "rundir",
111
"dbdir", "logdir", "htmldir", "include", "domain_order", "node_order",
112
"graph_order", "fork", "graph_title", "create_args", "graph_args",
113
"graph_vlabel", "graph_vtitle", "graph_total", "graph_scale", "graph",
114
"update", "host_name", "label", "cdef", "draw", "graph", "max", "min",
115
"negative", "skipdraw", "type", "warning", "critical", "special_stack",
116
"special_sum", "stack", "sum", "address", "htaccess", "warn",
117
"use_default_name", "use_node_name", "port", "graph_noscale",
118
"nsca", "nsca_server", "nsca_config", "extinfo", "fetch_data",
119
"filename", "max_processes", "nagios"
125
return ($array[$#array] - $array[0]);
129
my ($file,$last,$type) = @_;
130
my ($start,$step,$names,$data) = RRDs::fetch $file,$type || "AVERAGE";
131
my @array = map { @$_[0] } splice(@$data, $#$data - ($last || 1));
132
return $array[0] if (!$last);
137
my ($name,$service,$label,$level,$comment) = @_;
141
open ($nsca ,"|$config->{nsca} $config->{nsca_server} -c $config->{nsca_config} -to 60");
145
print $nsca "$name\t$service: $label\t$level\t$comment\n";
146
print ("$name;$service: $label;$level;$comment\n") if $DEBUG;
150
print $nsca "$name\t$service\t$level\t$comment\n";
151
print ("$name;$service;$level;$comment\n") if $DEBUG;
155
sub munin_createlock {
157
if (-e $lockname && (! -w $lockname || ! -f $lockname)) {
158
die "Error writing to $lockname, wrong permissions";
160
if (sysopen (LOCK,$lockname,O_WRONLY | O_CREAT | O_EXCL)) {
161
print "Creating lock : $lockname succeded\n" if $DEBUG;
162
print LOCK $$; # we want the pid inside for later use
166
print "Creating lock : $lockname failed, skipping\n" if $DEBUG;
171
sub munin_removelock {
173
if (-e $lockname && ! -w $lockname) {
174
die "Error deleting $lockname, wrong permissions";
178
print "Deleting lock : $lockname\n" if $DEBUG;
180
print "Deleting lock : $lockname not found, skipping\n" if $DEBUG;
186
unless (&munin_getlock($lockname)) {
187
print "Lock already exists: $lockname. Dying.\n";
195
unless (&munin_createlock($lockname)) {
196
# Is the lockpid alive?
199
if ($pid =~ /^\d+$/ and kill(0,$pid)) {
202
&munin_removelock ($lockname);
203
&munin_createlock($lockname);
210
my ($config,$data) = @_;
211
for my $domain (keys %{$data->{domain}}) {
212
unless ($config->{domain}->{$domain}) {
213
::logger("Removing domain: $domain");
214
delete ($data->{domain}->{$domain});
217
for my $node (keys %{$data->{domain}->{$domain}->{node}}) {
218
unless ($config->{domain}->{$domain}->{node}->{$node}) {
219
::logger("Removing node from $domain: $node");
220
delete ($data->{domain}->{$domain}->{node}->{$node});
226
sub munin_overwrite {
227
my ($configfile,$overwrite) = @_;
228
for my $key (keys %$overwrite) {
229
if (ref $overwrite->{$key}) {
230
&munin_overwrite($overwrite->{$key},$configfile->{$key});
232
$configfile->{$key} = $overwrite->{$key};
234
return ($configfile);
237
sub munin_readconfig {
238
my ($conf, $missingok, $corruptok) = @_;
240
my @contents = undef;
242
$conf ||= $configfile;
243
if (! -r $conf and ! $missingok) {
244
::logger ("munin_readconfig: cannot open '$conf'\n");
247
if (open (CFG, $conf))
253
$config = &munin_parse_config (\@contents);
255
# Some important defaults before we return...
256
$config->{'rundir'} ||= "/tmp/";
257
$config->{'dbdir'} ||= "/var/lib/munin/";
258
$config->{'logdir'} ||= "/var/log/";
259
$config->{'tmpldir'}||= "/etc/munin/templates/";
260
$config->{'htmldir'}||= "@@HTMLDIR@@/";
264
sub munin_parse_config
271
foreach my $line (@{$lines})
274
$line =~ s/(^|[^\\])#.*/$1/g; # Skip comments...
275
next unless ($line =~ /\S/); # And empty lines...
276
if (length $prevline)
278
$line = $prevline . $line;
283
($prevline = $line) =~ s/\\$//;
286
$line =~ s/\s+$//g; # And trailing whitespace...
287
$line =~ s/^\s+//g; # And heading whitespace...
289
if ($line =~ /^\s*\.(\S+)\s+(.+)\s*$/)
291
my ($var, $val) = ($1, $2);
292
$hash = &munin_set_var_path ($hash, $var, $val);
294
elsif ($line =~ /^\s*\[([^\]]*)]\s*$/)
297
if ($prefix =~ /^([^:;]+);([^:;]+)$/)
301
elsif ($prefix =~ /^([^:;]+);$/)
305
elsif ($prefix =~ /^([^:;]+);([^:;]+):(.*)$/)
309
elsif ($prefix =~ /^([^:;]+)$/)
311
(my $domain = $prefix) =~ s/^[^\.]+\.//;
312
$prefix = "$domain;$prefix:";
314
elsif ($prefix =~ /^([^:;]+):(.*)$/)
316
(my $domain = $prefix) =~ s/^[^\.]+\.//;
317
$prefix = "$domain;$prefix.";
320
elsif ($line =~ /^\s*(\S+)\s+(.+)\s*$/)
322
my ($var, $val) = ($1, $2);
323
$hash = &munin_set_var_path ($hash, "$prefix$var", $val);
327
warn "Malformed configuration line \"$line\".";
334
sub munin_get_var_path
340
print "DEBUG: Getting var \"$var\" = \"$val\"\n" if $DEBUG;
341
if ($var =~ /^\s*([^;:]+);([^;:]+):(\S+)\s*$/)
343
my ($dom, $host, $rest) = ($1, $2, $3);
344
my @sp = split (/\s*\.\s*/, $rest);
348
return $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{"$sp[1].$sp[2]"};
352
return $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{$sp[1]};
356
return $hash->{domain}->{$dom}->{node}->{$host}->{$sp[0]};
360
warn "munin_set_var: Malformatted variable path \"$var\".";
363
elsif ($var =~ /^\s*([^;:]+);([^;:]+)\s*$/)
365
my ($dom, $rest) = ($1, $2);
366
my @sp = split (/\s*\.\s*/, $rest);
370
return $hash->{domain}->{$dom}->{$sp[0]};
374
warn "munin_set_var: Malformatted variable path \"$var\".";
377
elsif ($var =~ /^\s*([^;:\.]+)\s*$/)
383
warn "munin_set_var: Malformatted variable path \"$var\".";
389
sub munin_set_var_path
395
print "DEBUG: Setting var \"$var\" = \"$val\"\n" if $DEBUG;
396
if ($var =~ /^\s*([^;:]+);([^;:]+):(\S+)\s*$/)
398
my ($dom, $host, $rest) = ($1, $2, $3);
399
my @sp = split (/\s*\.\s*/, $rest);
403
print STDERR ("Warning: Unknown option \"$sp[2]\" in \"$dom;$host:$sp[0].$sp[1].$sp[2]\".\n")
404
unless grep /^$sp[2]$/, @legal;
405
$hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{"$sp[1].$sp[2]"} = $val;
409
print STDERR ("Warning: Unknown option \"$sp[1]\" in \"$dom;$host:$sp[0].$sp[1]\".\n")
410
unless grep /^$sp[1]$/, @legal;
411
$hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{$sp[1]} = $val;
415
print STDERR ("Warning: Unknown option \"$sp[0]\" in \"$dom;$host:$sp[0]\".\n")
416
unless grep /^$sp[0]$/, @legal;
417
$hash->{domain}->{$dom}->{node}->{$host}->{$sp[0]} = $val;
421
warn "munin_set_var: Malformatted variable path \"$var\".";
424
elsif ($var =~ /^\s*([^;:]+);([^;:]+)\s*$/)
426
my ($dom, $rest) = ($1, $2);
427
my @sp = split (/\s*\.\s*/, $rest);
431
print STDERR ("Warning: Unknown option \"$sp[0]\" in \"$dom;$sp[0]\".\n")
432
unless grep /^$sp[0]$/, @legal;
433
$hash->{domain}->{$dom}->{$sp[0]} = $val;
437
warn "munin_set_var: Malformatted variable path \"$var\".";
440
elsif ($var =~ /^\s*([^;:\.]+)\s*$/)
442
print STDERR ("Warning: Unknown option \"$1\" in \"$1\".\n")
443
unless grep /^$1$/, @legal;
448
warn "munin_set_var: Malformatted variable path \"$var\".";
454
sub munin_writeconfig_loop {
455
my ($data,$fh,$pre) = @_;
458
# Write datafile in new format
459
foreach my $a (keys %{$data})
461
if (ref ($data->{$a}) eq "HASH")
463
if ($a eq "domain" or $a eq "node" or $a eq "client")
465
&munin_writeconfig_loop ($data->{$a}, $fh, "$pre");
474
elsif ($lpre =~ /;$/)
482
&munin_writeconfig_loop ($data->{$a}, $fh, "$lpre");
485
elsif (defined $data->{$a} and length $data->{$a})
487
print "Writing: $pre$a $data->{$a}\n" if $DEBUG;
488
print $fh "$pre$a $data->{$a}\n";
492
sub munin_writeconfig {
493
my ($datafilename,$data,$fh) = @_;
494
# my $datafile = new Config::General();
495
# $datafile->save_file($datafilename,$data);
500
unless (open ($fh, ">$datafilename"))
502
die "Fatal error: Could not open \"$datafilename\" for writing: $!";
506
# Write datafile in new format
507
&munin_writeconfig_loop ($data, $fh, "");
511
print "DEBUG: Closing filehandle \"$datafilename\"...\n" if $DEBUG;
517
my $conffile = shift;
518
$conffile ||= $configfile;
519
$config = &munin_readconfig ($conffile);
520
my $data = &munin_readconfig("$config->{dbdir}/datafile", 1, 1);
522
$data = &munin_overwrite($data,$config);
526
sub munin_get_filename {
527
my ($domain,$node,$service,$field) = @_;
529
return ($config->{'dbdir'} . "/$domain/$node-$service-$field-" . lc substr (($config->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field.".type"}||"GAUGE"), 0,1). ".rrd");
543
return undef unless defined $field;
545
my $ans = &munin_get_val ($conf, $field, $default, $domain, $node, $service, $plot);
546
return undef if not defined $ans;
548
if ($ans =~ /^yes$/i or
551
$ans =~ /^enable$/i or
557
elsif ($ans =~ /^no$/i or
558
$ans =~ /^false$/i or
560
$ans =~ /^disable$/i or
561
$ans =~ /^disabled$/i
576
sub munin_get_bool_val
583
if (!defined $default)
593
if ($field =~ /^yes$/i or
594
$field =~ /^true$/i or
596
$field =~ /^enable$/i or
597
$field =~ /^enabled$/i
602
elsif ($field =~ /^no$/i or
603
$field =~ /^false$/i or
604
$field =~ /^off$/i or
605
$field =~ /^disable$/i or
606
$field =~ /^disabled$/i
611
elsif ($field !~ /\D/)
633
return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$plot.$field"}
634
if (defined $domain and defined $node and defined $service and defined $plot and
635
defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{"$plot.$field"});
639
return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field}
640
if (defined $domain and defined $node and defined $service and
641
defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}->{$field});
642
return $conf->{domain}->{$domain}->{node}->{$node}->{$field}
643
if (defined $domain and defined $node and
644
defined $conf->{domain}->{$domain}->{node}->{$node}->{$field});
645
return $conf->{domain}->{$domain}->{$field}
646
if (defined $domain and defined $conf->{domain}->{$domain}->{$field});
647
return $conf->{$field}
648
if (defined $conf->{$field});
653
return $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service}
654
if (defined $domain and defined $node and defined $service and
655
defined $conf->{domain}->{$domain}->{node}->{$node}->{client}->{$service});
656
return $conf->{domain}->{$domain}->{node}->{$node}
657
if (defined $domain and defined $node and
658
defined $conf->{domain}->{$domain}->{node}->{$node});
659
return $conf->{domain}->{$domain}
660
if (defined $domain and defined $conf->{domain}->{$domain});