use Spong::Daemon;
use Spong::Log;
use Spong::HostGroups;
+use Spong::ConfigFile;
use Sys::Hostname;
use File::Path;
use Socket;
+use IO::Socket;
use Config;
use Time::Local;
use Getopt::Long;
exit 1;
}
-
+Spong::Log::set_debug_context( 'debuglevel' => $debuglevel );
#if( $ARGV[0] eq "--debug" ) { $debug = 1; shift; }
#if( $ARGV[0] eq "--restart" ) { $restart = 1; shift; }
#if( $ARGV[0] eq "--kill" ) { $kill = 1; shift; }
-$me = "@@BINDIR@@/spong-server";
-$smessage = "@@BINDIR@@/spong-message";
-$conf_file = $ARGV[0] || "@@ETCDIR@@/spong.conf";
-$hosts_file = "@@ETCDIR@@/spong.hosts";
-$groups_file = "@@ETCDIR@@/spong.groups";
+$ETCDIR = '@@ETCDIR@@';
+$BINDIR = '@@BINDIR@@';
+
+$me = "$BINDIR/spong-server";
+$smessage = "$BINDIR/spong-message";
+$conf_file = $ARGV[0] || "$ETCDIR/spong.conf";
+$hosts_file = "$ETCDIR/spong.hosts";
+$groups_file = "$ETCDIR/spong.groups";
$datafunc_path = "@@LIBDIR@@/Spong/plugins";
($HOST) = gethostbyname(&Sys::Hostname::hostname());
$HOST =~ tr/A-Z/a-z/;
$PROCS{'spong-update'} = { func => \&listen_for_updates, pid => undef };
}
+if (defined $SPONG_CLIENT_PORT ) {
+ $PROCS{'client'} = { func => \&listen_for_clients, pid => undef };
+}
+
# Establish a list of all the services that we monitor so that we can be
# consistant in the output that we display regardless of the group that we
}
+# This procedure listens for client connections connections (the client port),
+# and reponse to queries or request for configuration files.
+
+sub listen_for_clients {
+ my ( $sock, $client );
+
+ # Set up the socket to listen to
+ $SIG{'PIPE'} = 'IGNORE';
+ $SIG{'TERM'} = $SIG{'HUP'} = $SIG{'QUIT'} = sub {
+ &debug('spong client caught QUIT signal, exiting',3);
+ undef $sock; exit;
+ };
+
+ $sock = IO::Socket::INET->new( Listen => SOMAXCONN,
+# LocalHost => INADDR_ANY,
+ LocalPort => $main::SPONG_CLIENT_PORT,
+ Proto => 'tcp',
+ Timeout => 30,
+ Reuse => 1,
+ );
+ if (! defined $sock ) { die "socket: $!"; }
+
+ &debug( "client socket setup, listening for connections" );
+
+ while( 1 ) {
+ next unless ( $client = $sock->accept() );
+
+ $paddr = $client->peerhost();
+
+&debug("[$$] Connection from $paddr");
+
+ # &validate_connection( $paddr ); - need to do something here...
+
+ # Read all from the client, and disconnect, we process the message next.
+
+ my $header = <$client>; chomp $header;
+&debug("[$$] header = $header");
+
+ # Now depending on what kind of message it is, pass it off to a routine
+ # that can process the message.
+
+ if( $header =~ /^status\b/ ) { &client_status( $client, $header ); }
+ if( $header =~ /^get\b/ ) { &client_get( $client, $header ); }
+
+ undef $client;
+
+ }
+}
# This procedure listens for connections at port 1970 (the update port), and
# each time a connection is made, it grabs the info that is being sent to us,
if( $header =~ /^status\b/ ) { &save_status( $header, $message ); next; }
if( $header =~ /^event\b/ ) { &save_event( $header, $message ); next; }
+ if( $header =~ /^page\b/ ) { &save_page( $header, $message ); next; }
if( $header =~ /^ack-del\b/ ) { &del_ack( $header, $message ); next; }
if( $header =~ /^ack\b/ ) { &save_ack( $header, $message ); next; }
# if( $header =~ /^config\b/ ) { &save_config( $header, $message ); }
}
}
+# ===========================================================================
+# Client configuare methods. These all take messages from clients and sends
+# configuration file or info about configuration file back
+# ===========================================================================
+
+# Return status information about configuration files for a host
+
+sub client_status {
+ my( $client, $header ) = @_;
+
+ my( $host, $file ) = ( "", "" );
+ if ( $header =~ /\S+ (\S+) (\S+)/ ) { $host = $1; $file = $2; }
+
+ if ( ! $main::HOSTS{$host} && $host ne 'DEFAULT') {
+ $client->print("ERROR Host $host is not defined");
+ return;
+ }
+
+ # Get a Configuration file object for the host
+ my $cf = new Spong::ConfigFile( $host, $file );
+ if ( ! $cf ) {
+ $client->print("ERROR Configuration file $file not found");
+ return;
+ }
+
+ # Build the status line and return it to the client
+ $sts = "OK " . $cf->host() . " " . $cf->name() . " " . $cf->timestamp() .
+ " " . $cf->size() . " " . $cf->lines();
+ $client->print("$sts\n");
+
+}
+
+sub client_get {
+ my( $client, $header ) = @_;
+
+ my( $host, $file ) = ( "", "" );
+ if ( $header =~ /\S+ (\S+) (\S+)/ ) { $host = $1; $file = $2; }
+
+ if ( ! $main::HOSTS{$host} && $host ne 'DEFAULT') {
+ $client->print("ERROR Host $host is not defined");
+ return;
+ }
+
+ # Get a Configuration file object for the host
+ my $cf = new Spong::ConfigFile( $host, $file );
+ if ( ! $cf ) {
+ $client->print("ERROR Configuration file $file not found");
+ return;
+ }
+
+ my $contents = $cf->contents();
+
+ foreach ( @$contents ) { $client->print($_); }
+
+}
+
+
+
# ===========================================================================
# Database update methods. These all take messages from clients and update
# specific parts of the database.
}
+
+# Take the incoming page message, run it through some error checking,
+# and send the information off to spong-message and let it decide if it
+# should page/email someone...
+
+sub save_page {
+ my( $header, $message ) = @_;
+ my( $cmd, $host, $service, $color, $time, $sum, $path, $start, $duration );
+ my( $ttl ) = 0;
+
+ # Do some checking on the message. If it appears bogus, then just
+ # log a message, and close the connection.
+
+ if( $header =~ /^(\w+) (\S+) (\w+) (\w+) (\d+) (.*)$/ ) {
+ ($cmd, $host, $service, $color, $time, $sum) = ($1, $2, $3, $4, $5, $6);
+
+ if( $host !~ m/^[a-z0-9_\-\.]+$/ ) {
+ &error( "save_status: invalid host [$host]" ); return; }
+ if( $service !~ m/^[a-z0-9_\-\.]+$/ ) {
+ &error( "save_status: invalid service [$service]" ); return; }
+ if( $color ne "red" && $color ne "yellow" && $color ne "green" ) {
+ &error( "save_status: invalid color [$color]" ); return;}
+ if( $time !~ m/^\d+$/ ) {
+ &error( "save_status: invalid time [$time]" ); return; }
+ } else {
+ &error( "save_status: invalid header [$header]" ); return;
+ }
+
+ if ($main::HOSTS{$host} eq "") {
+ &error("save_status: undefined host [$host]");
+ return;
+ }
+
+ # Call message_user()...
+
+# $duration = $time - $start;
+ &message_user( "page", $host, $service, $color, $time, $sum );
+
+ # Save the status information to the history table and state file as well.
+
+ # Update the history file
+ if (0) {
+ $data = "page $time $service $color $sum\n";
+ &save_data( ">>", "$SPONGDB/$host/history/current", $data);
+
+ # If status history is enabled, save status message for history event
+ if ( $STATUS_HISTORY ) {
+ # Save the status update information
+ $data = "timestamp $start $time\ncolor $color\n$time $sum\n$message\n";
+ &save_data( ">>", "$SPONGDB/$host/history/status/$time-$service",
+ $data);
+ }
+ }
+
+}
+
+
+
+
# Take a BigBrother status message and convert it to a Spong status
# message and send it to save_status for processing
$debug = ($debuglevel == 0) ? 1 : $debuglevel
}
- Spong::Log::set_debug_context( "debuglevel" => $debug );
+ Spong::Log::set_debug_context( 'debuglevel' => $debug );
my $filename = ($SPONG_LOG_FILE) ? "$SPONGTMP/spong-server.log" : "";
my $syslog = ($SPONG_LOG_SYSLOG) ? 1 : 0;
sub message_user {
my ( $cmd, $host, $service, $color, $time, $sum, $duration ) = @_;
- if ($SEND_MESSAGE eq 'NONE') { return; }
-
if (! defined $duration || $duration eq "") { $duration = 0; }
$SIG{'CHLD'} = 'IGNORE';
- if ( $cmd eq "status" ) {
+ # if message type was 'status' and messaging is allowed
+ if ( $cmd eq "status" && $SEND_MESSAGE ne 'NONE' ) {
# If the color is 'red' and duration is non-zero, call spong-message for
# escalation notifications
&send_message( $host, $service, $color, $time, $sum, $duration );
}
}
+ } elsif ( $cmd eq "page" && $PAGE_MESSAGE eq 'PAGE' ) {
+ &debug("sending a page message notification",2);
+ &send_message( $host, $service, $color, $time, $sum, $duration );
}
$SIG{'CHLD'} = \&chld_handler;