From 8bb36e79bd9e1752c01499971cc511872c706956 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 6 Dec 2016 17:46:06 +0100 Subject: [PATCH] Support testing build determinism Builds can now specify the attribute "isDeterministic = true" to tell Hydra to build with build-repeat > 0. If there is a mismatch between rounds, the step / build fails with a suitable status. Maybe this should be a meta attribute, but that makes it invisible to hydra-queue-runner, and it seems reasonable to make a claim of mandatory determinism part of the derivation (since e.g. enabling this flag should trigger a rebuild). --- src/hydra-queue-runner/build-remote.cc | 12 +++++++++++- src/hydra-queue-runner/queue-monitor.cc | 1 + src/hydra-queue-runner/state.hh | 2 ++ src/root/build.tt | 2 ++ src/root/common.tt | 4 ++++ src/sql/hydra.sql | 1 + 6 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/hydra-queue-runner/build-remote.cc b/src/hydra-queue-runner/build-remote.cc index 9466f009..a0408f55 100644 --- a/src/hydra-queue-runner/build-remote.cc +++ b/src/hydra-queue-runner/build-remote.cc @@ -169,7 +169,7 @@ void State::buildRemote(ref destStore, unsigned int remoteVersion; try { - to << SERVE_MAGIC_1 << 0x202; + to << SERVE_MAGIC_1 << 0x203; to.flush(); unsigned int magic = readInt(from); @@ -180,6 +180,8 @@ void State::buildRemote(ref destStore, throw Error(format("unsupported ‘nix-store --serve’ protocol version on ‘%1%’") % machine->sshName); if (GET_PROTOCOL_MINOR(remoteVersion) >= 1) sendDerivation = false; + if (GET_PROTOCOL_MINOR(remoteVersion) < 3 && step->isDeterministic) + throw Error("machine ‘%1%’ does not support deterministic builds; please upgrade it to Nix 1.12", machine->sshName); } catch (EndOfFile & e) { child.pid.wait(true); @@ -261,6 +263,9 @@ void State::buildRemote(ref destStore, to << maxSilentTime << buildTimeout; if (GET_PROTOCOL_MINOR(remoteVersion) >= 2) to << 64 * 1024 * 1024; // == maxLogSize + if (GET_PROTOCOL_MINOR(remoteVersion) >= 3) + // FIXME: make the number of repeats configurable. + to << (step->isDeterministic ? 1 : 0); to.flush(); result.startTime = time(0); @@ -325,6 +330,11 @@ void State::buildRemote(ref destStore, case BuildResult::LogLimitExceeded: result.stepStatus = bsLogLimitExceeded; break; + case BuildResult::NotDeterministic: + result.stepStatus = bsNotDeterministic; + result.canRetry = false; + result.canCache = true; + break; default: result.stepStatus = bsAborted; break; diff --git a/src/hydra-queue-runner/queue-monitor.cc b/src/hydra-queue-runner/queue-monitor.cc index 644919d7..8504a87f 100644 --- a/src/hydra-queue-runner/queue-monitor.cc +++ b/src/hydra-queue-runner/queue-monitor.cc @@ -418,6 +418,7 @@ Step::ptr State::createStep(ref destStore, step->drv = readDerivation(drvPath); step->preferLocalBuild = step->drv.willBuildLocally(); + step->isDeterministic = get(step->drv.env, "isDetermistic", "0") == "1"; step->systemType = step->drv.platform; { diff --git a/src/hydra-queue-runner/state.hh b/src/hydra-queue-runner/state.hh index 347bbbb7..2994b9fb 100644 --- a/src/hydra-queue-runner/state.hh +++ b/src/hydra-queue-runner/state.hh @@ -35,6 +35,7 @@ typedef enum { bsUnsupported = 9, bsLogLimitExceeded = 10, bsNarSizeLimitExceeded = 11, + bsNotDeterministic = 12, bsBusy = 100, // not stored } BuildStatus; @@ -139,6 +140,7 @@ struct Step nix::Derivation drv; std::set requiredSystemFeatures; bool preferLocalBuild; + bool isDeterministic; std::string systemType; // concatenation of drv.platform and requiredSystemFeatures struct State diff --git a/src/root/build.tt b/src/root/build.tt index 68548b98..e78fc883 100644 --- a/src/root/build.tt +++ b/src/root/build.tt @@ -69,6 +69,8 @@ FOR step IN steps; IF step.busy; busy = 1; END; END; Log limit exceeded [% ELSIF step.status == 11 %] Output limit exceeded + [% ELSIF step.status == 12 %] + Non-deterministic build [% ELSIF step.errormsg %] Failed: [% HTML.escape(step.errormsg) %] [% ELSE %] diff --git a/src/root/common.tt b/src/root/common.tt index 3350a277..076ca437 100644 --- a/src/root/common.tt +++ b/src/root/common.tt @@ -209,6 +209,8 @@ BLOCK renderBuildStatusIcon; Log limit exceeded [% ELSIF buildstatus == 11 %] Output size limit exceeded + [% ELSIF buildstatus == 12 %] + Non-deterministic build [% ELSE %] Failed [% END; @@ -240,6 +242,8 @@ BLOCK renderStatus; Log limit exceeded [% ELSIF buildstatus == 11 %] Output limit exceeded + [% ELSIF buildstatus == 12 %] + Non-deterministic build [% ELSE %] Aborted (Hydra failure; see below) diff --git a/src/sql/hydra.sql b/src/sql/hydra.sql index 44a2eb14..fc20e069 100644 --- a/src/sql/hydra.sql +++ b/src/sql/hydra.sql @@ -211,6 +211,7 @@ create table Builds ( -- 9 = unsupported system type -- 10 = log limit exceeded -- 11 = NAR size limit exceeded + -- 12 = build or step was not deterministic buildStatus integer, size bigint,