3.79 KB
# Copyright (c) 2017 Mathieu Roy <>
#   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; either version 2 of the License, or
#   (at your option) any later version.
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
#   USA
# simple clone of munin-cron that actually handle mergedb and run,

use strict;
use Fcntl qw(:flock);
use Munin::Master::Utils;
use Sys::Syslog; 

my $user = "munin";  
our $munin_bin = "/usr/share/munin";
our $local_munin_bin = "/usr/local/share/munin"; 

# check if we are running with munin user (not with getlogin() because
# su often mess it up) to avoid files created with wrong ownership
die "This should not be started by ".(getpwuid($<))[0]." but $user instead. Exit" unless ((getpwuid($<))[0] eq $user);

# start logging
openlog("munin-cron-plus", "pid", "LOG_DAEMON"); 

# silently forbid concurrent runs to avoid mail spam - but syslog it
# (
open(LOCK, "< $0") or die "Failed to ask lock. Exit";
flock(LOCK, LOCK_EX | LOCK_NB) or 
    syslog("info", "failed to ask lock") &&
    closelog() &&

# identify conf
my $main_conffile = "$Munin::Common::Defaults::MUNIN_CONFDIR/munin.conf"; 
my $merge_conffile = "$Munin::Common::Defaults::MUNIN_CONFDIR/munin-merge.conf";

# if we do some mergin, we actually are interested in general conf
my @restrict_to_host;
if (-e $merge_conffile) {
    # barbarian check, I'd gladly use a nice better function from
    # the munin library, but right now it suits my needs
    open FILE, "<", $main_conffile or die "open: $!\n";
    while (<FILE>) {
	next if /^[[:space:]]*#/; # comment
	next if /^[[:space:]]*$/; # empty line
	s/\s//; # remove blank space
	next unless s/^\[//; # node are between [ ]
	next unless s/\]$//;
	my @entities;
	@entities = split(";", $_); # take the last element after ;
	push(@restrict_to_host, "--host", $entities[-1]); 

# subs
sub run {
    # bin is always first argument
    my ($bin, @request) = @_;

    # local bin always takes precedence
    my $fullbin = $main::munin_bin."/$bin";
    $fullbin = $main::local_munin_bin."/$bin" if -e $main::local_munin_bin."/$bin";

    # bin still do not exists
    unless (-e $fullbin) {
	syslog("info", "no valid executable for $bin, skipping");
	return 1;

    # otherwise, log, time and run
    syslog("info", "$bin ".join(" ", @request));
    $main::runtime{$bin} = time();
    system($fullbin, @request);
    $main::runtime{$bin} = (time() - $main::runtime{$bin});

# run
our %runtime;
$runtime{'main'} = time();

# get data from nodes
run("munin-update", @ARGV);

# eval limits
run("munin-limits", @ARGV);

# merge db, if there is at least a conffile
if (-e $merge_conffile) {
    # take no arguments

# build html
# It is a noop if html_strategy is "cgi"
run("munin-html", @ARGV);

# build graph 
# It is a noop if graph_strategy is "cgi"
# extra args: --cron and --host
run("munin-graph", "--cron", @restrict_to_host, @ARGV);

# exit with time per process
my $runtimelist;
for (sort keys %runtime) {
    next if $_ eq 'main';
    $runtimelist .= " ".$_.": ".$runtime{$_}."s;";
syslog("info", "done in ".(time() - $runtime{'main'})."s (includes$runtimelist)");