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

Reply via email to