* Experimental feature: allow a derivation to tell the build hook that
it requires a certain feature on the build machine, e.g. requiredSystemFeatures = [ "kvm" ]; We need this in Hydra to make sure that builds that require KVM support are forwarded to machines that have KVM support. Probably this should also be enforced for local builds.
This commit is contained in:
parent
e41ecbf730
commit
766f708418
4 changed files with 43 additions and 12 deletions
|
@ -36,6 +36,8 @@ sub sendReply {
|
||||||
print STDERR "# $reply\n";
|
print STDERR "# $reply\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub all { $_ || return 0 for @_; 1 }
|
||||||
|
|
||||||
|
|
||||||
# Initialisation.
|
# Initialisation.
|
||||||
my $loadIncreased = 0;
|
my $loadIncreased = 0;
|
||||||
|
@ -64,13 +66,14 @@ if (defined $conf && -e $conf) {
|
||||||
chomp;
|
chomp;
|
||||||
s/\#.*$//g;
|
s/\#.*$//g;
|
||||||
next if /^\s*$/;
|
next if /^\s*$/;
|
||||||
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)(\s+([0-9\.]+))?\s*$/ or die;
|
my @tokens = split /\s/, $_;
|
||||||
push @machines,
|
push @machines,
|
||||||
{ hostName => $1
|
{ hostName => $tokens[0]
|
||||||
, systemTypes => [split(/,/, $2)]
|
, systemTypes => [ split(/,/, $tokens[1]) ]
|
||||||
, sshKeys => $3
|
, sshKeys => $tokens[2]
|
||||||
, maxJobs => $4
|
, maxJobs => int($tokens[3])
|
||||||
, speedFactor => 1.0 * ($6 || 1)
|
, speedFactor => 1.0 * (defined $tokens[4] ? int($tokens[4]) : 1)
|
||||||
|
, features => [ split(/,/, $tokens[5] || "") ]
|
||||||
, enabled => 1
|
, enabled => 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -85,7 +88,8 @@ my ($drvPath, $hostName, $slotLock);
|
||||||
REQ: while (1) {
|
REQ: while (1) {
|
||||||
$_ = <STDIN> || exit 0;
|
$_ = <STDIN> || exit 0;
|
||||||
my ($amWilling, $neededSystem);
|
my ($amWilling, $neededSystem);
|
||||||
($amWilling, $neededSystem, $drvPath) = split;
|
($amWilling, $neededSystem, $drvPath, $requiredFeatures) = split;
|
||||||
|
my @requiredFeatures = split /,/, $requiredFeatures;
|
||||||
|
|
||||||
my $canBuildLocally = $amWilling && ($localSystem eq $neededSystem);
|
my $canBuildLocally = $amWilling && ($localSystem eq $neededSystem);
|
||||||
|
|
||||||
|
@ -103,12 +107,15 @@ REQ: while (1) {
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
# Find all machine that can execute this build, i.e., that
|
# Find all machine that can execute this build, i.e., that
|
||||||
# support builds for the given platform and are not at their
|
# support builds for the given platform and features, and are
|
||||||
# job limit.
|
# not at their job limit.
|
||||||
my $rightType = 0;
|
my $rightType = 0;
|
||||||
my @available = ();
|
my @available = ();
|
||||||
LOOP: foreach my $cur (@machines) {
|
LOOP: foreach my $cur (@machines) {
|
||||||
if ($cur->{enabled} && grep { $neededSystem eq $_ } @{$cur->{systemTypes}}) {
|
if ($cur->{enabled}
|
||||||
|
&& (grep { $neededSystem eq $_ } @{$cur->{systemTypes}})
|
||||||
|
&& all(map { my $f = $_; 0 != grep { $f eq $_ } @{$cur->{features}} } @requiredFeatures))
|
||||||
|
{
|
||||||
$rightType = 1;
|
$rightType = 1;
|
||||||
|
|
||||||
# We have a machine of the right type. Determine the load on
|
# We have a machine of the right type. Determine the load on
|
||||||
|
|
|
@ -1327,8 +1327,16 @@ HookReply DerivationGoal::tryBuildHook()
|
||||||
if (!worker.hook)
|
if (!worker.hook)
|
||||||
worker.hook = boost::shared_ptr<HookInstance>(new HookInstance);
|
worker.hook = boost::shared_ptr<HookInstance>(new HookInstance);
|
||||||
|
|
||||||
writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3%") %
|
/* Tell the hook about system features (beyond the system type)
|
||||||
(worker.getNrLocalBuilds() < maxBuildJobs ? "1" : "0") % drv.platform % drvPath).str());
|
required from the build machine. (The hook could parse the
|
||||||
|
drv file itself, but this is easier.) */
|
||||||
|
Strings features = tokenizeString(drv.env["requiredSystemFeatures"]);
|
||||||
|
foreach (Strings::iterator, i, features) checkStoreName(*i); /* !!! abuse */
|
||||||
|
|
||||||
|
/* Send the request to the hook. */
|
||||||
|
writeLine(worker.hook->toHook.writeSide, (format("%1% %2% %3% %4%")
|
||||||
|
% (worker.getNrLocalBuilds() < maxBuildJobs ? "1" : "0")
|
||||||
|
% drv.platform % drvPath % concatStringsSep(",", features)).str());
|
||||||
|
|
||||||
/* Read the first line of input, which should be a word indicating
|
/* Read the first line of input, which should be a word indicating
|
||||||
whether the hook wishes to perform the build. */
|
whether the hook wishes to perform the build. */
|
||||||
|
|
|
@ -966,6 +966,17 @@ Strings tokenizeString(const string & s, const string & separators)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string concatStringsSep(const string & sep, const Strings & ss)
|
||||||
|
{
|
||||||
|
string s;
|
||||||
|
foreach (Strings::const_iterator, i, ss) {
|
||||||
|
if (s.size() != 0) s += sep;
|
||||||
|
s += *i;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
string statusToString(int status)
|
string statusToString(int status)
|
||||||
{
|
{
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||||
|
|
|
@ -280,6 +280,11 @@ MakeError(Interrupted, BaseError)
|
||||||
Strings tokenizeString(const string & s, const string & separators = " \t\n\r");
|
Strings tokenizeString(const string & s, const string & separators = " \t\n\r");
|
||||||
|
|
||||||
|
|
||||||
|
/* Concatenate the given strings with a separator between the
|
||||||
|
elements. */
|
||||||
|
string concatStringsSep(const string & sep, const Strings & ss);
|
||||||
|
|
||||||
|
|
||||||
/* Convert the exit status of a child as returned by wait() into an
|
/* Convert the exit status of a child as returned by wait() into an
|
||||||
error string. */
|
error string. */
|
||||||
string statusToString(int status);
|
string statusToString(int status);
|
||||||
|
|
Loading…
Reference in a new issue