#!/usr/bin/perl -w## stated - A daemon to monitor the states of nodes in the testbed. Recives# state change notification through the event system, and writes the new# state into the database.## In the future, will watch for invalid state transitions, and watch for nodes# that time out.## Send it a HUP signal to get it to reload the timeout and transition# information. Periodically reloads this information regardless, though.### Configure variables#uselib'@prefix@/lib';my$BOSSNODE="@BOSSNODE@";my$TBOPS="@TBOPSEMAIL@";$|=1;useevent;uselibdb;uselibtestbed;useGetopt::Std;usestrict;useEnglish;## Will need permissions to do something about nodes that have timed out#if($UID!=0){die"This should only be run as root!\n";}## Number of iterations (roughly, seconds) after which we'll reload # information from the database. This is so we don't end up with information# that's _too_ out of sync.#my$reload_time=360;## Process command-line arguments#sub usage{print<<"END";Usage:$0[-d][-s server] [-p port] [-h]-s serverUsespecifiedserver,insteadofthissite's bossnode-p port Use specified port-d Turn on debugging output, and don'tgointothebackground-hThismessageEND}my%opt=();getopts("ds:p:h",\%opt);if($opt{h}){exit&usage;}if(@ARGV){exit&usage;}my($server,$port,$debug);if($opt{s}) { $server = $opt{s}; }else{$server=$BOSSNODE;}if($opt{p}){$port=$opt{p};}if($opt{d}){$debug=1;}else{$debug=0;}## Background#if(!$debug){if(TBBackGround("/var/log/testbed/stated.log")){exit(0);}}my$URL="elvin://$server";if($port){$URL.=":$port";}## Connect to the event system, and subscribe the the events we want #my$handle=event_register($URL,0);if(!$handle){die"Unable to register with event system\n";}my$tuple=address_tuple_alloc();if(!$tuple){die"Could not allocate an address tuple\n";}

## Unfortunately, we can't subscribe to multiple objtypes - so, we subscribe# to all events to $BOSSNODE, and throw away notificattions whose objtypes# do not match the ones we care about.#%$tuple=(host=>$BOSSNODE);

}## Read in the pre-existing node states, and timeout and valid transition# information from the database#my%nodes=readStates();my%timeouts=getTimeouts();my%valid=getValid();## Gets set if a reload of state from the database should happen.#my$do_reload=0;## Make the daemon reload database state on a sighup - but I'm worried# about what would happen if we tried to do this mid-loop. So, we'll# just set a flag and do it when we're done with our current pass.#$SIG{HUP}=sub {print"Recieved a SIGHUP\n";$do_reload=1;};print"stated starting up\n";## Now, we just poll for events, and watch for #my$iterations=0;while(1){event_poll($handle);my$now=time();## Look for nodes that have passed their timeout#while(my($node,$value)=each%nodes){my$state=$value->{state};

## If there's an entry in oldnodes for this node, and it# hasn't changed state or time, use the old entry (so that# we don't lose information about which nodes we've already# notified the ops about, etc.)#

%timeouts=getTimeouts();%valid=getValid();}sub debug(@){if($debug){print@_;}}sub notify($){my$message=shift;if(!$debug){SENDMAIL($TBOPS,"Node State Daemon Messsage",$message);}print$message;}## This gets called if we die of 'natural causes' (exit, die, etc.)#END{if($handle){print"Exiting, cleaning up\n";if(event_unregister($handle)==0){die"Unable to unregister with event system\n";}}}