mirror of
https://github.com/webmin/webmin.git
synced 2025-07-21 23:40:34 +00:00
715 lines
18 KiB
Perl
Executable File
715 lines
18 KiB
Perl
Executable File
# status-lib.pl
|
|
# Functions for getting the status of services
|
|
|
|
BEGIN { push(@INC, ".."); };
|
|
use WebminCore;
|
|
&init_config();
|
|
%access = &get_module_acl();
|
|
use Socket;
|
|
|
|
# Wrapper command for cron job
|
|
$cron_cmd = "$module_config_directory/monitor.pl";
|
|
$full_cron_cmd = $cron_cmd." >/dev/null 2>&1";
|
|
|
|
# Config directory for monitors
|
|
$services_dir = "$module_config_directory/services";
|
|
|
|
# File storing last status of each monitor
|
|
$oldstatus_file = "$module_config_directory/oldstatus";
|
|
if (!-r $oldstatus_file) {
|
|
$oldstatus_file = "$module_var_directory/oldstatus";
|
|
}
|
|
|
|
# Failure count file for each monitor
|
|
$fails_file = "$module_config_directory/fails";
|
|
if (!-r $fails_file) {
|
|
$fails_file = "$module_var_directory/fails";
|
|
}
|
|
|
|
# Last email sent for each monitor
|
|
$lastsent_file = "$module_config_directory/lastsent";
|
|
if (!-r $lastsent_file) {
|
|
$lastsent_file = "$module_var_directory/lastsent";
|
|
}
|
|
|
|
# Directory of historic results for each monitor
|
|
$history_dir = "$module_config_directory/history";
|
|
if (!-d $history_dir) {
|
|
$history_dir = "$module_var_directory/history";
|
|
}
|
|
|
|
$templates_dir = "$module_config_directory/templates";
|
|
|
|
%monitor_os_support = ( 'traffic' => { 'os_support' => '*-linux freebsd' },
|
|
);
|
|
|
|
@monitor_statuses = ( 'up', 'down', 'un', 'webmin', 'timed', 'isdown' );
|
|
|
|
$mysql_variant = "mysql";
|
|
if (&foreign_check("mysql")) {
|
|
# Fix MySQL / MariaDB
|
|
&foreign_require("mysql");
|
|
if ($mysql::mysql_version =~ /mariadb/i) {
|
|
$mysql_variant = "mariadb";
|
|
}
|
|
}
|
|
if ($mysql_variant eq "mariadb") {
|
|
$text{'type_mysql'} =~ s/MySQL/MariaDB/g;
|
|
}
|
|
|
|
# list_services()
|
|
# Returns a list of all services this module knows how to get status on.
|
|
# If this is the first time the function is called a default set of services
|
|
# will be setup.
|
|
sub list_services
|
|
{
|
|
my (%mod, @rv);
|
|
if (!-d $services_dir) {
|
|
# setup initial services
|
|
mkdir($module_config_directory, 0700);
|
|
mkdir($services_dir, 0700);
|
|
system("cp $module_root_directory/services/* $services_dir");
|
|
}
|
|
map { $mod{$_}++ } &list_modules();
|
|
opendir(DIR, $services_dir);
|
|
while($f = readdir(DIR)) {
|
|
next if ($f !~ /^(.*)\.serv$/);
|
|
my $serv = &get_service($1);
|
|
next if (!$serv || !$serv->{'type'} || !$serv->{'id'});
|
|
if ($serv->{'default'} && $serv->{'id'} eq 'mysql' &&
|
|
$mysql_variant eq "mariadb") {
|
|
$serv->{'desc'} =~ s/MySQL/MariaDB/g;
|
|
}
|
|
if ($serv->{'depends'}) {
|
|
my $d;
|
|
map { $d++ if (!$mod{$_}) } split(/\s+/, $serv->{'depends'});
|
|
push(@rv, $serv) if (!$d);
|
|
}
|
|
else {
|
|
push(@rv, $serv);
|
|
}
|
|
}
|
|
closedir(DIR);
|
|
return @rv;
|
|
}
|
|
|
|
# get_service(id)
|
|
sub get_service
|
|
{
|
|
my %serv;
|
|
read_file("$services_dir/$_[0].serv", \%serv) || return undef;
|
|
$serv{'fails'} = 1 if (!defined($serv{'fails'}));
|
|
$serv{'_file'} = "$services_dir/$_[0].serv";
|
|
if (!defined($serv{'notify'})) {
|
|
$serv{'notify'} = 'email pager snmp';
|
|
}
|
|
$serv{'remote'} = "*" if (!$serv{'remote'} && !$serv{'groups'});
|
|
return $_[0] ne $serv{'id'} ? undef : \%serv;
|
|
}
|
|
|
|
# save_service(&serv)
|
|
sub save_service
|
|
{
|
|
my ($serv) = @_;
|
|
mkdir($services_dir, 0755) if (!-d $services_dir);
|
|
&lock_file("$services_dir/$serv->{'id'}.serv");
|
|
&write_file("$services_dir/$serv->{'id'}.serv", $serv);
|
|
&unlock_file("$services_dir/$serv->{'id'}.serv");
|
|
}
|
|
|
|
# delete_service(&serv)
|
|
sub delete_service
|
|
{
|
|
my ($serv) = @_;
|
|
&unlink_logged("$services_dir/$serv->{'id'}.serv");
|
|
&unlink_logged("$history_dir/$serv->{'id'}");
|
|
}
|
|
|
|
# expand_remotes(&service)
|
|
# Given a service with direct and group remote hosts, returns a list of the
|
|
# names of all actual hosts (* means local)
|
|
sub expand_remotes
|
|
{
|
|
my @remote;
|
|
push(@remote, split(/\s+/, $_[0]->{'remote'}));
|
|
my @groupnames = split(/\s+/, $_[0]->{'groups'});
|
|
if (@groupnames) {
|
|
&foreign_require("servers");
|
|
my @groups = &servers::list_all_groups();
|
|
foreach my $g (@groupnames) {
|
|
my ($group) = grep { $_->{'name'} eq $g } @groups;
|
|
if ($group) {
|
|
push(@remote, @{$group->{'members'}});
|
|
}
|
|
}
|
|
}
|
|
return &unique(@remote);
|
|
}
|
|
|
|
# service_status(&service, [from-cgi])
|
|
# Gets the status of a service, possibly on another server. If called in
|
|
# an array content, the status of all hosts for this monitor are returned.
|
|
sub service_status
|
|
{
|
|
my $t = $_[0]->{'type'};
|
|
my @rv;
|
|
foreach $r (&expand_remotes($_[0])) {
|
|
my $rv;
|
|
local $main::error_must_die = 1;
|
|
eval {
|
|
local $SIG{'ALRM'} = sub { die "status alarm\n" };
|
|
alarm(60); # wait at most 60 secs for a result
|
|
if ($r ne "*") {
|
|
# Make a remote call to another webmin server
|
|
&remote_error_setup(\&remote_error);
|
|
$remote_error_msg = undef;
|
|
&remote_foreign_require($r, 'status', 'status-lib.pl')
|
|
if (!$done_remote_status{$r}++);
|
|
my $webmindown = $s->{'type'} eq 'alive' ? 0 : -2;
|
|
if ($remote_error_msg) {
|
|
$rv = { 'up' => $webmindown,
|
|
'desc' => "$text{'mon_webmin'} : $remote_error_msg" };
|
|
}
|
|
else {
|
|
my %s = %{$_[0]};
|
|
$s{'remote'} = '*';
|
|
$s{'groups'} = undef;
|
|
($rv) = &remote_foreign_call($r, 'status',
|
|
'service_status', \%s, $_[1]);
|
|
if ($remote_error_msg) {
|
|
$rv = { 'up' => $webmindown, 'desc' =>
|
|
"$text{'mon_webmin'} : $remote_error_msg" };
|
|
}
|
|
}
|
|
}
|
|
elsif ($t =~ /^(\S+)::(\S+)$/) {
|
|
# Call to another module
|
|
my ($mod, $mtype) = ($1, $2);
|
|
&foreign_require($mod, "status_monitor.pl");
|
|
$rv = &foreign_call($mod, "status_monitor_status",
|
|
$mtype, $_[0], $_[1]);
|
|
}
|
|
else {
|
|
# Just include and use the local monitor library
|
|
do "${t}-monitor.pl" if (!$done_monitor{$t}++);
|
|
my $func = "get_${t}_status";
|
|
$rv = &$func($_[0],
|
|
$_[0]->{'clone'} ? $_[0]->{'clone'} : $t,
|
|
$_[1]);
|
|
}
|
|
alarm(0);
|
|
};
|
|
if ($@ =~ /status alarm/) {
|
|
push(@rv, { 'up' => -3,
|
|
'remote' => $r });
|
|
}
|
|
elsif ($@) {
|
|
# A real error happened
|
|
die $@;
|
|
}
|
|
else {
|
|
$rv->{'remote'} = $r;
|
|
push(@rv, $rv);
|
|
}
|
|
}
|
|
return wantarray ? @rv : $rv[0];
|
|
}
|
|
|
|
sub remote_error
|
|
{
|
|
$remote_error_msg = join("", @_);
|
|
}
|
|
|
|
# list_modules()
|
|
# Returns a list of all modules available on this system
|
|
sub list_modules
|
|
{
|
|
return map { $_->{'dir'} } grep { &check_os_support($_) }
|
|
&get_all_module_infos();
|
|
}
|
|
|
|
# list_handlers()
|
|
# Returns a list of the module's monitor type handlers, and those
|
|
# defined in other modules.
|
|
sub list_handlers
|
|
{
|
|
my ($f, @rv);
|
|
opendir(DIR, ".");
|
|
while($f = readdir(DIR)) {
|
|
if ($f =~ /^(\S+)-monitor\.pl$/) {
|
|
my $m = $1;
|
|
my $oss = $monitor_os_support{$m};
|
|
next if ($oss && !&check_os_support($oss));
|
|
push(@rv, [ $m, $text{"type_$m"} ]);
|
|
}
|
|
}
|
|
closedir(DIR);
|
|
foreach my $m (&get_all_module_infos()) {
|
|
my $mdir = defined(&module_root_directory) ?
|
|
&module_root_directory($m->{'dir'}) :
|
|
"$root_directory/$m->{'dir'}";
|
|
if (-r "$mdir/status_monitor.pl" &&
|
|
&check_os_support($m)) {
|
|
&foreign_require($m->{'dir'}, "status_monitor.pl");
|
|
my @mms = &foreign_call($m->{'dir'}, "status_monitor_list");
|
|
push(@rv, map { [ $m->{'dir'}."::".$_->[0], $_->[1] ] } @mms);
|
|
}
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# depends_check(&service, [module]+)
|
|
sub depends_check
|
|
{
|
|
return if ($_[0]->{'id'}); # only check for new services
|
|
if ($_[0]->{'remote'}) {
|
|
# Check on the remote server
|
|
foreach my $m (@_[1..$#_]) {
|
|
&remote_foreign_check($_[0]->{'remote'}, $m, 1) ||
|
|
&error(&text('depends_remote', "<tt>$m</tt>",
|
|
"<tt>$_[0]->{'remote'}</tt>"));
|
|
}
|
|
}
|
|
else {
|
|
# Check on this server
|
|
foreach my $m (@_[1..$#_]) {
|
|
my %minfo = &get_module_info($m);
|
|
%minfo || &error(&text('depends_mod', "<tt>$m</tt>"));
|
|
&check_os_support(\%minfo, undef, undef, 1) ||
|
|
&error(&text('depends_os', "<tt>$minfo{'desc'}</tt>"));
|
|
}
|
|
$_[0]->{'depends'} = join(" ", @_[1..$#_]);
|
|
}
|
|
}
|
|
|
|
# find_named_process(regexp)
|
|
sub find_named_process
|
|
{
|
|
foreach my $p (&proc::list_processes()) {
|
|
$p->{'args'} =~ s/\s.*$//; $p->{'args'} =~ s/[\[\]]//g;
|
|
if ($p->{'args'} =~ /$_[0]/) {
|
|
return $p;
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# smtp_command(handle, command)
|
|
sub smtp_command
|
|
{
|
|
my ($m, $c) = @_;
|
|
print $m $c;
|
|
my $r = <$m>;
|
|
if ($r !~ /^[23]\d+/) {
|
|
&error(&text('sched_esmtpcmd', "<tt>$c</tt>", "<tt>$r</tt>"));
|
|
}
|
|
}
|
|
|
|
# setup_cron_job()
|
|
# Create a cron job based on the module's configuration
|
|
sub setup_cron_job
|
|
{
|
|
&lock_file($cron_cmd);
|
|
&foreign_require("cron");
|
|
my $job;
|
|
foreach my $j (&cron::list_cron_jobs()) {
|
|
$job = $j if ($j->{'user'} eq 'root' &&
|
|
($j->{'command'} eq $cron_cmd ||
|
|
$j->{'command'} eq $full_cron_cmd));
|
|
}
|
|
if ($job) {
|
|
&lock_file(&cron::cron_file($job));
|
|
&cron::delete_cron_job($job);
|
|
&unlock_file(&cron::cron_file($job));
|
|
unlink($cron_cmd);
|
|
}
|
|
if ($config{'sched_mode'}) {
|
|
# Create the program that cron calls
|
|
&cron::create_wrapper($cron_cmd, $module_name, "monitor.pl");
|
|
|
|
# Setup the actual cron job
|
|
my $njob;
|
|
$njob = { 'user' => 'root', 'active' => 1,
|
|
'hours' => '*', 'days' => '*',
|
|
'months' => '*', 'weekdays' => '*',
|
|
'command' => $full_cron_cmd };
|
|
if ($config{'sched_period'} == 0) {
|
|
$njob->{'mins'} = &make_interval(60);
|
|
}
|
|
elsif ($config{'sched_period'} == 1) {
|
|
$njob->{'hours'} = &make_interval(24);
|
|
$njob->{'mins'} = 0;
|
|
}
|
|
elsif ($config{'sched_period'} == 2) {
|
|
$njob->{'days'} = &make_interval(31, 1);
|
|
$njob->{'hours'} = $njob->{'mins'} = 0;
|
|
}
|
|
elsif ($config{'sched_period'} == 3) {
|
|
$njob->{'months'} = &make_interval(12, 1);
|
|
$njob->{'days'} = 1;
|
|
$njob->{'hours'} = $njob->{'mins'} = 0;
|
|
}
|
|
&lock_file(&cron::cron_file($njob));
|
|
&cron::create_cron_job($njob);
|
|
&unlock_file(&cron::cron_file($njob));
|
|
}
|
|
&unlock_file($cron_cmd);
|
|
}
|
|
|
|
# make_interval(length, offset2)
|
|
sub make_interval
|
|
{
|
|
my (@rv, $i);
|
|
for($i=$config{'sched_offset'}+$_[1]; $i<$_[0]; $i+=$config{'sched_int'}) {
|
|
push(@rv,$i);
|
|
}
|
|
return join(",", @rv);
|
|
}
|
|
|
|
# expand_oldstatus(oldstatus, &serv)
|
|
# Converts an old-status string like *=1 foo.com=2 into a hash. If the string
|
|
# contains just one number, it is assumed to be for just the first remote host
|
|
sub expand_oldstatus
|
|
{
|
|
my ($o, $serv) = @_;
|
|
my @remotes = split(/\s+/, $serv->{'remote'});
|
|
if ($o =~ /^\-?(\d+)$/) {
|
|
return { $remotes[0] => $o };
|
|
}
|
|
else {
|
|
my %rv;
|
|
foreach my $hs (split(/\s+/, $o)) {
|
|
my ($h, $s) = split(/=/, $hs);
|
|
$rv{$h} = $s;
|
|
}
|
|
return \%rv;
|
|
}
|
|
}
|
|
|
|
# nice_remotes(&monitor)
|
|
sub nice_remotes
|
|
{
|
|
my ($s) = @_;
|
|
my @remotes = map { $_ eq "*" ? $text{'index_local'}
|
|
: &html_escape($_) }
|
|
split(/\s+/, $s->{'remote'});
|
|
foreach my $g (split(/\s+/, $s->{'groups'})) {
|
|
push(@remotes, &text('index_group', $g));
|
|
}
|
|
return join("<br>", @remotes);
|
|
}
|
|
|
|
sub group_desc
|
|
{
|
|
my ($group) = @_;
|
|
my $mems = scalar(@{$group->{'members'}});
|
|
return $group->{'name'}." (".
|
|
&text($mems == 0 ? 'mon_empty' :
|
|
$mems == 1 ? 'mon_onemem' : 'mon_members', $mems).")";
|
|
}
|
|
|
|
# list_notification_modes()
|
|
# Returns a list of available notification modes (like email, sms, etc..)
|
|
sub list_notification_modes
|
|
{
|
|
my @rv = ( "email" );
|
|
if ($config{'pager_cmd'} && $config{'sched_pager'}) {
|
|
push(@rv, "pager");
|
|
}
|
|
if ($config{'snmp_server'}) {
|
|
my $gotmod = 0;
|
|
eval "use Net::SNMP";
|
|
$gotmod++ if (!$@);
|
|
eval "use SNMP_Session";
|
|
$gotmod++ if (!$@);
|
|
push(@rv, "snmp") if ($gotmod);
|
|
}
|
|
if ($config{'sched_carrier'} && $config{'sched_sms'}) {
|
|
push(@rv, "sms");
|
|
}
|
|
if ($config{'sched_webhook'}) {
|
|
push(@rv, "webhook");
|
|
}
|
|
return @rv;
|
|
}
|
|
|
|
# list_sms_carriers()
|
|
# Returns a list of information about carriers to whom we can send SMS
|
|
sub list_sms_carriers
|
|
{
|
|
return ( { 'id' => 'tmobile',
|
|
'desc' => 'T-Mobile',
|
|
'domain' => 'tmomail.net' },
|
|
{ 'id' => 'cingular',
|
|
'desc' => 'AT&T SMS',
|
|
'domain' => 'txt.att.net' },
|
|
{ 'id' => 'attmms',
|
|
'desc' => 'AT&T MMS',
|
|
'domain' => 'mms.att.net' },
|
|
{ 'id' => 'oldcingular',
|
|
'desc' => 'Cingular',
|
|
'domain' => 'cingularme.com',
|
|
'alpha' => 1 },
|
|
{ 'id' => 'verizon',
|
|
'desc' => 'Verizon',
|
|
'domain' => 'vtext.com' },
|
|
{ 'id' => 'sprint',
|
|
'desc' => 'Sprint PCS',
|
|
'domain' => 'messaging.sprintpcs.com' },
|
|
{ 'id' => 'nextel',
|
|
'desc' => 'Nextel',
|
|
'domain' => 'messaging.nextel.com' },
|
|
{ 'id' => 'alltel',
|
|
'desc' => 'Alltel',
|
|
'domain' => 'message.alltel.com' },
|
|
{ 'id' => 'boost',
|
|
'desc' => 'Boost Mobile',
|
|
'domain' => 'myboostmobile.com' },
|
|
{ 'id' => 'virgin',
|
|
'desc' => 'Virgin Mobile',
|
|
'domain' => 'vmobl.com' },
|
|
{ 'id' => 'cbell',
|
|
'desc' => 'Cincinnati Bell',
|
|
'domain' => 'gocbw.com' },
|
|
{ 'id' => 'tcom',
|
|
'desc' => 'T-COM',
|
|
'domain' => 'sms.t-online.de' },
|
|
{ 'id' => 'vodafone',
|
|
'desc' => 'Vodafone UK',
|
|
'domain' => 'vodafone.net' },
|
|
{ 'id' => 'vodafonejapan',
|
|
'desc' => 'Vodafone Japan',
|
|
'domain' => 't.vodafone.ne.jp' },
|
|
{ 'id' => 'bellcanada',
|
|
'desc' => 'Bell Canada',
|
|
'domain' => 'txt.bellmobility.ca' },
|
|
{ 'id' => 'bellsouth',
|
|
'desc' => 'Bell South',
|
|
'domain' => 'sms.bellsouth.com' },
|
|
{ 'id' => 'cellularone',
|
|
'desc' => 'Cellular One',
|
|
'domain' => 'mobile.celloneusa.com' },
|
|
{ 'id' => 'o2',
|
|
'desc' => 'O2',
|
|
'domain' => 'mmail.co.uk' },
|
|
{ 'id' => 'rogers',
|
|
'desc' => 'Rogers Canada',
|
|
'domain' => 'pcs.rogers.com' },
|
|
{ 'id' => 'skytel',
|
|
'desc' => 'Skytel',
|
|
'domain' => 'skytel.com' },
|
|
{ 'id' => 'telus',
|
|
'desc' => 'Telus Canada',
|
|
'domain' => 'msg.telus.com' },
|
|
{ 'id' => 'cricket',
|
|
'desc' => 'Cricket',
|
|
'domain' => 'sms.mycricket.com' },
|
|
{ 'id' => 'googlefi',
|
|
'desc' => 'Google Fi',
|
|
'domain' => 'msg.fi.google.com' },
|
|
);
|
|
}
|
|
|
|
# list_templates()
|
|
# Returns a list of hash refs, one for each email template
|
|
sub list_templates
|
|
{
|
|
opendir(DIR, $templates_dir) || return ( );
|
|
my @rv;
|
|
foreach my $f (readdir(DIR)) {
|
|
if ($f =~ /^\d+$/) {
|
|
push(@rv, &get_template($f));
|
|
}
|
|
}
|
|
closedir(DIR);
|
|
return @rv;
|
|
}
|
|
|
|
# get_template(id)
|
|
# Returns the hash ref for a specific template, by ID
|
|
sub get_template
|
|
{
|
|
my ($id) = @_;
|
|
my %tmpl;
|
|
&read_file("$templates_dir/$id", \%tmpl) || return undef;
|
|
$tmpl{'id'} = $id;
|
|
$tmpl{'file'} = "$templates_dir/$id";
|
|
$tmpl{'email'} =~ s/\\n/\n/g;
|
|
$tmpl{'email'} =~ s/\\\\/\\/g;
|
|
return \%tmpl;
|
|
}
|
|
|
|
# save_template(&template)
|
|
# Creates or saves an email template. Also does locking.
|
|
sub save_template
|
|
{
|
|
my ($tmpl) = @_;
|
|
$tmpl->{'id'} ||= time().$$;
|
|
$tmpl->{'file'} = "$templates_dir/$tmpl->{'id'}";
|
|
my %write = %$tmpl;
|
|
$write{'email'} =~ s/\\/\\\\/g;
|
|
$write{'email'} =~ s/\n/\\n/g;
|
|
if (!-d $templates_dir) {
|
|
&make_dir($templates_dir, 0755);
|
|
}
|
|
&lock_file($tmpl->{'file'});
|
|
&write_file($tmpl->{'file'}, \%write);
|
|
&unlock_file($tmpl->{'file'});
|
|
}
|
|
|
|
# delete_template(&template)
|
|
# Removes an existing template. Also does locking.
|
|
sub delete_template
|
|
{
|
|
my ($tmpl) = @_;
|
|
&unlink_logged($tmpl->{'file'});
|
|
}
|
|
|
|
# set_monitor_environment(&serv)
|
|
# Sets environment variables based on some monitor
|
|
sub set_monitor_environment
|
|
{
|
|
my ($serv) = @_;
|
|
foreach my $k (keys %$serv) {
|
|
if (!ref($serv->{$k})) {
|
|
$ENV{'STATUS_'.uc($k)} = $serv->{$k};
|
|
}
|
|
}
|
|
}
|
|
|
|
# reset_monitor_environment(&serv)
|
|
# Undoes the call to set_monitor_environment
|
|
sub reset_monitor_environment
|
|
{
|
|
my ($serv) = @_;
|
|
foreach my $k (keys %$serv) {
|
|
if (!ref($serv->{$k})) {
|
|
delete($ENV{'STATUS_'.uc($k)});
|
|
}
|
|
}
|
|
}
|
|
|
|
# list_history(&serv, [max-tail-lines], [max-head-lines])
|
|
# Lists history entries for some service. Each is a hash ref with keys
|
|
# old - Previous status, in host=status format
|
|
# new - New status, in host=status format
|
|
# time - Time at which history was logged
|
|
# value - Optional value at that time (such as memory used)
|
|
# by - Can be 'web' for update from web UI, or 'cron' for background
|
|
sub list_history
|
|
{
|
|
my ($serv, $maxtail, $maxhead) = @_;
|
|
my $hfile = "$history_dir/$serv->{'id'}";
|
|
return ( ) if (!-r $hfile);
|
|
if ($maxtail) {
|
|
open(HFILE, "tail -".quotemeta($maxtail)." ".quotemeta($hfile)." |");
|
|
}
|
|
else {
|
|
open(HFILE, "<".$hfile);
|
|
}
|
|
my @rv;
|
|
while(my $line = <HFILE>) {
|
|
$line =~ s/\r|\n//g;
|
|
my %h = map { split(/=/, $_, 2) } split(/\t+/, $line);
|
|
if ($h{'time'}) {
|
|
push(@rv, \%h);
|
|
}
|
|
last if ($maxhead && scalar(@rv) >= $maxhead);
|
|
}
|
|
close(HFILE);
|
|
return @rv;
|
|
}
|
|
|
|
# add_history(&serv, &history)
|
|
# Adds a history entry for some service
|
|
sub add_history
|
|
{
|
|
my ($serv, $h) = @_;
|
|
if (!-d $history_dir) {
|
|
&make_dir($history_dir, '0700');
|
|
}
|
|
my $hfile = "$history_dir/$serv->{'id'}";
|
|
&lock_file($hfile, 1);
|
|
my ($first) = &list_history($serv, undef, 1);
|
|
my $cutoff = time() - $config{'history_purge'}*24*60*60;
|
|
if ($first && $first->{'time'} < $cutoff-(24*60*60)) {
|
|
# First entry is more than a day older than the cutoff .. remove all
|
|
# entries older than the custoff
|
|
my @oldh = &list_history($serv);
|
|
&open_tempfile(HFILE, ">$hfile", 0, 1);
|
|
foreach my $oh (@oldh) {
|
|
if ($oh->{'time'} > $cutoff) {
|
|
&print_tempfile(HFILE,
|
|
join("\t", map { $_."=".$oh->{$_} } keys %$oh)."\n");
|
|
}
|
|
}
|
|
&close_tempfile(HFILE);
|
|
}
|
|
&open_tempfile(HFILE, ">>$hfile", 0, 1);
|
|
&print_tempfile(HFILE, join("\t", map { $_."=".$h->{$_} } keys %$h)."\n");
|
|
&close_tempfile(HFILE);
|
|
&unlock_file($hfile, 1);
|
|
}
|
|
|
|
# get_status_icon(up)
|
|
# Given a status code, return the image path to it
|
|
sub get_status_icon
|
|
{
|
|
my ($up) = @_;
|
|
return &get_webprefix().
|
|
"/".$module_name."/images/".($up == 1 ? "up.gif" :
|
|
$up == -1 ? "not.gif" :
|
|
$up == -2 ? "webmin.gif" :
|
|
$up == -3 ? "timed.gif" :
|
|
$up == -4 ? "skip.gif" :
|
|
"down.gif");
|
|
}
|
|
|
|
sub status_to_string
|
|
{
|
|
my ($up) = @_;
|
|
return $up == 1 ? $text{'mon_up'} :
|
|
$up == -1 ? $text{'mon_not'} :
|
|
$up == -2 ? $text{'mon_webmin'} :
|
|
$up == -3 ? $text{'mon_timeout'} :
|
|
$up == -4 ? $text{'mon_skip'} :
|
|
"<font color=#ff0000>$text{'mon_down'}</font>";
|
|
}
|
|
|
|
sub get_services_current_status
|
|
{
|
|
my (@serv) = @_;
|
|
my %monitors;
|
|
foreach my $s (@serv) {
|
|
my $title = &html_escape($s->{'desc'});
|
|
my %monitor;
|
|
$monitor{'title'} = $title;
|
|
my @stats = &service_status($s, 1);
|
|
if ($s->{'depend'}) {
|
|
my $ds = &get_service($s->{'depend'});
|
|
if ($ds) {
|
|
my @dstats = &service_status($ds, 1);
|
|
if ($dstats[0]->{'up'} != 1) {
|
|
@stats = map {{ 'up' => -4 }} @stats;
|
|
}
|
|
}
|
|
}
|
|
my @ups = map {$_->{'up'}} @stats;
|
|
my @remotes = map {$_->{'remote'}} @stats;
|
|
for (my $i = 0; $i < @ups; $i++) {
|
|
my $up = $ups[$i];
|
|
my $h = $remotes[$i];
|
|
$h = $text{'index_local'} if ($h eq '*');
|
|
$monitor{'status'} = $up;
|
|
$monitor{'status_text'} = &status_to_string($h);
|
|
$monitor{'icon'} = &get_status_icon($up);
|
|
$monitor{'icon_title'} = &html_escape($h);
|
|
}
|
|
$monitors{$s->{'id'}} = \%monitor;
|
|
}
|
|
return %monitors;
|
|
}
|
|
|
|
1;
|
|
|