Most of the early part of this series is straightforward (and acked) and could go in whenever.
Patches 15-24 introduce sg-report-host-history. It's probably easiest to simply review the final version of the script, which can be found below. The history is preserved mostly for archeological purposes. Ian. #!/usr/bin/perl -w # This is part of "osstest", an automated testing framework for Xen. # Copyright (C) 2009-2013 Citrix Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. use strict qw(vars); use DBI; use Osstest; use IO::Handle; use HTML::Entities; use POSIX; use Osstest::Executive qw(:DEFAULT :colours); our $limit= 200; our $flightlimit; our $htmlout = "."; our @blessings; open DEBUG, ">/dev/null"; my $namecond= "(name = 'host' or name like '%_host')"; csreadconfig(); while (@ARGV && $ARGV[0] =~ m/^-/) { $_= shift @ARGV; last if m/^--?$/; if (m/^--(limit)\=([1-9]\d*)$/) { $$1= $2; } elsif (m/^--flight-limit\=([1-9]\d*)$/) { $flightlimit= $1; } elsif (m/^--blessings?=(.*)$/) { push @blessings, split ',', $1; } elsif (m/^--html-dir=(.*)$/) { $htmlout= $1; } elsif (m/^--debug/) { open DEBUG, ">&2" or die $!; DEBUG->autoflush(1); } else { die "$_ ?"; } } @blessings= qw(real) if !@blessings; @ARGV or die $!; our $flightcond; sub computeflightsrange () { if (!$flightlimit) { my $flagscond = '('.join(' OR ', map { "f.hostflag = 'blessed-$_'" } @blessings).')'; my $nhostsq = db_prepare(<<END); SELECT count(*) FROM resources r WHERE restype='host' AND EXISTS (SELECT 1 FROM hostflags f WHERE f.hostname=r.resname AND $flagscond) END $nhostsq->execute(); my ($nhosts) = $nhostsq->fetchrow_array(); print DEBUG "COUNTED $nhosts hosts\n"; $flightlimit = $nhosts * $limit * 2; } my $minflightsq = db_prepare(<<END); SELECT flight FROM ( SELECT flight FROM flights ORDER BY flight DESC LIMIT $flightlimit ) f ORDER BY flight ASC LIMIT 1 END $minflightsq->execute(); my ($minflight) = $minflightsq->fetchrow_array(); $minflight //= 0; $flightcond = "(flight > $minflight)"; } sub jobquery ($$) { my ($q, $jr) = @_; $q->execute($jr->{flight}, $jr->{job}); return $q->fetchrow_hashref(); } our %hosts; sub mainquery () { our $valcond = join " OR ", map { "val = ?" } keys %hosts; our @params = keys %hosts; our $runvarq //= db_prepare(<<END); SELECT flight, job, name, val FROM runvars WHERE $namecond AND ($valcond) AND $flightcond ORDER BY flight DESC LIMIT ($limit * 3 + 100) * ? END push @params, scalar keys %hosts; $runvarq->execute(@params); print DEBUG "FIRST PASS\n"; while (my $jr= $runvarq->fetchrow_hashref()) { print DEBUG "JOB $jr->{flight}.$jr->{job} "; push @{ $hosts{$jr->{val}} }, $jr; } } sub reporthost ($) { my ($hostname) = @_; die if $hostname =~ m/[^-_.+0-9a-z]/; my $html_file= "$htmlout/$hostname.html"; open H, "> $html_file.new" or die "$html_file $!"; my $title= "host history $hostname\n"; $title= encode_entities($title); print H "<html><head><title>$title</title></head><body>\n"; print H "<h1>$title</h1>\n"; print H "<table rules=all><tr>\n"; print H "<th>alloc testid</th><th>alloc completed</th>\n"; print H "<th>job finished</th>\n"; print H "<th>role</th>\n"; print H "<th>flight</th>\n"; print H "<th>branch</th><th>intended</th><th>blessing</th>\n"; print H "<th>job</th><th>failure</th>\n"; print H "</tr>\n"; our $endedq //= db_prepare(<<END); SELECT finished, testid, status AS laststepstatus FROM steps WHERE flight=? AND job=? AND finished IS NOT NULL ORDER BY finished DESC LIMIT 1 END our $infoq //= db_prepare(<<END); SELECT blessing, branch, intended, status FROM flights JOIN jobs USING (flight) WHERE flight=? AND job=? END our $allocdq //= db_prepare(<<END); SELECT testid, finished, status FROM steps WHERE flight=? AND job=? AND (testid='hosts-allocate' OR step='ts-hosts-allocate') ORDER BY finished ASC LIMIT 1 END my $inrows = $hosts{$hostname}; print DEBUG "FOUND ", (scalar @$inrows), " ROWS for $hostname\n"; my @rows; foreach my $jr (@$inrows) { print DEBUG "JOB $jr->{flight}.$jr->{job}\n"; my $endedrow = jobquery($endedq, $jr); if (!$endedrow) { print DEBUG "no-finished\n"; next; } print DEBUG join " ", map { $endedrow->{$_} } sort keys %$endedrow; print DEBUG ".\n"; push @rows, { %$jr, %$endedrow }; } @rows = sort { $b->{finished} <=> $a->{finished} } @rows; $#rows = $limit-1 if @rows > $limit; my $alternate = 0; foreach my $jr (@rows) { my $ir = jobquery($infoq, $jr); my $ar = jobquery($allocdq, $jr); my $altcolour = report_altcolour($alternate); print H "<tr $altcolour>"; if (!defined $ar->{testid}) { print H "<td bgcolor=\"$red\"></td>"; print H "<td>?</td>"; } else { if ($ar->{status} eq 'pass') { print H "<td>$ar->{testid}</td>"; print H "<td>", (show_abs_time $ar->{finished}), "</td>"; } elsif ($ar->{status} eq 'running') { print H "<td bgcolor=\"$blue\">$ar->{testid}</td>"; print H "<td>(incomplete)</td>"; } else { print H "<td bgcolor=\"$red\">$ar->{testid}</td>"; print H "<td>$ar->{status}</td>"; } } print H "\n"; print H "<td>", (show_abs_time $jr->{finished}), "</td>\n"; print H "<td>", $jr->{name}, "</td>\n"; my $url= "$c{ReportHtmlPubBaseUrl}/$jr->{flight}"; print H "<td><a href=\"$url\">$jr->{flight}</a></td>\n"; $url= "$c{ReportHtmlPubBaseUrl}/$jr->{flight}/". encode_entities($jr->{job})."/"; print H "<td>$ir->{branch}</td>"; print H "<td>$ir->{intended}</td>"; print H "<td>"; print H $ir->{blessing} unless $ir->{blessing} eq 'running'; print H "</td>"; print H "<td><a href=\"$url\">$jr->{job}</td>\n"; my $ri = report_run_getinfo({ %$jr, %$ir }); print H "<td bgcolor=\"$ri->{Colour}\">$ri->{Summary}</td>\n"; print H "</tr>\n\n"; $alternate ^= 1; } print H "</table></body></html>\n"; close H or die $!; rename "$html_file.new", "$html_file" or die "$html_file $!"; } db_retry($dbh_tests, [qw(flights resources)], sub { computeflightsrange(); }); $dbh_tests->do("SET LOCAL enable_seqscan=false"); # Otherwise the PostgreSQL query planner likes to do a complete scan # of the runvars table, rather than walking backwards through the # flights until it has what we've told it is enough. foreach my $host (@ARGV) { if ($host =~ m/^flight:/) { my $flight=$'; #'; db_retry($dbh_tests, [qw(flights)], sub { our $hostsinflightq //= db_prepare(<<END); SELECT DISTINCT val FROM runvars WHERE flight=? AND (name = 'host' or name like '%_host') END $hostsinflightq->execute($flight); while (my $row = $hostsinflightq->fetchrow_hashref()) { $hosts{$row->{val}} = [ ]; } }); } elsif ($host !~ m/:/) { $hosts{$host} = [ ]; } else { die "$host ?"; } } exit 0 unless %hosts; db_retry($dbh_tests, [qw(flights)], sub { mainquery(); }); foreach my $host (sort keys %hosts) { db_retry($dbh_tests, [qw(flights)], sub { reporthost $host; }); } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel