| 1 |
#!/usr/bin/perl |
|---|
| 2 |
|
|---|
| 3 |
BEGIN { |
|---|
| 4 |
(my $dir = $0) =~ s/\/?[^\/]+$//; |
|---|
| 5 |
eval "use lib '$dir/lib';"; |
|---|
| 6 |
die $@ if($@); |
|---|
| 7 |
}; |
|---|
| 8 |
|
|---|
| 9 |
use strict; |
|---|
| 10 |
use Time::HiRes qw( gettimeofday tv_interval sleep ); |
|---|
| 11 |
use POSIX qw( setsid ); |
|---|
| 12 |
use Getopt::Long; |
|---|
| 13 |
use Data::Dumper; |
|---|
| 14 |
use vars qw($config_file $debug $status_file $interface $port $config $status); |
|---|
| 15 |
|
|---|
| 16 |
use Resmon::Config; |
|---|
| 17 |
use Resmon::ExtComm; |
|---|
| 18 |
use Resmon::Status; |
|---|
| 19 |
use Resmon::Module; |
|---|
| 20 |
|
|---|
| 21 |
GetOptions( |
|---|
| 22 |
"i=s" => \$interface, |
|---|
| 23 |
"p=i" => \$port, |
|---|
| 24 |
"c=s" => \$config_file, |
|---|
| 25 |
"d" => \$debug, |
|---|
| 26 |
"f=s" => \$status_file, |
|---|
| 27 |
); |
|---|
| 28 |
|
|---|
| 29 |
$config_file ||= "$0.conf"; |
|---|
| 30 |
die "Cannot open configuration file: $config_file" unless (-r $config_file); |
|---|
| 31 |
|
|---|
| 32 |
sub configure { |
|---|
| 33 |
$config = Resmon::Config->new($config_file); |
|---|
| 34 |
$config->{statusfile} = $status_file if($status_file); |
|---|
| 35 |
$config->{port} = $port if($port); |
|---|
| 36 |
$config->{interface} = $interface if($interface); |
|---|
| 37 |
} |
|---|
| 38 |
|
|---|
| 39 |
sub reconfigure { |
|---|
| 40 |
my $modstatus = ""; |
|---|
| 41 |
print STDERR "Reloading modules...\n"; |
|---|
| 42 |
my $modules = $config->{Module}; |
|---|
| 43 |
while ( my ($key, $value) = each(%$modules) ) { |
|---|
| 44 |
my $mod = $value->[0]; # Only need the first of each module |
|---|
| 45 |
# Called this way rather than $mod->reload_module() in order to deal |
|---|
| 46 |
# with modules that failed to load on startup and won't have a |
|---|
| 47 |
# reload_module method. |
|---|
| 48 |
my $errs = Resmon::Module::reload_module($mod); |
|---|
| 49 |
if ($errs) { |
|---|
| 50 |
my $modname = ref($mod) || $mod; |
|---|
| 51 |
$modname =~ s/Resmon::Module:://; |
|---|
| 52 |
$modstatus .= "$modname "; |
|---|
| 53 |
print STDERR " Failed to reload module $modname\n"; |
|---|
| 54 |
print STDERR $errs; |
|---|
| 55 |
print STDERR " This module is no longer available.\n"; |
|---|
| 56 |
} |
|---|
| 57 |
} |
|---|
| 58 |
print STDERR "Reloading configuration...\n"; |
|---|
| 59 |
eval { configure(); }; |
|---|
| 60 |
if ($@) { |
|---|
| 61 |
# The config object is recreated every time we reload, so we shouldn't |
|---|
| 62 |
# need to reset this BAD value to empty on a successful load. |
|---|
| 63 |
$config->{'configstatus'} = "BAD"; |
|---|
| 64 |
print STDERR " Failed to reload: "; |
|---|
| 65 |
print STDERR $@; |
|---|
| 66 |
print STDERR " Continuing with old configuration\n"; |
|---|
| 67 |
} |
|---|
| 68 |
|
|---|
| 69 |
$config->{'modstatus'} = $modstatus; |
|---|
| 70 |
$status->purge($config); |
|---|
| 71 |
} |
|---|
| 72 |
|
|---|
| 73 |
$SIG{'HUP'} = \&reconfigure; |
|---|
| 74 |
configure(); |
|---|
| 75 |
|
|---|
| 76 |
my $sigint = 0; |
|---|
| 77 |
sub sigint_handler { $sigint = 1; } |
|---|
| 78 |
$SIG{'INT'} = \&sigint_handler; |
|---|
| 79 |
|
|---|
| 80 |
my $rmlast = undef; |
|---|
| 81 |
sub wait_interval { |
|---|
| 82 |
$rmlast = [gettimeofday] unless defined($rmlast); |
|---|
| 83 |
my $elapsed = $config->{interval} - tv_interval($rmlast); |
|---|
| 84 |
if($elapsed > 0) { |
|---|
| 85 |
sleep($elapsed); |
|---|
| 86 |
} |
|---|
| 87 |
$rmlast = [gettimeofday]; |
|---|
| 88 |
} |
|---|
| 89 |
|
|---|
| 90 |
unless($debug) { |
|---|
| 91 |
fork && exit; |
|---|
| 92 |
setsid; |
|---|
| 93 |
close(STDIN); |
|---|
| 94 |
close(STDOUT); |
|---|
| 95 |
close(STDERR); |
|---|
| 96 |
fork && exit; |
|---|
| 97 |
} |
|---|
| 98 |
|
|---|
| 99 |
my $list = []; |
|---|
| 100 |
$status = Resmon::Status->new($config->{statusfile}); |
|---|
| 101 |
$status->open(); |
|---|
| 102 |
$status->serve_http_on($config->{interface}, $config->{port}) |
|---|
| 103 |
if($config->{port}); |
|---|
| 104 |
|
|---|
| 105 |
while(1) { |
|---|
| 106 |
while(my($module_name, $mod_configs) = each %{$config->{Module}}) { |
|---|
| 107 |
my $coderef = undef; |
|---|
| 108 |
eval { $coderef = Resmon::Module::fetch_monitor($module_name); }; |
|---|
| 109 |
foreach my $monobj (@$mod_configs) { |
|---|
| 110 |
my $check_rv = 'BAD', |
|---|
| 111 |
my $check_mess = 'no data'; |
|---|
| 112 |
my $starttime = [gettimeofday]; |
|---|
| 113 |
if($coderef) { |
|---|
| 114 |
eval { ($check_rv, $check_mess) = $coderef->($monobj); }; |
|---|
| 115 |
} else { |
|---|
| 116 |
eval { ($check_rv, $check_mess) = $monobj->handler(); }; |
|---|
| 117 |
} |
|---|
| 118 |
my $checkstat = $@; |
|---|
| 119 |
my $confighash = {}; |
|---|
| 120 |
eval { $confighash = $monobj->config_as_hash(); }; |
|---|
| 121 |
my $results = { |
|---|
| 122 |
configuration => $confighash, |
|---|
| 123 |
last_runtime_seconds => sprintf("%.6f", tv_interval($starttime)), |
|---|
| 124 |
}; |
|---|
| 125 |
if($checkstat) { |
|---|
| 126 |
$results->{state} = 'BAD'; |
|---|
| 127 |
$results->{message} = "Bad module or problem running handler code."; |
|---|
| 128 |
} else { |
|---|
| 129 |
$results->{state} = $check_rv; |
|---|
| 130 |
$results->{message} = $check_mess; |
|---|
| 131 |
} |
|---|
| 132 |
$status->store($module_name,$monobj->{'object'}, $results); |
|---|
| 133 |
} |
|---|
| 134 |
} |
|---|
| 135 |
$status->close(); |
|---|
| 136 |
die "Exiting.\n" if($sigint); |
|---|
| 137 |
wait_interval(); |
|---|
| 138 |
die "Exiting.\n" if($sigint); |
|---|
| 139 |
print "\n---- ".localtime(time)."----------\n" |
|---|
| 140 |
unless $status->open(); |
|---|
| 141 |
} |
|---|
| 142 |
|
|---|