#!/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