Skip to content

Commit

Permalink
Merge branch 'wait-for-builders' of https://github.com/serokell/nix
Browse files Browse the repository at this point in the history
  • Loading branch information
edolstra committed May 18, 2020
2 parents 2e16186 + 183dd28 commit 0ed946a
Showing 1 changed file with 60 additions and 39 deletions.
99 changes: 60 additions & 39 deletions src/libstore/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ class UserLock
Path fnUserLock;
AutoCloseFD fdUserLock;

bool isEnabled;
string user;
uid_t uid;
gid_t gid;
Expand All @@ -522,14 +523,24 @@ class UserLock
uid_t getGID() { assert(gid); return gid; }
std::vector<gid_t> getSupplementaryGIDs() { return supplementaryGIDs; }

bool enabled() { return uid != 0; }
bool findFreeUser();

bool enabled() { return isEnabled; }

};


UserLock::UserLock()
{
assert(settings.buildUsersGroup != "");
createDirs(settings.nixStateDir + "/userpool");
/* Mark that user is not enabled by default */
uid = 0;
isEnabled = false;
}

bool UserLock::findFreeUser() {
if (enabled()) return true;

/* Get the members of the build-users-group. */
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
Expand Down Expand Up @@ -559,7 +570,6 @@ UserLock::UserLock()
throw Error(format("the user '%1%' in the group '%2%' does not exist")
% i % settings.buildUsersGroup);

createDirs(settings.nixStateDir + "/userpool");

fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str();

Expand Down Expand Up @@ -590,16 +600,13 @@ UserLock::UserLock()
supplementaryGIDs.resize(ngroups);
#endif

return;
isEnabled = true;
return true;
}
}

throw Error(format("all build users are currently in use; "
"consider creating additional users and adding them to the '%1%' group")
% settings.buildUsersGroup);
return false;
}


void UserLock::kill()
{
killUser(uid);
Expand Down Expand Up @@ -928,6 +935,7 @@ class DerivationGoal : public Goal
void closureRepaired();
void inputsRealised();
void tryToBuild();
void tryLocalBuild();
void buildDone();

/* Is the build hook willing to perform the build? */
Expand Down Expand Up @@ -999,6 +1007,8 @@ class DerivationGoal : public Goal
Goal::amDone(result);
}

void started();

void done(BuildResult::Status status, const string & msg = "");

StorePathSet exportReferences(const StorePathSet & storePaths);
Expand Down Expand Up @@ -1386,6 +1396,19 @@ void DerivationGoal::inputsRealised()
result = BuildResult();
}

void DerivationGoal::started() {
auto msg = fmt(
buildMode == bmRepair ? "repairing outputs of '%s'" :
buildMode == bmCheck ? "checking outputs of '%s'" :
nrRounds > 1 ? "building '%s' (round %d/%d)" :
"building '%s'", worker.store.printStorePath(drvPath), curRound, nrRounds);
fmt("building '%s'", worker.store.printStorePath(drvPath));
if (hook) msg += fmt(" on '%s'", machineName);
act = std::make_unique<Activity>(*logger, lvlInfo, actBuild, msg,
Logger::Fields{worker.store.printStorePath(drvPath), hook ? machineName : "", curRound, nrRounds});
mcRunningBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.runningBuilds);
worker.updateProgress();
}

void DerivationGoal::tryToBuild()
{
Expand Down Expand Up @@ -1437,20 +1460,6 @@ void DerivationGoal::tryToBuild()
supported for local builds. */
bool buildLocally = buildMode != bmNormal || parsedDrv->willBuildLocally();

auto started = [&]() {
auto msg = fmt(
buildMode == bmRepair ? "repairing outputs of '%s'" :
buildMode == bmCheck ? "checking outputs of '%s'" :
nrRounds > 1 ? "building '%s' (round %d/%d)" :
"building '%s'", worker.store.printStorePath(drvPath), curRound, nrRounds);
fmt("building '%s'", worker.store.printStorePath(drvPath));
if (hook) msg += fmt(" on '%s'", machineName);
act = std::make_unique<Activity>(*logger, lvlInfo, actBuild, msg,
Logger::Fields{worker.store.printStorePath(drvPath), hook ? machineName : "", curRound, nrRounds});
mcRunningBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.runningBuilds);
worker.updateProgress();
};

/* Is the build hook willing to accept this job? */
if (!buildLocally) {
switch (tryBuildHook()) {
Expand Down Expand Up @@ -1483,6 +1492,34 @@ void DerivationGoal::tryToBuild()
return;
}

state = &DerivationGoal::tryLocalBuild;
worker.wakeUp(shared_from_this());
}

void DerivationGoal::tryLocalBuild() {

/* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */
if (settings.buildUsersGroup != "" && getuid() == 0) {
#if defined(__linux__) || defined(__APPLE__)
if (!buildUser) buildUser = std::make_unique<UserLock>();

if (buildUser->findFreeUser()) {
/* Make sure that no other processes are executing under this
uid. */
buildUser->kill();
} else {
debug("waiting for build users");
worker.waitForAWhile(shared_from_this());
return;
}
#else
/* Don't know how to block the creation of setuid/setgid
binaries on this platform. */
throw Error("build users are not supported on this platform for security reasons");
#endif
}

try {

/* Okay, we have to build. */
Expand Down Expand Up @@ -1943,22 +1980,6 @@ void DerivationGoal::startBuilder()
#endif
}

/* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */
if (settings.buildUsersGroup != "" && getuid() == 0) {
#if defined(__linux__) || defined(__APPLE__)
buildUser = std::make_unique<UserLock>();

/* Make sure that no other processes are executing under this
uid. */
buildUser->kill();
#else
/* Don't know how to block the creation of setuid/setgid
binaries on this platform. */
throw Error("build users are not supported on this platform for security reasons");
#endif
}

/* Create a temporary directory where the build will take
place. */
tmpDir = createTempDir("", "nix-build-" + std::string(drvPath.name()), false, false, 0700);
Expand Down Expand Up @@ -4820,7 +4841,7 @@ void Worker::waitForInput()
if (!waitingForAWhile.empty()) {
useTimeout = true;
if (lastWokenUp == steady_time_point::min())
printError("waiting for locks or build slots...");
printError("waiting for locks, build slots or build users...");
if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) lastWokenUp = before;
timeout = std::max(1L,
(long) std::chrono::duration_cast<std::chrono::seconds>(
Expand Down

0 comments on commit 0ed946a

Please sign in to comment.