=head1 NAME B - spong-client module to check the local RealServer =head1 DESCRIPTION This is a plugin module for the Spong L program. The B module checks the status of the locally running RealServer process using the rssm command. It is known to work with version 4 of the software, it may work with others (the latest is v9). It not only alerts you to a problem if it can't connect, but it also checks to make sure that certain specified encoders are running (useful if you're doing live streaming) and returns all the players currently connected. The number of players listening to each live stream can be graphed using L. This module should really be for L but I don't have the rssm program for the version of Linux I'm running, nor do I know the protocol which rssm uses. Someday I may try and find out the protocol, but not yet. If someone can supply me with a rssm that runs in Debian GNU/Linux Woody then I'll modify it to work as a spong-network module. =cut # Register this routine with the plugin reqistry $CHECKFUNCS{'realserver'} = \&check_realserver; # This routine checks RealServer process running locally using rssm. use Expect; sub check_realserver { my ($color) = 'green'; my ($message) = ''; my ($summary) = ''; my ($password) = $REALSERVER_PASSWORD; if (! defined $password || $password eq '') { $color = 'red'; $summary = 'failed - no password'; $message = "Please supply me with a password.\n"; } else { my ($exp); if ($exp = new Expect ("$REALSERVER_RSSM -i localhost")) { $exp->log_stdout(0); my ($state) = 'start'; my (@list); $exp->expect(10, [ qr'password:', sub { $spawn_ok = 1; my $fh = shift; $fh->send("$password\n"); $state = 'password'; exp_continue; } ], [ 'Command:', sub { my ($fh) = shift; if ($state eq 'password') { $fh->send("l\n"); $state = 'list'; exp_continue; } elsif ($state eq 'list') { @list = sort split(/^/m, $exp->before()); $fh->send("x\n"); $state = 'exit'; exp_continue; } } ], [ 'rssm: cannot connect to', sub { $state = 'login failed'; exp_continue; } ]); if ($state eq 'login failed') { $color = 'red'; $summary = 'failed'; $message = "Connection to RealServer failed. Do you have the correct password?\n"; } else { shift(@list); my ($encoder_count) = 0; my ($player_count) = 0; my (%encoders_present); foreach my $line (@list) { $line =~ s/\r\n//; if ($line =~ /^\s*(\w+)\s+([.0-9]+)(\s+(\w+))?/) { my ($type) = $1; my ($ip) = $2; my ($stream) = $4 || undef; if ($type eq 'Encoder') { $encoder_count++; $encoders_present{$ip} = 1; $line = $line . "$REALSERVER_ENCODERS_CRIT{$ip}[1] ($REALSERVER_ENCODERS_CRIT{$ip}[0])" if defined $REALSERVER_ENCODERS_CRIT{$ip}; $line = $line . "$REALSERVER_ENCODERS_WARN{$ip}[1] ($REALSERVER_ENCODERS_WARN{$ip}[0])" if defined $REALSERVER_ENCODERS_WARN{$ip}; } elsif ($type eq 'Player') { $player_count++; } } } my $expected_encoder_count = $#{ [ keys %REALSERVER_ENCODERS_CRIT ] }+1 + $#{ [ keys %REALSERVER_ENCODERS_WARN ] }+1; if ($expected_encoder_count != $encoder_count) { $color = 'yellow'; $summary = "$encoder_count encoders, expected $expected_encoder_count"; $message = "Missing encoder"; $message .= 's' if $expected_encoder_count - $encoder_count > 1; $message .= "\n"; foreach my $encoder (keys %REALSERVER_ENCODERS_WARN) { $message .= "\t$encoder\t$REALSERVER_ENCODERS_WARN{$encoder}[1]\n" unless defined $encoders_present{$encoder}; } foreach my $encoder (keys %REALSERVER_ENCODERS_CRIT) { if (! defined $encoders_present{$encoder}) { $color = 'red'; $message .= "\t$encoder\t$REALSERVER_ENCODERS_CRIT{$encoder}[1]\n"; } } $message .= "\n"; } else { $summary = "ok - players: $player_count"; } $message .= "Players connected: $player_count\n\n"; $message .= join("\n", @list) . "\n"; } } else { $color = 'red'; $summary = 'failed'; $message = "Failed to execute rssm: $!\n"; } } # print "c: $color\n"; # print "s: $summary\n"; # print "m: $message\n"; &debug( "realserver - $color, $summary" ); &status( $SPONGSERVER, $HOST, "realserver", $color, $summary, $message ); } =head2 Output Returned =over 4 =item Status If the RealServer process is contactable and any specified encoders are running then a 'green' status is returned. Otherwise, 'yellow' is return if any of the encoders are not running. 'red' is returned if no password is supplied, the server is not accessible or rssm fails to execute. =item Summary Field If there are no problems then 'ok' and the numbner of players currently connected is returned. If there are problems then a short summary is presented. If there are encoders not running then the number of encoders not present and the number expected is returned. =item Detail Message Field Are full list of all players and encoders currently connected is returned. Along with a count of the number of players connected. If any encoders which are expected aren't found then they are listed. =back =head2 Configuration It is necessary to add the following to L: $REALSERVER_PASSWORD = 'password'; %REALSERVER_ENCODERS_WARN = ( '10.1.1.1' => [ 'streamfile1', 'Stream pretty name 1' ], ); %REALSERVER_ENCODERS_CRIT = ( '10.1.1.2' => [ 'streamfile2', 'Stream pretty name 2' ] ); $REALSERVER_RSSM = "/local/pnserver/bin/rssm"; Configure C<$REALSERVER_RSSM> to be where rssm is installed on your system. In C<%REALSERVER_ENCODERS_WARN> and C<%REALSERVER_ENCODERS_CRIT> the IP address is the IP address of the encoder. In the array, 'streamfile1' is the name that clients request (the filename the encoder encodes to). 'Stream pretty name1' is more human readable form. It is inserted in the list of encoders that is returned to L and is used for the L graphs. =back =head1 SEE ALSO L, L, L =head1 RESTRICTIONS B uses rssm, and the Perl Expect module. Run: =over 4 perl -MCPAN -e shell i Expect =back 4 =head1 AUTHOR Andrew Ruthven - 2002/06/20