#!/usr/bin/perl
use warnings;
use strict;
use Getopt::Long;
use Fcntl qw< :DEFAULT :flock >;
use Net::Ping;
use constant { UNKNOWN => 0, STAR => 2, ON => 3, OFF => 4 };
GetOptions(
"interval=i" => \(my $interval = 5),
"help" => \&usage,
) or usage();
usage() unless @ARGV >= 1;
my %host = map {
my ($h, $i) = split /:/, $_, 2;
$i ||= $interval;
$i =~ /^\d+$/ or die "Error: Interval of host \"$h\" is not a number!\n";
($h => $i);
} @ARGV;
$SIG{CHLD} = "IGNORE";
$|++;
# Mix last_checks so to not check all hosts at the same time.
my %last_check = map { $_ => time - int rand $host{$_} } keys %host;
my %status = map { $_ => UNKNOWN } keys %host;
write_status();
my $ping = Net::Ping->new;
while(1) {
foreach my $host (sort keys %last_check) {
next if $last_check{$host} > time - $host{$host};
$last_check{$host} = time;
write_if_change($host, sub { $status{$host} = $ping->ping($host, 5) ? ON : OFF });
}
# To not hog all the CPU :)
sleep 1;
}
sub write_if_change {
my ($host, $sub) = @_;
my $old_status = $status{$host};
$sub->();
my $new_status = $status{$host};
if($old_status != $new_status) {
$status{$host} = STAR;
write_status();
system "beep", "-r2", "-l150", "-f", $new_status == ON ? "1700" : "200"
if $new_status == ON or $new_status == OFF;
$status{$host} = $new_status;
write_status();
}
}
sub write_status {
for (sort keys %host) {
my $status = $status{$_};
my $first = substr $_, 0, 1;
print
$status == ON ? uc $first :
$status == OFF ? lc $first :
$status == UNKNOWN ? "?" :
$status == STAR ? "*" : die;
}
print "\n";
}
sub usage { print STDERR <<EOH; exit 0 }
node-statusd -- monitors the liveness of given hosts
Usage: $0 [--interval=5] -- host1 host2 host3 ...
Options:
--interval=5
Specifies the interval to wait between livetests.
Options may be abbreviated to uniqueness.
EOH
Download