#!/usr/bin/perl my $BBMHOME = '/export/home/bbmass'; my $BYMAILLOG = '/export/home/bbmass/bymail/extract.log'; my $BYMAILCF = '/export/home/bbmass/bymail/latest.cf'; my $RULEQAURL = 'http://ruleqa.spamassassin.org/'; # where do the reporting scripts get run from? my $REPORTSCRIPTSADIR = "/export/home/automc/svn/spamassassin"; # --------------------------------------------------------------------------- use strict; use warnings; sub run; # directory used to lock between slaves; no longer used my $LOCKDIR = "/not/in/use"; my $got_lock = undef; $|=1; my $perl = $^X; if (!$perl) { die "no perl path found in ARGV!"; } my $command = shift @ARGV; if ($command eq 'start') { do_start(); } elsif ($command eq 'stop') { do_stop(); } exit; # --------------------------------------------------------------------------- sub do_start { # ensure all pre-reqs (and rules) are built system ("$perl Makefile.PL < /dev/null"); system ("make"); # for mass-check to report, without having to have a working "svn" client # in the chroot # --non-interactive not on the zone yet. duh! # system ("svn info --non-interactive > masses/svninfo.tmp"); system ("svn info > masses/svninfo.tmp < /dev/null"); # mass-check-by-mail support # only use files that are < 1 hour old # if (-f $BYMAILCF && -M $BYMAILCF < (1/24)) { print "\nFound recent rules-by-mail rules file, will mass-check:\n\n"; system ("ls -l $BYMAILCF"); system ("cp $BYMAILCF masses/mailed.cf"); print "".("-" x 75)."\n"; system ("cat masses/mailed.cf"); print "".("-" x 75)."\n"; if (-f $BYMAILLOG) { print "\nRules-by-mail extraction log:\n\n"; system ("ls -l $BYMAILLOG"); system ("cat $BYMAILLOG"); } } else { unlink "masses/mailed.cf"; } # if (!perform_singleton_actions()) { # # give the "winning" slave time to do the work we also need done # print "sleeping for 60 seconds so that corpus is rebuilt\n"; # sleep 60; # } } sub perform_singleton_actions { if (!try_get_exclusive_lock()) { print "cannot get the exclusive lock; some other BB slave is\n". "doing the singleton actions for us.\n"; return 0; } $SIG{INT} = $SIG{TERM} = sub { kill_lock(); die "killed!"; }; eval { _perform_singleton_actions_unlocked(); }; if ($@) { warn $@; kill_lock(); die "aargh"; } kill_lock(); $SIG{INT} = 'DEFAULT'; $SIG{TERM} = 'DEFAULT'; return 1; } sub _perform_singleton_actions_unlocked { # print "got lock: performing singleton actions\n"; # run "build/automc/populate_cor"; # better off doing this periodically from the qproc } # --------------------------------------------------------------------------- sub do_stop { my $rev = get_current_svn_revision(); my $slave = get_current_slave_name(); use POSIX qw(strftime); my $daterev = strftime("%Y%m%d", gmtime(time)) . "-r$rev-b"; my $rurl = $RULEQAURL.$daterev; chdir("masses") or die; print "REPORTS\n\n"; print "Rule-QA results from this mass-check will be published at\n\n"; print " $rurl\n\n"; print "QUICK FREQS REPORT (this mass-check only):\n\n"; system ("$perl hit-frequencies -c tstrules -x -p -T -s 0"); print "\n\nBUILDING SLOW REPORTS:\n\n"; my $logdir = "$BBMHOME/tmp/logs-r$rev"; if (!-d $logdir) { run ("mkdir $logdir"); } run ("mv ham.log $logdir/ham-$slave.log"); run ("mv spam.log $logdir/spam-$slave.log"); # ensure those log files are readable by the freqsd run ("chmod 755 $logdir"); run ("chmod 644 $logdir/ham-$slave.log $logdir/spam-$slave.log"); # run our fast report generator $ENV{HOME} = $BBMHOME; umask(022); run ("$REPORTSCRIPTSADIR/masses/rule-qa/corpus-hourly --dir $logdir --tag b"); run ("$REPORTSCRIPTSADIR/masses/rule-qa/automc/gen_info_xml"); # enqueue a request for the slow stuff with the report-generation daemon run ("$REPORTSCRIPTSADIR/build/automc/freqsd --enq $logdir"); } # --------------------------------------------------------------------------- sub get_current_svn_revision { open (SVNINFO, "(svn info --non-interactive || svn info) < /dev/null 2>&1 |"); # note: use 'Last Changed Rev' instead of 'Revision'. Because we share # an SVN repository with other projects, this means that the same # rev of *our* codebase may appear under multiple rev#s, as other projects # check their changes in. my $revision; while () { # Last Changed Rev: 332684 next unless /^Last Changed Rev: (\d+)/; $revision = $1; last; } close SVNINFO; return $revision if $revision; } sub run { my ($cmd, $ignoreexit) = @_; print "[$cmd]\n"; system ($cmd); if (!$ignoreexit) { die "command '$cmd' failed with status $?" if (($? >> 8) != 0); } } sub get_current_slave_name { my $pwd = `pwd`; $pwd =~ /\/slaves\/([^\/]+)\// and return $1; warn "cannot work out slave name from $pwd"; return "unknown"; } sub try_get_exclusive_lock { if (!-d $LOCKDIR) { print "singleton lock: $LOCKDIR does not exist, so no locking is required.\n"; return 1; } if (!-w $LOCKDIR) { die "cannot write to $LOCKDIR"; } $got_lock = undef; my $newf = $LOCKDIR."/singleton_lock.active"; if (-f $newf) { open (IN, "<$newf"); my $pid = + 0; close IN; if ($pid > 0 && kill(0, $pid)) { print "singleton lock: locked by $pid, still active.\n"; return 0; } else { print "singleton lock: locked by $pid, no longer active. killing lock\n"; # should have to do this too often, which is just as well, as there's # a tiny little racelet here unlink $newf; } } my $tmpf = $LOCKDIR."/singleton_lock.new.$$"; open (OUT, ">$tmpf") or die "cannot write to $tmpf"; print OUT $$; close OUT or die "cannot write to $tmpf"; if (!-f $newf && rename($tmpf, $newf)) { print "singleton lock: taking\n"; $got_lock = $newf; return 1; } else { print "singleton lock: missed the lock\n"; unlink $tmpf; return 0; } } sub kill_lock { return unless $got_lock; unlink $got_lock or warn "singleton lock: unlink $got_lock failed: $!"; }