5 Copyright (c) 2003-2010, Andrew Dunstan
7 See accompanying License file for license details
13 use Digest::SHA1 qw(sha1_hex);
19 use Storable qw(thaw);
21 use vars qw($dbhost $dbname $dbuser $dbpass $dbport
22 $all_stat $fail_stat $change_stat $green_stat
26 require "$ENV{BFConfDir}/BuildFarmWeb.pl";
28 die "no dbname" unless $dbname;
29 die "no dbuser" unless $dbuser;
31 # don't use configged dbuser/dbpass
33 $dbuser=""; $dbpass="";
35 my $dsn="dbi:Pg:dbname=$dbname";
36 $dsn .= ";host=$dbhost" if $dbhost;
37 $dsn .= ";port=$dbport" if $dbport;
39 my $db = DBI->connect($dsn,$dbuser,$dbpass);
41 die $DBI::errstr unless $db;
43 my $clear_old = $db->do(q[
47 (SELECT name FROM buildsystems WHERE no_alerts)
51 my $sth = $db->prepare(q[
53 SELECT DISTINCT ON (sysname, branch)
55 extract(epoch from snapshot at time zone 'GMT')::int as snapshot,
57 FROM build_status s join buildsystems b on (s.sysname = b.name)
58 WHERE NOT b.no_alerts and
59 snapshot > current_timestamp - interval '30 days'
60 ORDER BY sysname, branch, snapshot desc
68 while (my $row = $sth->fetchrow_hashref)
70 push(@last_heard, $row);
77 SELECT sysname, branch,
78 extract(epoch from first_alert) as first_alert,
79 extract(epoch from last_notification) as last_notification
84 my $alerts = $db->selectall_hashref($sql,['sysname','branch']);
89 my $clear_sth = $db->prepare(q[
96 my $update_sth = $db->prepare(q[
99 SET last_notification = timestamp '1970-01-01' + ( interval '1 second' * $1)
104 my $insert_sth = $db->prepare(q[
106 INSERT INTO alerts ( sysname, branch, first_alert, last_notification )
108 timestamp '1970-01-01' + ( interval '1 second' * $3),
109 timestamp '1970-01-01' + ( interval '1 second' * $4))
114 my $lts = scalar(localtime);
115 print "starting alert run: $lts\n";
117 foreach my $sysbranch (@last_heard)
119 # not all versions of DBD::Pg decode modern bytea literals nicely. cope.
120 $sysbranch->{config} =~ s/^(\\?x)([a-fA-F0-9]+)$/pack('H*',$2)/e;
123 my $client_conf = thaw $sysbranch->{config};
125 my %client_alert_settings = %{ $client_conf->{alerts} || {} };
126 my $setting = $client_alert_settings{$sysbranch->{branch}};
127 unless ($setting && $setting->{alert_after} && $setting->{alert_every})
129 # if no valid setting, clear any alert and keep going
130 if ($alerts->{$sysbranch->{sysname}}->{$sysbranch->{branch}})
132 $clear_sth->execute($sysbranch->{sysname},$sysbranch->{branch});
133 push(@need_cleared,[$sysbranch]);
137 # ok, we have valid settings. should the alert be on?
138 my $hours_since_heard = ($now - $sysbranch->{snapshot}) / 3600;
141 "have settings for $sysbranch->{sysname}:$sysbranch->{branch} ",
142 "hours since heard = $hours_since_heard, ",
143 "setting = $setting->{alert_after} / $setting->{alert_every} \n";
145 if ($hours_since_heard > $setting->{alert_after})
148 $alerts->{$sysbranch->{sysname}}->{$sysbranch->{branch}};
150 ($now - (3600 * $setting->{alert_every})) >
151 $known_alert->{last_notification})
153 # check if it's too old - 15 days and twice initial seems plenty
154 if ($hours_since_heard > 360 &&
155 $hours_since_heard > 2 * $setting->{alert_after} )
157 print "alert is too old ... giving up\n";
161 # old alert, but time to alert again
162 print "alert is on, but time to alert again\n";
163 $update_sth->execute($now,
164 $sysbranch->{sysname},
165 $sysbranch->{branch},
167 push(@need_alerts,[$sysbranch,$setting]);
168 print "alert updated\n";
170 elsif ( ! $known_alert )
173 print "new alert needed\n";
174 $insert_sth->execute($sysbranch->{sysname},
175 $sysbranch->{branch},
177 print "new record inserted\n";
178 push(@need_alerts,[$sysbranch,$setting]);
181 # nope, so clear the alert if it exists
182 elsif ($alerts->{$sysbranch->{sysname}}->{$sysbranch->{branch}})
184 print "clear exisiting alerts";
185 $clear_sth->execute($sysbranch->{sysname},$sysbranch->{branch});
186 push(@need_cleared,[$sysbranch,$setting]);
191 print "start emails\n";
193 my $addr_sth = $db->prepare(q[
201 my $me = `id -un`; chomp $me;
202 my $host = `hostname`; chomp ($host);
203 $host = $default_host unless ($host =~ m/[.]/ || !defined($default_host));
205 my $from_addr = "PG Build Farm <$me\@$host>";
206 $from_addr =~ tr /\r\n//d;
210 foreach my $clearme (@need_cleared)
212 my ($sysbranch, $setting) = @$clearme;
213 my ($animal, $branch) = ($sysbranch->{sysname},$sysbranch->{branch});
217 my $hours = sprintf("%.2f",($now - $sysbranch->{snapshot}) / 3600);
218 $text = "$sysbranch->{sysname} has now reported " .
219 "on $sysbranch->{branch} $hours hours ago.";
223 $text = "$sysbranch->{sysname} has lost alarm settings on branch: " .
224 "$sysbranch->{branch}. Resetting alarm to off.";
226 my $msg = new Mail::Send;
228 $msg->set('From',$from_addr);
230 $addr_sth->execute($animal);
232 my $mailto = $addr_sth->fetchrow_array;
234 print "sending clear to $mailto\n";
239 $msg->subject("PGBuildfarm member $animal Branch $branch Alert cleared");
241 print $fh "\n\n$text\n";
244 print "alert cleared $animal $branch\n";
247 foreach my $clearme (@need_alerts)
249 my ($sysbranch, $setting) = @$clearme;
250 my ($animal, $branch) = ($sysbranch->{sysname},$sysbranch->{branch});
251 my $hours = sprintf("%.2f",($now - $sysbranch->{snapshot}) / 3600);
252 my $text = "$sysbranch->{sysname} has not reported " .
253 "on $sysbranch->{branch} for $hours hours.";
254 my $msg = new Mail::Send;
256 $msg->set('From',$from_addr);
258 $addr_sth->execute($animal);
260 my ($mailto) = $addr_sth->fetchrow_array;
264 print "sending alert to $mailto\n";
268 $msg->subject("PGBuildfarm member $animal Branch $branch " .
269 "Alert notification");
271 print $fh "\n\n$text\n";
274 print "alert sent $animal $branch\n";
278 print "=================================\n";