%PDF- %PDF-
| Direktori : /usr/share/perl5/vendor_perl/Munin/Master/ |
| Current File : //usr/share/perl5/vendor_perl/Munin/Master/Utils.pm |
package Munin::Master::Utils;
# -*- cperl -*-
# $Id$
use strict;
use warnings;
use Carp;
use Exporter;
use English qw(-no_match_vars);
use Fcntl qw(:DEFAULT :flock);
use File::Path;
use IO::Handle;
use Munin::Common::Defaults;
use Munin::Master::Logger;
use Munin::Master::Config;
use Munin::Common::Config;
use Log::Log4perl qw(:easy);
use POSIX qw(strftime);
use POSIX qw(:sys_wait_h);
use Symbol qw(gensym);
use Data::Dumper;
use Storable;
use Scalar::Util qw(isweak weaken);
our (@ISA, @EXPORT);
@ISA = ('Exporter');
@EXPORT = (
'munin_nscasend',
'munin_createlock',
'munin_removelock',
'munin_runlock',
'munin_getlock',
'munin_readconfig_raw',
'munin_writeconfig',
'munin_writeconfig_storable',
'munin_read_storable',
'munin_write_storable',
'munin_delete',
'munin_overwrite',
'munin_dumpconfig',
'munin_dumpconfig_as_str',
'munin_readconfig_base',
'munin_readconfig_part',
'munin_configpart_revision',
'munin_draw_field',
'munin_get_bool',
'munin_get_bool_val',
'munin_get',
'munin_field_status',
'munin_service_status',
'munin_node_status',
'munin_category_status',
'munin_get_picture_filename',
'munin_get_picture_loc',
'munin_get_html_filename',
'munin_get_filename',
'munin_get_keypath',
'munin_graph_column_headers',
'munin_get_max_label_length',
'munin_get_field_order',
'munin_get_rrd_filename',
'munin_get_node_name',
'munin_get_orig_node_name',
'munin_get_parent_name',
'munin_get_node_fqn',
'munin_find_node_by_fqn',
'munin_get_node_loc',
'munin_get_node',
'munin_set_var_loc',
'munin_set_var_path',
'munin_set',
'munin_copy_node_toloc',
'munin_get_separated_node',
'munin_mkdir_p',
'munin_find_field',
'munin_find_field_for_limits',
'munin_get_parent',
'munin_get_children',
'munin_get_node_partialpath',
'munin_has_subservices',
'munin_get_host_path_from_string',
'print_version_and_exit',
'exit_if_run_by_super_user',
'look_for_child',
'wait_for_remaining_children',
);
my $VERSION = $Munin::Common::Defaults::MUNIN_VERSION;
my $nsca = new IO::Handle;
my $config = undef;
my $config_parts = {
# config parts that might be loaded and reloaded at times
'datafile' => {
'timestamp' => 0,
'config' => undef,
'revision' => 0,
'include_base' => 1,
},
'limits' => {
'timestamp' => 0,
'config' => undef,
'revision' => 0,
'include_base' => 1,
},
'htmlconf' => {
'timestamp' => 0,
'config' => undef,
'revision' => 0,
'include_base' => 0,
},
};
my $configfile="$Munin::Common::Defaults::MUNIN_CONFDIR/munin.conf";
# Fields to copy when "aliasing" a field
my @COPY_FIELDS = ("label", "draw", "type", "rrdfile", "fieldname", "info");
my @dircomponents = split('/',$0);
my $me = pop(@dircomponents);
sub munin_draw_field {
my $hash = shift;
return 0 if munin_get_bool ($hash, "skipdraw", 0);
return 0 if !munin_get_bool ($hash, "graph", 1);
return defined $hash->{"label"};
}
sub munin_nscasend {
my ($name,$service,$label,$level,$comment) = @_;
if (!$nsca->opened)
{
open ($nsca ,'|-', "$config->{nsca} $config->{nsca_server} -c $config->{nsca_config} -to 60");
}
if ($label)
{
print $nsca "$name\t$service: $label\t$level\t$comment\n";
DEBUG "To $nsca: $name;$service: $label;$level;$comment\n";
}
else
{
print $nsca "$name\t$service\t$level\t$comment\n";
DEBUG "[DEBUG] To $nsca: $name;$service;$level;$comment\n";
}
}
sub munin_createlock {
# Create lock file, fail and die if not possible.
my ($lockname) = @_;
if (sysopen (LOCK,$lockname,O_WRONLY | O_CREAT | O_EXCL)) {
DEBUG "[DEBUG] Creating lock : $lockname succeeded\n";
print LOCK $$; # we want the pid inside for later use
close LOCK;
return 1;
} else {
LOGCROAK("Creating lock $lockname failed: $!\n");
}
}
sub munin_removelock {
# Remove lock or die trying.
my ($lockname) = @_;
unlink $lockname or
LOGCROAK("[FATAL ERROR] Error deleting lock $lockname: $!\n");
}
sub munin_runlock {
my ($lockname) = @_;
unless (munin_getlock($lockname)) {
LOGCROAK("[FATAL ERROR] Lock already exists: $lockname. Dying.\n");
}
return 1;
}
sub munin_getlock {
my ($lockname) = @_;
if (-f $lockname) {
DEBUG "[DEBUG] Lock $lockname already exists, checking process";
# Is the lockpid alive?
# To check this is inteligent and so on. It also makes for a
# nice locking racing-condition. BUT, since munin-* runs from
# cron every 5 minutes this should not be a real threat. This
# ream of code should complete in less than 5 minutes.
open my $LOCK, '<', $lockname or
LOGCROAK("Could not open $lockname for reading: $!\n");
my $pid = <$LOCK>;
$pid = '' if !defined($pid);
close($LOCK) or LOGCROAK("Could not close $lockname: $!\n");
DEBUG "[DEBUG] Lock contained pid '$pid'";
# Make sure it's a proper pid
if (defined($pid) and $pid =~ /^(\d+)$/ and $1 != 1) {
$pid = $1;
if (kill(0, $pid)) {
DEBUG "[DEBUG] kill -0 $pid worked - it is still alive. Locking failed.";
return 0;
}
INFO "[INFO] Process $pid is dead, stealing lock, removing file";
} else {
INFO "[INFO] PID in lock file is bogus. Removing lock file";
}
munin_removelock($lockname);
}
DEBUG "[DEBUG] Creating new lock file $lockname";
munin_createlock($lockname);
return 1;
}
sub munin_delete {
my ($config,$data) = @_;
for my $domain (keys %{$data->{domain}}) {
unless ($config->{domain}->{$domain}) {
DEBUG "[DEBUG] Removing domain: $domain";
delete ($data->{domain}->{$domain});
next;
}
for my $node (keys %{$data->{domain}->{$domain}->{node}}) {
unless ($config->{domain}->{$domain}->{node}->{$node}) {
DEBUG "[DEBUG] Removing node from $domain: $node";
delete ($data->{domain}->{$domain}->{node}->{$node});
}
}
}
return ($data);
}
sub munin_overwrite {
# copy from $overwrite OVER $config.
my ($configfile,$overwrite) = @_;
for my $key (keys %$overwrite) {
next if substr($key,0,3) eq '#%#';
if (ref $overwrite->{$key}) {
if (!defined $configfile->{$key}) {
if (ref $overwrite->{$key} eq "HASH") {
$configfile->{$key}->{'#%#parent'} = $configfile; weaken($configfile->{$key}->{'#%#parent'});
$configfile->{$key}->{'#%#name'} = $key;
munin_overwrite($configfile->{$key},$overwrite->{$key});
} else {
$configfile->{$key} = $overwrite->{$key};
}
} else {
munin_overwrite($configfile->{$key},$overwrite->{$key});
}
} else {
$configfile->{$key} = $overwrite->{$key};
}
}
return ($configfile);
}
sub munin_readconfig_raw {
my ($conf, $missingok) = @_;
my $part = undef;
$conf ||= $configfile;
# try first to read storable version
$part = munin_read_storable("$conf.storable");
if (!defined $part) {
if (! -r $conf and ! $missingok) {
WARN "munin_readconfig: cannot open '$conf'";
return;
}
if (open (my $CFG, '<', $conf)) {
my @contents = <$CFG>;
close ($CFG);
$part = munin_parse_config (\@contents);
}
}
return $part;
}
sub munin_parse_config
{
my $lines = shift;
my $hash = {};
my $prefix = "";
my $prevline = "";
foreach my $line (@{$lines})
{
chomp $line;
if ($line =~ /#/) {
next if ($line =~ /^#/);
$line =~ s/(^|[^\\])#.*/$1/g;
$line =~ s/\\#/#/g;
}
next unless ($line =~ /\S/); # And empty lines...
if (length $prevline) {
$line = $prevline . $line;
$prevline = "";
}
if ($line =~ /\\\\$/) {
$line =~ s/\\\\$/\\/;
} elsif ($line =~ /\\$/) {
($prevline = $line) =~ s/\\$//;
next;
}
$line =~ s/\s+$//g; # And trailing whitespace...
$line =~ s/^\s+//g; # And heading whitespace...
if ($line =~ /^\.(\S+)\s+(.+)\s*$/) {
my ($var, $val) = ($1, $2);
$hash = munin_set_var_path ($hash, $var, $val);
} elsif ($line =~ /^\s*\[([^\]]*)]\s*$/) {
$prefix = $1;
if ($prefix =~ /^([^:]+);([^:;]+)$/) {
$prefix .= ":";
} elsif ($prefix =~ /^([^:;]+);$/) {
$prefix .= "";
} elsif ($prefix =~ /^([^:;]+);([^:;]+):(.*)$/) {
$prefix .= ".";
} elsif ($prefix =~ /^([^:;]+)$/) {
(my $domain = $prefix) =~ s/^[^\.]+\.//;
$prefix = "$domain;$prefix:";
} elsif ($prefix =~ /^([^:;]+):(.*)$/) {
(my $domain = $prefix) =~ s/^[^\.]+\.//;
$prefix = "$domain;$prefix.";
}
} elsif ($line =~ /^\s*(\S+)\s+(.+)\s*$/) {
my ($var, $val) = ($1, $2);
$hash = munin_set_var_path ($hash, "$prefix$var", $val);
} else {
warn "Malformed configuration line \"$line\".";
}
}
return $hash;
}
sub munin_get_var_path
{
my $hash = shift;
my $var = shift;
my $val = shift;
DEBUG "DEBUG: Getting var \"$var\" = \"$val\"\n";
if ($var =~ /^\s*([^;:]+);([^;:]+):(\S+)\s*$/)
{
my ($dom, $host, $rest) = ($1, $2, $3);
my @sp = split (/\./, $rest);
if (@sp == 3)
{
return $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{"$sp[1].$sp[2]"};
}
elsif (@sp == 2)
{
return $hash->{domain}->{$dom}->{node}->{$host}->{client}->{$sp[0]}->{$sp[1]};
}
elsif (@sp == 1)
{
return $hash->{domain}->{$dom}->{node}->{$host}->{$sp[0]};
}
else
{
warn "munin_set_var_path: Malformatted variable path \"$var\".";
}
}
elsif ($var =~ /^\s*([^;:]+);([^;:]+)\s*$/)
{
my ($dom, $rest) = ($1, $2);
my @sp = split (/\./, $rest);
if (@sp == 1)
{
return $hash->{domain}->{$dom}->{$sp[0]};
}
else
{
warn "munin_set_var_path: Malformatted variable path \"$var\".";
}
}
elsif ($var =~ /^\s*([^;:\.]+)\s*$/)
{
return $hash->{$1};
}
else
{
warn "munin_set_var_path: Malformatted variable path \"$var\".";
}
return;
}
sub munin_find_field {
# Starting at the (presumably the root) $hash make recursive calls
# until for example graph_title or value is found, and then
# continue recursing and itterating until all are found.
#
# Then we return a array of pointers into the $hash
#
# This function will not use REs as they are inordinately
# expensive. There is a munin_find_field_for_limits that will
# match REs instead of whole strings.
my ($hash, $field, $avoid) = @_;
my $res = [];
if (ref ($hash) eq "HASH") {
foreach my $key (keys %{$hash}) {
next if substr($key,0,3) eq '#%#';
last if defined $avoid and $key eq $avoid;
# Always check $key eq $field first here, or we break
if ($key eq $field) {
push @$res, $hash;
} elsif (ref ($hash->{$key}) eq "HASH") {
push @$res, @{munin_find_field ($hash->{$key}, $field, $avoid)};
}
}
}
return $res;
}
sub munin_find_field_for_limits {
my ($hash, $field, $avoid) = @_;
my $res = [];
if (ref ($field) ne "Regexp") {
$field = qr/^$field$/;
}
if (ref ($hash) eq "HASH") {
foreach my $key (keys %{$hash}) {
next if substr($key,0,3) eq '#%#';
last if defined $avoid and $key eq $avoid;
if (ref ($hash->{$key}) eq "HASH") {
push @$res, @{munin_find_field_for_limits ($hash->{$key}, $field, $avoid)};
} elsif ($key =~ $field) {
push @$res, $hash;
}
}
}
return $res;
}
sub munin_get_children {
my $hash = shift;
my $res = [];
return if (ref ($hash) ne "HASH");
foreach my $key (keys %{$hash}) {
next if substr($key,0,3) eq '#%#';
if (defined $hash->{$key} and ref ($hash->{$key}) eq "HASH") {
push @$res, $hash->{$key};
}
}
return $res;
}
sub munin_get_separated_node
{
my $hash = shift;
my $ret = {};
if (ref ($hash) eq "HASH") {
foreach my $key (keys %$hash) {
next if substr($key,0,3) eq '#%#';
if (ref ($hash->{$key}) eq "HASH") {
$ret->{$key} = munin_get_separated_node ($hash->{$key});
} else {
$ret->{$key} = $hash->{$key};
}
}
} else {
return;
}
return $ret;
}
sub munin_get_parent_name
{
my $hash = shift;
if (ref ($hash) eq "HASH" and defined $hash->{'#%#parent'}) {
return munin_get_node_name ($hash->{'#%#parent'});
} else {
return "none";
}
}
sub munin_get_orig_node_name {
my $hash = shift;
if (ref ($hash) eq "HASH" and defined $hash->{'#%#name'}) {
return (defined $hash->{'#%#origname'}) ? $hash->{'#%#origname'} : $hash->{'#%#name'};
} else {
return;
}
}
sub munin_get_node_name
{
my $hash = shift;
if (ref ($hash) eq "HASH" and defined $hash->{'#%#name'}) {
return $hash->{'#%#name'};
} else {
return;
}
}
sub munin_get_node_fqn
{
my $hash = shift;
if (ref ($hash) eq "HASH") {
my $fqn = "";
if (defined $hash->{'#%#name'}) {
$fqn = $hash->{'#%#name'};
}
if (defined $hash->{'#%#parent'}) {
# Recursively prepend the parent, concatenation with /
$fqn = munin_get_node_fqn ($hash->{'#%#parent'}) . "/" . $fqn;
}
return $fqn;
} else {
return;
}
}
sub munin_find_node_by_fqn {
# The FQN should be relative to the point in the hash we're handed.
my($hash,$fqn) = @_;
my $here = $hash;
my @path = split('/',$fqn);
foreach my $pc (@path) {
next if $pc eq 'root';
if (exists $here->{$pc}) {
$here = $here->{$pc};
} else {
confess "Could not find FQN $fqn!";
}
}
return $here ;
}
sub munin_get_picture_loc {
my $hash = shift;
my $res = [];
if (ref ($hash) ne "HASH") { # Not a hash node
return;
}
if (defined $hash->{'#%#origin'}) {
$res = munin_get_picture_loc ($hash->{'#%#origin'});
} elsif (defined $hash->{'#%#origparent'}){
$res = munin_get_picture_loc ($hash->{'#%#origparent'});
push @$res, munin_get_orig_node_name ($hash) if defined $res;
} elsif (defined $hash->{'#%#parent'}) {
$res = munin_get_picture_loc ($hash->{'#%#parent'});
push @$res, munin_get_orig_node_name ($hash) if defined $res;
}
return $res;
}
sub munin_get_node_loc {
my $hash = shift;
my $res = [];
if (ref ($hash) ne "HASH") { # Not a has node
return;
}
if (defined $hash->{'#%#parent'}) {
if(defined $hash->{'#%#origparent'}){
$res = munin_get_node_loc ($hash->{'#%#origparent'});
} else {
$res = munin_get_node_loc ($hash->{'#%#parent'});
}
push @$res, munin_get_orig_node_name ($hash) if defined $res;
}
return $res;
}
sub munin_get_parent {
my $hash = shift;
if (ref ($hash) ne "HASH") { # Not a has node
return;
}
if (defined $hash->{'#%#parent'}) {
return $hash->{'#%#parent'};
} else {
return;
}
}
sub munin_get_node {
# From the given point in the hash itterate deeper into the
# has along the path given by the array in $loc.
#
# If any part of the path in $loc is undefined we bail.
my $hash = shift;
my $loc = shift;
foreach my $tmpvar (@$loc) {
if (! exists $hash->{$tmpvar} ) {
# Only complain on a blank key if is no key like that. Usually it
# shouln't, so it avoids a needless regexp in this highly used
# function
ERROR "[ERROR] munin_get_node: Cannot work on hash node '$tmpvar'" if ($tmpvar !~ /\S/);
return undef;
}
$hash = $hash->{$tmpvar};
}
return $hash;
}
sub munin_set {
my $hash = shift;
my $var = shift;
my $val = shift;
return munin_set_var_loc ($hash, [$var], $val);
}
sub munin_set_var_loc
{
my $hash = shift;
my $loc = shift;
my $val = shift;
my $iloc = 0;
# XXX - Dirty breaking recursive function
# --> Using goto is BAD, but enough for now
START:
# Find the next normal value (that doesn't begin with #%#)
my $tmpvar = $loc->[$iloc++];
$tmpvar = $loc->[$iloc++] while (defined $tmpvar and
substr($tmpvar,0,3) eq '#%#');
if (index($tmpvar, " ") != -1) {
ERROR "[ERROR] munin_set_var_loc: Cannot work on hash node \"$tmpvar\"";
return;
}
if (scalar @$loc > $iloc) {
if (!defined $hash->{$tmpvar} or !defined $hash->{$tmpvar}->{"#%#name"}) {
# Init the new node
$hash->{$tmpvar}->{"#%#parent"} = $hash; weaken($hash->{$tmpvar}->{"#%#parent"});
$hash->{$tmpvar}->{"#%#name"} = $tmpvar;
}
# Recurse
$hash = $hash->{$tmpvar};
goto START;
} else {
WARN "[WARNING] munin_set_var_loc: Setting unknown option '$tmpvar' at "
. munin_get_keypath($hash)
unless Munin::Common::Config::cl_is_keyword($tmpvar);
# FIX - or not.
$hash->{$tmpvar} = $val;
return $hash;
}
}
sub munin_get_node_partialpath
{
my $hash = shift;
my $var = shift;
my $ret = undef;
return if !defined $hash or ref ($hash) ne "HASH";
my $root = munin_get_root_node ($hash);
my $hashloc = munin_get_node_loc ($hash);
my $varloc = undef;
if ($var =~ /^\s*([^:]+):(\S+)\s*$/) {
my ($leftstring, $rightstring) = ($1, $2);
my @leftarr = split (/;/, $leftstring);
my @rightarr = split (/\./, $rightstring);
push @$varloc, @leftarr, @rightarr
} elsif ($var =~ /^\s*([^;:.]+)\s*$/) {
push @$varloc, $var;
} elsif ($var =~ /^\s*([^.]+)\.([^:;]+)$/) {
my ($leftstring, $rightstring) = ($1, $2);
my @leftarr = split (/;/, $leftstring);
my @rightarr = split (/\./, $rightstring);
push @$varloc, @leftarr, @rightarr;
} elsif ($var =~ /^\s*(\S+)\s*$/) {
my @leftarr = split (/;/, $1);
push @$varloc, @leftarr;
} else {
ERROR "[ERROR] munin_get_node_partialpath: Malformed variable path \"$var\".";
}
# We've got both parts of the loc (varloc and hashloc) -- let's figure out
# where they meet up.
do {
$ret = munin_get_node ($root, [@$hashloc, @$varloc]);
} while (!defined $ret and pop @$hashloc);
return $ret;
}
sub munin_set_var_path
{
my $hash = shift;
my $var = shift;
my $val = shift;
my $result = undef;
DEBUG "[DEBUG] munin_set_var_path: Setting var \"$var\" = \"$val\"";
if ($var =~ /^\s*([^:]+):(\S+)\s*$/) {
my ($leftstring, $rightstring) = ($1, $2);
my @leftarr = split (/;/, $leftstring);
my @rightarr = split (/\./, $rightstring);
$result = munin_set_var_loc ($hash, [@leftarr, @rightarr], $val);
} elsif ($var =~ /^\s*([^;:\.]+)\s*$/) {
$result = munin_set_var_loc ($hash, [$1], $val);
} elsif ($var =~ /^\s*([^:;]+)$/) {
my @leftarr = split (/\./, $1);
$result = munin_set_var_loc ($hash, [@leftarr], $val);
} elsif ($var =~ /^\s*(.+)\.([^\.:;]+)$/) {
my ($leftstring, $rightstring) = ($1, $2);
my @leftarr = split (/;/, $leftstring);
my @rightarr = split (/\./, $rightstring);
$result = munin_set_var_loc ($hash, [@leftarr, @rightarr], $val);
} elsif ($var =~ /^\s*(\S+)\s*$/) {
my @leftarr = split (/;/, $1);
$result = munin_set_var_loc ($hash, [@leftarr], $val);
} else {
ERROR "Error: munin_set_var_path: Malformatted variable path \"$var\".";
}
if (!defined $result) {
ERROR "Error: munin_set_var_path: Failed setting \"$var\" = \"$val\".";
}
return $hash;
}
sub munin_get_root_node
{
my $hash = shift;
return if ref ($hash) ne "HASH";
while (defined $hash->{'#%#parent'}) {
$hash = $hash->{'#%#parent'};
}
return $hash;
}
sub munin_writeconfig_loop {
my ($hash,$fh,$pre) = @_;
foreach my $key (keys %$hash) {
next if substr($key,0,3) eq '#%#';
my $path = (defined $pre ? join(';', ($pre, $key)) : $key);
if (ref ($hash->{$key}) eq "HASH") {
munin_writeconfig_loop ($hash->{$key}, $fh, $path);
} else {
next if !defined $pre and $key eq "version"; # Handled separately
next if !defined $hash->{$key} or !length $hash->{$key};
(my $outstring = $hash->{$key}) =~ s/([^\\])#/$1\\#/g;
# Too much. Can be seen in the file itself.
# DEBUG "[DEBUG] Writing: $path $outstring\n";
if ($outstring =~ /\\$/)
{ # Backslash as last char has special meaning. Avoid it.
print $fh "$path $outstring\\\n";
} else {
print $fh "$path $outstring\n";
}
}
}
}
sub munin_read_storable {
my ($storable_filename, $default) = @_;
if (-e $storable_filename) {
my $storable = eval { Storable::retrieve($storable_filename); };
return $storable unless $@;
# Didn't managed to read storable.
# Removing it as it is already torched anyway.
unlink($storable_filename);
}
# return default if no better option
return $default;
}
sub munin_write_storable {
my ($storable_filename, $data) = @_;
DEBUG "[DEBUG] about to write '$storable_filename'";
# We don't need to write anything if there is nothing to write.
return unless defined $data;
my $storable_filename_tmp = $storable_filename . ".tmp.$$";
# Write datafile.storable, in network order to be architecture indep
Storable::nstore($data, $storable_filename_tmp);
# Atomic commit
rename ($storable_filename_tmp, $storable_filename);
}
sub munin_writeconfig_storable {
my ($datafilename,$data) = @_;
DEBUG "[DEBUG] Writing state to $datafilename";
munin_write_storable($datafilename, $data);
}
sub munin_writeconfig {
my ($datafilename,$data,$fh) = @_;
DEBUG "[DEBUG] Writing state to $datafilename";
my $is_fh_already_managed = defined $fh;
if (! $is_fh_already_managed) {
$fh = gensym();
unless (open ($fh, ">", $datafilename)) {
LOGCROAK "Fatal error: Could not open \"$datafilename\" for writing: $!";
}
}
# Write version
print $fh "version $VERSION\n";
# Write datafile
munin_writeconfig_loop ($data, $fh);
if (! $is_fh_already_managed) {
DEBUG "[DEBUG] Closing filehandle \"$datafilename\"...\n";
close ($fh);
}
}
sub munin_dumpconfig_as_str {
my ($config) = @_;
local $Data::Dumper::Sortkeys = sub { [ sort grep {!/^#%#parent$/} keys %{$_[0]} ]; };
local $Data::Dumper::Indent = 1;
return Dumper $config;
}
sub munin_dumpconfig {
my ($config) = @_;
my $indent = $Data::Dumper::Indent;
my $sorter = $Data::Dumper::Sortkeys;
$Data::Dumper::Sortkeys =
sub { [ sort grep {!/^#%#parent$/} keys %{$_[0]} ]; };
$Data::Dumper::Indent = 1;
print "##\n";
print "## NOTE: #%#parent is hidden to make the print readable!\n";
print "##\n";
print Dumper $config;
$Data::Dumper::Sortkeys = $sorter;
$Data::Dumper::Indent = $indent;
}
sub munin_configpart_revision {
my $what = shift;
if (defined $what and defined $config_parts->{$what}) {
return $config_parts->{$what}{revision};
}
my $rev = 0;
foreach $what (keys %$config_parts) {
$rev += $config_parts->{$what}{revision};
}
return $rev;
}
sub munin_readconfig_part {
my $what = shift;
my $missingok = shift;
if (! defined $config_parts->{$what}) {
ERROR "[ERROR] munin_readconfig_part with unknown part name ($what).";
return undef;
}
# for now, we only really care about storable.
# No reason to bother reading non-storable elements anyway.
my $filename = "$config->{dbdir}/$what.storable";
my $part = {};
my $doupdate = 0;
if (! -f $filename) {
unless (defined $missingok and $missingok) {
ERROR "[FATAL] munin_readconfig_part($what) - missing file";
exit(1);
}
# missing ok, return last value if we have one, copy config if not
unless (defined $config_parts->{$what}{config}) {
# well, not if we shouldn't include the config
if ($config_parts->{$what}{include_base}) {
$doupdate = 1;
}
}
} else {
my @stat = stat($filename);
if ($config_parts->{$what}{timestamp} < $stat[9]) {
# could use _raw if we wanted to read non-storable fallback
$config_parts->{$what}{config} = undef; # Unalloc RAM for old config, since it will be overriden anyway.
$part = munin_read_storable($filename);
$config_parts->{$what}{timestamp} = $stat[9];
$doupdate = 1;
}
}
if ($doupdate) {
$part->{'#%#name'} = 'root';
$part->{'#%#parent'} = undef;
$part = munin_overwrite($part, $config) if ($config_parts->{$what}{include_base});
$config_parts->{$what}{config} = $part;
++$config_parts->{$what}{revision};
}
return $config_parts->{$what}{config};
}
sub munin_readconfig_base {
my $conffile = shift;
$conffile ||= $configfile;
$config = munin_readconfig_raw($conffile);
if (defined $config->{'includedir'}) {
my $dirname = $config->{'includedir'};
DEBUG "Includedir statement to include files in $dirname";
my $DIR;
opendir($DIR, $dirname) or
WARN "[Warning] Could not open includedir directory $dirname: $OS_ERROR\n";
my @files = grep { ! /^\.|~$/ } readdir($DIR);
closedir($DIR);
@files = map { $_ = $dirname.'/'.$_; } (sort @files);
foreach my $f (@files) {
INFO "Reading additional config from $f";
my $extra = munin_readconfig_raw ($f);
# let the new values overwrite what we already have
$config = munin_overwrite($config, $extra);
}
}
# Some important defaults before we return...
$config->{'dropdownlimit'} ||= $Munin::Common::Defaults::DROPDOWNLIMIT;
$config->{'rundir'} ||= $Munin::Common::Defaults::MUNIN_STATEDIR;
$config->{'dbdir'} ||= $Munin::Common::Defaults::MUNIN_DBDIR;
$config->{'logdir'} ||= $Munin::Common::Defaults::MUNIN_LOGDIR;
$config->{'tmpldir'} ||= "$Munin::Common::Defaults::MUNIN_CONFDIR/templates/";
$config->{'staticdir'} ||= "$Munin::Common::Defaults::MUNIN_CONFDIR/static/";
$config->{'htmldir'} ||= $Munin::Common::Defaults::MUNIN_HTMLDIR;
$config->{'spooldir'} ||= $Munin::Common::Defaults::MUNIN_SPOOLDIR;
$config->{'#%#parent'} = undef;
$config->{'#%#name'} = "root";
return $config;
}
sub munin_get_html_filename {
# Actually only used in M::M::HTMLOld
my $hash = shift;
my $loc = munin_get_node_loc ($hash);
my $ret = munin_get ($hash, 'htmldir');
my $plugin = "index";
# Sanitise
$ret =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g;
$hash =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g;
@$loc = map {
my $l = $_;
$l =~ s/\//_/g;
$l =~ s/^\./_/g;
$l;
} @$loc;
if (defined $hash->{'graph_title'} and !munin_has_subservices ($hash)) {
$plugin = pop @$loc or return;
}
if (@$loc) { # The rest is used as directory names...
$ret .= "/" . join ('/', @$loc);
}
return "$ret/$plugin.html";
}
sub munin_get_picture_filename {
my $hash = shift;
my $scale = shift;
my $sum = shift;
my $loc = munin_get_picture_loc ($hash);
my $ret = munin_get ($hash, 'htmldir');
# Sanitise
$ret =~ s/[^\w_\/"'\[\]\(\)+=-]\./_/g;
$hash =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g;
$scale =~ s/[^\w_\/"'\[\]\(\)+=-]/_/g;
@$loc = map {
my $l = $_;
$l =~ s/\//_/g;
$l =~ s/^\./_/g;
$l;
} @$loc;
my $plugin = pop @$loc or return;
my $node = pop @$loc or return;
if (@$loc) { # The rest is used as directory names...
$ret .= "/" . join ('/', @$loc);
}
if (defined $sum and $sum) {
return "$ret/$node/$plugin-$scale-sum.png";
} elsif (defined $scale) {
return "$ret/$node/$plugin-$scale.png";
} else {
return "$ret/$node/$plugin.png";
}
}
sub munin_path_to_loc
{
my $path = shift;
my $result = undef;
if ($path =~ /^\s*([^:]+):(\S+)\s*$/) {
my ($leftstring, $rightstring) = ($1, $2);
my @leftarr = split (/;/, $leftstring);
my @rightarr = split (/\./, $rightstring);
$result = [@leftarr, @rightarr];
} elsif ($path =~ /^\s*([^;:\.]+)\s*$/) {
$result = [$1];
} elsif ($path =~ /^\s*(.+)\.([^\.:;]+)$/) {
my ($leftstring, $rightstring) = ($1, $2);
my @leftarr = split (/;/, $leftstring);
my @rightarr = split (/\./, $rightstring);
$result = [@leftarr, @rightarr];
} elsif ($path =~ /^\s*(\S+)\s*$/) {
my @leftarr = split (/;/, $1);
$result = [@leftarr];
} else {
ERROR "[ERROR] munin_path_to_loc: Malformatted variable path \"$path\".";
}
if (!defined $result) {
ERROR "[ERROR] munin_path_to_loc: Failed converting \"$path\".";
}
return $result;
}
sub munin_get_keypath {
my $hash = shift;
my $asfile = shift || '';
my @group = ();
my $host = 0;
my @service = ();
my $i = $hash;
while (ref ($i) eq "HASH") {
# Not sure when a #%#name node can go missing
my $name = $i->{'#%#name'} || '*BUG*';
goto gotoparent if $name eq '*BUG*';
last if $name eq 'root';
if ($host) {
# Into group land now
unshift(@group,$name);
} else {
# In service land, working towards host.
# If i or my parent has a graph_title we're still working with services
if (defined $i->{'#%#parent'}{graph_title} or defined $i->{graph_title}) {
$name =~ s/-/_/g; # can't handle dashes in service or below
unshift(@service,$name);
} else {
$host = 1;
unshift(@group,$name);
}
}
gotoparent:
$i=$i->{'#%#parent'};
}
if ($asfile) {
return (shift @group).'/'.join('/',@group).'-'.join('-',@service);
} else {
return join(';',@group).':'.join('.',@service);
}
}
sub munin_get_filename {
my $hash = shift;
my $loc = munin_get_keypath ($hash,1);
my $ret = munin_get ($hash, "dbdir");
if (!defined $loc or !defined $ret) {
return;
}
return ($ret . "/$loc-" . lc substr (munin_get($hash, "type", "GAUGE"), 0,1). ".rrd");
}
sub munin_get_bool
{
my $hash = shift;
my $field = shift;
my $default = shift;
my $ans = munin_get ($hash, $field, $default);
return if not defined $ans;
if ($ans =~ /^yes$/i or
$ans =~ /^true$/i or
$ans =~ /^on$/i or
$ans =~ /^enable$/i or
$ans =~ /^enabled$/i
) {
return 1;
} elsif ($ans =~ /^no$/i or
$ans =~ /^false$/i or
$ans =~ /^off$/i or
$ans =~ /^disable$/i or
$ans =~ /^disabled$/i
) {
return 0;
} elsif ($ans !~ /\D/) {
return $ans;
} else {
return $default;
}
}
sub munin_get_bool_val
{
my $field = shift;
my $default = shift;
if (!defined $field)
{
if (!defined $default)
{
return 0;
}
else
{
return $default;
}
}
if ($field =~ /^yes$/i or
$field =~ /^true$/i or
$field =~ /^on$/i or
$field =~ /^enable$/i or
$field =~ /^enabled$/i
)
{
return 1;
}
elsif ($field =~ /^no$/i or
$field =~ /^false$/i or
$field =~ /^off$/i or
$field =~ /^disable$/i or
$field =~ /^disabled$/i
)
{
return 0;
}
elsif ($field !~ /\D/)
{
return $field;
}
else
{
return;
}
}
sub munin_get
{
my ($hash, $field, $default) = @_;
# Iterate to top if needed
do {
return $default if (ref ($hash) ne "HASH");
my $hash_field = $hash->{$field};
return $hash_field if (defined $hash_field && ref($hash_field) ne "HASH");
# Go up
$hash = $hash->{'#%#parent'};
} while (defined $hash);
return $default;
}
sub munin_copy_node_toloc
{
my $from = shift;
my $to = shift;
my $loc = shift;
return unless defined $from and defined $to and defined $loc;
if (ref ($from) eq "HASH") {
foreach my $key (keys %$from) {
next if substr($key,0,3) eq '#%#';
if (ref ($from->{$key}) eq "HASH") {
munin_copy_node_toloc ($from->{$key}, $to, [@$loc, $key]);
} else {
munin_set_var_loc ($to, [@$loc, $key], $from->{$key});
}
}
} else {
$to = $from;
}
return $to;
}
sub munin_copy_node
{
my $from = shift;
my $to = shift;
if (ref ($from) eq "HASH") {
foreach my $key (keys %$from) {
if (ref ($from->{$key}) eq "HASH") {
# Easier to do with the other copy function
munin_copy_node_toloc ($from->{$key}, $to, [$key]);
} else {
munin_set_var_loc ($to, [$key], $from->{$key});
}
}
} else {
$to = $from;
}
return $to;
}
sub munin_node_status
{
my ($config, $limits, $domain, $node, $check_draw) = @_;
my $state = "ok";
return unless defined $config->{domain}->{$domain}->{node}->{$node};
my $snode = $config->{domain}->{$domain}->{node}->{$node};
foreach my $service (keys %{$snode})
{
my $fres = munin_service_status ($config, $limits, $domain, $node, $service, $check_draw);
if (defined $fres)
{
if ($fres eq "critical")
{
$state = $fres;
last;
}
elsif ($fres eq "warning")
{
$state = $fres;
}
}
}
return $state;
}
sub munin_category_status {
my $hash = shift || return;
my $limits = shift || return;
my $category = shift || return;
my $check_draw = 1;
my $state = "ok";
return unless (defined $hash and ref ($hash) eq "HASH");
foreach my $service (@{munin_get_children ($hash)}) {
next if (!defined $service or ref ($service) ne "HASH");
next if (!defined $service->{'graph_title'});
next if ($category ne munin_get ($service, "graph_category", "other"));
next if ($check_draw and not munin_get_bool ($service, "graph", 1));
my $fres = munin_service_status ($service, $limits, $check_draw);
if (defined $fres) {
if ($fres eq "critical") {
$state = $fres;
last;
} elsif ($fres eq "warning") {
$state = $fres;
} elsif ($fres eq "unknown" and $state eq "ok") {
$state = $fres;
}
}
}
return $state;
}
sub munin_service_status {
my ($config, $limits, $check_draw) = @_;
my $state = "ok";
return unless defined $config;
for my $fieldnode (@{munin_find_field ($config, "label")}) {
my $field = munin_get_node_name ($fieldnode);
my $fres = munin_field_status ($fieldnode, $limits, $check_draw);
if (defined $fres) {
if ($fres eq "critical") {
$state = $fres;
last;
} elsif ($fres eq "warning") {
$state = $fres;
}
}
}
return $state;
}
sub munin_field_status {
my ($hash, $limits, $check_draw) = @_;
my $state = "ok";
# Return undef if nagios is turned off, or the field doesn't have any limits
if ((!defined munin_get ($hash, "warning", undef)) and (!defined munin_get ($hash, "critical"))) {
return;
}
if (!defined $check_draw or !$check_draw or munin_draw_field ($hash)) {
my $loc = munin_get_node_loc ($hash);
my $node = munin_get_node ($limits, $loc);
return $node->{"state"} || "ok";
}
return $state;
}
sub munin_graph_column_headers
{
my ($config, $domain, $node, $serv) = @_;
my $ret = 0;
my @fields = ();
foreach my $field (keys %{$config->{domain}->{$domain}->{node}->{$node}->{client}->{$serv}})
{
if ($field =~ /^([^\.]+)\.negative$/ and munin_draw_field ($config->{domain}->{$domain}->{node}->{$node}, $serv, $1))
{
return 1;
}
elsif ($field =~ /^([^\.]+)\.label$/ and munin_draw_field ($config->{domain}->{$domain}->{node}->{$node}, $serv, $1))
{
push @fields, $1;
}
}
return 1 if (munin_get_max_label_length ($config->{'domain'}->{$domain}->{'node'}->{$node}, $config, $domain, $node, $serv, \@fields) > 20);
return $ret;
}
sub munin_get_max_label_length
{
my $service = shift;
my $order = shift;
my $result = 0;
my $tot = munin_get ($service, "graph_total");
for my $field (@$order) {
my $path = undef;
(my $f = $field) =~ s/=.+//;
next if (!munin_get_bool ($service->{$f}, "process", 1));
next if (munin_get_bool ($service->{$f}, "skipdraw", 0));
next if (!munin_get_bool ($service->{$f}, "graph", 1));
my $len = length (munin_get ($service->{$f}, "label") || $f);
if ($result < $len) {
$result = $len;
}
}
if (defined $tot and length $tot > $result) {
$result = length $tot;
}
return $result;
}
sub munin_get_field_order
{
my $hash = shift;
my $result = [];
return if !defined $hash or ref($hash) ne "HASH";
my $order = munin_get ($hash, "graph_order");
if (defined $hash->{graph_sources}) {
foreach my $gs (split /\s+/, $hash->{'graph_sources'}) {
push (@$result, "-".$gs);
}
}
if (defined $order) {
push (@$result, split /\s+/, $order);
}
for my $fieldnode (@{munin_find_field ($hash, "label")}) {
my $fieldname = munin_get_node_name ($fieldnode);
push @$result,$fieldname
if !grep m[^\Q$fieldname\E(?:=|$)], @$result;
}
for my $fieldnode (@{munin_find_field ($hash, "stack")}) {
my $fieldname = munin_get_node_name ($fieldnode);
push @$result,$fieldname
if !grep m[^\Q$fieldname\E(?:=|$)], @$result;;
}
# We have seen some occurances of redundance in the graph_order
# due to plugin bugs and so on. This make process_service
# generate rrd commands with multiple definitions of the same
# data. SO: Make sure there is no redundance in the order.
my %seen = ();
my $nresult = [];
for my $field (@$result) {
next if exists($seen{$field});
push @$nresult, $field;
$seen{$field}=1;
}
return $nresult;
}
sub munin_get_rrd_filename {
my $field = shift;
my $path = shift;
my $result = undef;
# Bail out on bad input data
return if !defined $field or ref ($field) ne "HASH";
# If the field has a .filename setting, use it
if ($result = munin_get ($field, "filename")) {
return $result;
}
# Handle custom paths (used in .sum, .stack, graph_order, et al)
if (defined $path and length $path) {
my $sourcenode = munin_get_node_partialpath ($field, $path);
$result = munin_get_filename ($sourcenode);
for my $f (@COPY_FIELDS) {
if (not exists $field->{$f} and exists $sourcenode->{$f}) {
DEBUG "DEBUG: Copying $f...\n";
munin_set_var_loc ($field, [$f], $sourcenode->{$f});
}
}
} else {
$result = munin_get_filename ($field);
}
return $result;
}
sub munin_mkdir_p {
my ($dirname, $umask) = @_;
eval {
mkpath($dirname, 0, $umask);
};
return if $EVAL_ERROR;
return 1;
}
sub exit_if_run_by_super_user {
if ($EFFECTIVE_USER_ID == 0) {
print qq{This program will easily break if you run it as root as you are
trying now. Please run it as user '$Munin::Common::Defaults::MUNIN_USER'. The correct 'su' command
on many systems is 'su - munin --shell=/bin/bash'
Aborting.
};
exit 1;
}
}
sub print_version_and_exit {
print qq{munin version $Munin::Common::Defaults::MUNIN_VERSION.
Copyright (C) 2002-2009 Jimmy Olsen, Audun Ytterdal, Tore Andersson, Kjell-Magne Øierud, Nicolai Langfeldt, Linpro AS, Redpill Linpro AS and others.
This is free software released under the GNU General Public
License. There is NO warranty; not even for MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. For details, please refer to the file
COPYING that is included with this software or refer to
http://www.fsf.org/licensing/licenses/gpl.txt
};
exit 0;
}
sub look_for_child {
# wait for child process in blocking or non-blocking mode.
my ($block) = @_;
my $pid;
if ($block) {
$pid = waitpid(-1, 0);
} else {
$pid = waitpid(-1, WNOHANG);
if ($pid == 0) {
return 0;
}
}
if ($pid < 0) {
ERROR "[ERROR] Unexpectedly ran out of children: $!";
croak "[ERROR] Ran out of children: $!\n";
}
if ($? != 0) {
WARN "[WARNING] Child $pid failed: " . ($? << 8) .
"(signal " . ($? & 0xff) . ")";
}
return 1;
}
sub wait_for_remaining_children {
my ($running) = @_;
while ($running > 0) {
look_for_child("block");
--$running;
}
return $running;
}
sub munin_has_subservices {
my ($hash) = @_;
return 0 unless defined $hash;
# Only services (which again require graph_title) can have subservices
return 0 unless defined $hash->{'graph_title'};
if (!defined $hash->{'#%#has_subservices'}) {
$hash->{'#%#has_subservices'} = scalar (grep $_, map { ref($hash->{$_}) eq "HASH" and $_ ne '#%#parent' and defined $hash->{$_}->{'graph_title'} ? 1 : undef } keys %$hash);
}
return $hash->{'#%#has_subservices'};
}
sub munin_get_host_path_from_string {
# splits a host definition, as used in the config, into a group array and a host name
my $key = shift;
my (@groups) = split(';', $key);
my $host = pop(@groups);
if(scalar @groups > 0){
} else {
my @groups = split('.', $key);
if(scalar @groups > 1){
@groups = ($groups[0]);
}
}
return (\@groups, $host);
}
1;
__END__
=head1 NAME
Munin::Master::Utils - Exports a lot of utility functions.
=head1 SYNOPSIS
use Munin::Master::Utils;
=head1 SUBROUTINES
=over
=item B<munin_category_status>
Gets current status of a category.
Parameters:
- $hash: A ref to the hash node whose children to check
- $limits: A ref to the root node of the limits tree
- $category: The category to review
- $check_draw: [optional] Ignore undrawn fields
Returns:
- Success: The status of the field
- Failure: undef
=item B<munin_readconfig_base>
Read configuration file, include dir files, and initialize important
default values that are optional.
Parameters:
- $file: munin.conf filename. If omitted, default filename is used.
Returns:
- Success: The $config hash (also cached in module)
=item B<munin_copy_node>
Copy hash node.
Parameters:
- $from: Hash node to copy
- $to: Where to copy it to
Returns:
- Success: $to
- Failure: undef
=item B<munin_copy_node_toloc>
Copy hash node at.
Parameters:
- $from: Hash node to copy
- $to: Where to copy it to
- $loc: Path to node under $to
Returns:
- Success: $to
- Failure: undef
=item B<munin_createlock>
=item B<munin_delete>
=item B<munin_draw_field>
Check whether a field will be visible in the graph or not.
Parameters:
- $hash: A ref to the hash node for the field
Returns:
- Success: Boolean; true if field will be graphed, false if not
- Failure: undef
=item B<munin_field_status>
Gets current status of a field.
Parameters:
- $hash: A ref to the field hash node
- $limits: A ref to the root node of the limits tree
- $check_draw: [optional] Ignore undrawn fields
Returns:
- Success: The status of the field
- Failure: undef
=item B<munin_find_field>
Search a hash to find hash nodes with $field defined.
Parameters:
- $hash: A hash ref to search
- $field: The name of the field to search for, or a regex
- $avoid: [optional] Stop traversing further down if this field is found
Returns:
- Success: A ref to an array of the hash nodes containing $field.
- Failure: undef
=item B<munin_get>
Get variable.
Parameters:
- $hash: Ref to hash node
- $field: Name of field to get
- $default: [optional] Value to return if $field isn't set
Returns:
- Success: field contents
- Failure: $default if defined, else undef
=item B<munin_get_bool>
Get boolean variable.
Parameters:
- $hash: Ref to hash node
- $field: Name of field to get
- $default: [optional] Value to return if $field isn't set
Returns:
- Success: 1 or 0 (true or false)
- Failure: $default if defined, else undef
=item B<munin_get_bool_val>
=item B<munin_get_children>
Get all child hash nodes.
Parameters:
- $hash: A hash ref to the parent node
Returns:
- Success: A ref to an array of the child nodes
- Failure: undef
=item B<munin_get_field_order>
Get the field order in a graph.
Parameters:
- $hash: A hash ref to the service
Returns:
- Success: A ref to an array of the field names
- Failure: undef
=item B<munin_get_filename>
Get rrd filename for a field, without any bells or whistles. Used by
munin-update to figure out which file to update.
Parameters:
- $hash: Ref to hash field
Returns:
- Success: Full path to rrd file
- Failure: undef
=item B<munin_get_html_filename>
Get the full path-name of an html file.
Parameters:
- $hash: A ref to the service hash node
Returns:
- Success: The file name with full path
- Failure: undef
=item B<munin_get_max_label_length>
Get the length of the longest label in a graph.
Parameters:
- $hash: the graph in question
- $order: A ref to an array of fields (graph_order)
Returns:
- Success: The length of the longest label in the graph
- Failure: undef
=item B<munin_get_node>
Gets a node by loc.
Parameters:
- $hash: A ref to the hash to set the variable in
- $loc: A ref to an array with the full path of the node
Returns:
- Success: The node ref found by $loc
- Failure: undef
=item B<munin_get_node_loc>
Get location array for hash node.
Parameters:
- $hash: A ref to the node
Returns:
- Success: Ref to an array with the full path of the variable
- Failure: undef
=item B<munin_get_node_name>
Return the name of the hash node supplied.
Parameters:
- $hash: A ref to the hash node
Returns:
- Success: The name of the node
=item B<munin_get_node_partialpath>
Gets a node from a partial path.
Parameters:
- $hash: A ref to the "current" location in the hash tree
- $var: A path string with relative location (from the $hash).
Returns:
- Success: The node
- Failure: undef
=item B<munin_get_parent>
Get parent node of a hash.
Parameters:
- $hash: A ref to the node
Returns:
- Success: Ref to an parent
- Failure: undef
=item B<munin_get_parent_name>
Return the name of the parent of the hash node supplied
Parameters:
- $hash: A ref to the hash node
Returns:
- Success: The name of the parent node
- Failure: If no parent node exists, "none" is returned.
=item B<munin_get_picture_filename>
Get the full path+name of a picture file.
Parameters:
- $hash: A ref to the service hash node
- $scale: [optional] The scale (day, week, year, month)
- $sum: [optional] Boolean value, whether it's a sum graph or not.
Returns:
- Success: The file name with full path
- Failure: undef
=item B<munin_get_picture_loc>
Get location array for hash node for picture purposes. Differs from
munin_get_node_loc in that it honors #%#origin metadata
Parameters:
- $hash: A ref to the node
Returns:
- Success: Ref to an array with the full path of the variable
- Failure: undef
=item B<munin_get_root_node>
Get the root node of the hash tree.
Parameters:
- $hash: A hash node to traverse up from
Returns:
- Success: A ref to the root hash node
- Failure: undef
=item B<munin_get_rrd_filename>
Get the name of the rrd file corresponding to a field. Checks for lots
of bells and whistles. This function is the correct one to use when
figuring out where to fetch data from.
Parameters:
- $field: The hash object of the field
- $path: [optional] The path to the field (as given in graph_order/sum/stack/et al)
Returns:
- Success: A string with the filename of the rrd file
- Failure: undef
=item B<munin_get_separated_node>
Copy a node to a separate node without "specials".
Parameters:
- $hash: The node to copy
Returns:
- Success: A ref to a new node without "#%#"-fields
- Failure: undef
=item B<munin_get_var_path>
=item B<munin_getlock>
=item B<munin_graph_column_headers>
=item B<munin_has_subservices>
munin_has_subservices($hash);
Checks whether the service represented by $hash has subservices (multigraph),
and returns the result.
Parameters:
- $hash: Hash reference pointing to a service
Returns:
- true: if the hash is indeed a service, and said service has got subservices
- false: otherwise
=item B<munin_mkdir_p>
munin_mkdir_p('/a/path/', oct('777'));
Make a directory and recursively any nonexistent directory in the path
to it.
=item B<munin_node_status>
=item B<munin_nscasend>
=item B<munin_overwrite>
Take contents of one config-namespace and replace/insert the instances
needed.
=item B<munin_parse_config>
=item B<munin_path_to_loc>
Returns a loc array from a path string.
Parameters:
- $path: A path string
Returns:
- Success: A ref to an array with the loc
- Failure: undef
=item B<munin_readconfig_part>
Read a partial configuration
Parameters:
- $what: name of the part that should be loaded (datafile or limits)
Returns:
- Success: a $config with the $specified part, but overwritten by $config
=item B<munin_removelock>
=item B<munin_runlock>
=item B<munin_service_status>
Gets current status of a service.
Parameters:
- $hash: A ref to the field hash node
- $limits: A ref to the root node of the limits tree
- $check_draw: [optional] Ignore undrawn fields
Returns:
- Success: The status of the field
- Failure: undef
=item B<munin_set>
Sets a variable in a hash.
Parameters:
- $hash: A ref to the hash to set the variable in
- $var: The name of the variable
- $val: The value to set the variable to
Returns:
- Success: The $hash we were handed
- Failure: undef
=item B<munin_set_var_loc>
Sets a variable in a hash.
Parameters:
- $hash: A ref to the hash to set the variable in
- $loc: A ref to an array with the full path of the variable
- $val: The value to set the variable to
Returns:
- Success: The $hash we were handed
- Failure: undef
=item B<munin_set_var_path>
Sets a variable in a hash.
Parameters:
- $hash: A ref to the hash to set the variable in
- $var: A string with the full path of the variable
- $val: The value to set the variable to
Returns:
- Success: The $hash we were handed
- Failure: The $hash we were handed
=item B<munin_writeconfig>
=item B<munin_writeconfig_loop>
=back
=head1 COPYING
Copyright (C) 2003-2007 Jimmy Olsen, Audun Ytterdal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 dated June,
1991.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=cut
# vim: syntax=perl ts=8