aboutsummaryrefslogtreecommitdiff
path: root/src/build-remote/build-remote.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/build-remote/build-remote.cc')
-rw-r--r--src/build-remote/build-remote.cc160
1 files changed, 52 insertions, 108 deletions
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index d7aee2886..7ffbdca7c 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -9,6 +9,7 @@
#include <sys/time.h>
#endif
+#include "machines.hh"
#include "shared.hh"
#include "pathlocks.hh"
#include "globals.hh"
@@ -22,131 +23,56 @@ using std::cin;
static void handleAlarm(int sig) {
}
-class Machine {
- const std::set<string> supportedFeatures;
- const std::set<string> mandatoryFeatures;
-
-public:
- const string hostName;
- const std::vector<string> systemTypes;
- const string sshKey;
- const unsigned int maxJobs;
- const unsigned int speedFactor;
- bool enabled;
-
- bool allSupported(const std::set<string> & features) const {
- return std::all_of(features.begin(), features.end(),
- [&](const string & feature) {
- return supportedFeatures.count(feature) ||
- mandatoryFeatures.count(feature);
- });
- }
-
- bool mandatoryMet(const std::set<string> & features) const {
- return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(),
- [&](const string & feature) {
- return features.count(feature);
- });
- }
-
- Machine(decltype(hostName) hostName,
- decltype(systemTypes) systemTypes,
- decltype(sshKey) sshKey,
- decltype(maxJobs) maxJobs,
- decltype(speedFactor) speedFactor,
- decltype(supportedFeatures) supportedFeatures,
- decltype(mandatoryFeatures) mandatoryFeatures) :
- supportedFeatures(supportedFeatures),
- mandatoryFeatures(mandatoryFeatures),
- hostName(hostName),
- systemTypes(systemTypes),
- sshKey(sshKey),
- maxJobs(maxJobs),
- speedFactor(std::max(1U, speedFactor)),
- enabled(true)
- {};
-};;
-
-static std::vector<Machine> readConf()
+std::string escapeUri(std::string uri)
{
- auto conf = getEnv("NIX_REMOTE_SYSTEMS", SYSCONFDIR "/nix/machines");
-
- auto machines = std::vector<Machine>{};
- auto lines = std::vector<string>{};
- try {
- lines = tokenizeString<std::vector<string>>(readFile(conf), "\n");
- } catch (const SysError & e) {
- if (e.errNo != ENOENT)
- throw;
- }
- for (auto line : lines) {
- chomp(line);
- line.erase(std::find(line.begin(), line.end(), '#'), line.end());
- if (line.empty()) {
- continue;
- }
- auto tokens = tokenizeString<std::vector<string>>(line);
- auto sz = tokens.size();
- if (sz < 4)
- throw FormatError("bad machines.conf file ‘%1%’", conf);
- machines.emplace_back(tokens[0],
- tokenizeString<std::vector<string>>(tokens[1], ","),
- tokens[2],
- stoull(tokens[3]),
- sz >= 5 ? stoull(tokens[4]) : 1LL,
- sz >= 6 ?
- tokenizeString<std::set<string>>(tokens[5], ",") :
- std::set<string>{},
- sz >= 7 ?
- tokenizeString<std::set<string>>(tokens[6], ",") :
- std::set<string>{});
- }
- return machines;
+ std::replace(uri.begin(), uri.end(), '/', '_');
+ return uri;
}
static string currentLoad;
static AutoCloseFD openSlotLock(const Machine & m, unsigned long long slot)
{
- std::ostringstream fn_stream(currentLoad, std::ios_base::ate | std::ios_base::out);
- fn_stream << "/";
- for (auto t : m.systemTypes) {
- fn_stream << t << "-";
- }
- fn_stream << m.hostName << "-" << slot;
- return openLockFile(fn_stream.str(), true);
+ return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true);
}
-static char display_env[] = "DISPLAY=";
-static char ssh_env[] = "SSH_ASKPASS=";
-
int main (int argc, char * * argv)
{
return handleExceptions(argv[0], [&]() {
initNix();
/* Ensure we don't get any SSH passphrase or host key popups. */
- if (putenv(display_env) == -1 ||
- putenv(ssh_env) == -1)
- throw SysError("setting SSH env vars");
+ unsetenv("DISPLAY");
+ unsetenv("SSH_ASKPASS");
- if (argc != 4)
+ if (argc != 6)
throw UsageError("called without required arguments");
auto store = openStore();
auto localSystem = argv[1];
- settings.maxSilentTime = stoull(string(argv[2]));
- settings.buildTimeout = stoull(string(argv[3]));
+ settings.maxSilentTime = std::stoll(argv[2]);
+ settings.buildTimeout = std::stoll(argv[3]);
+ verbosity = (Verbosity) std::stoll(argv[4]);
+ settings.builders = argv[5];
- currentLoad = getEnv("NIX_CURRENT_LOAD", "/run/nix/current-load");
+ /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
+ that gets cleared on reboot, but it wouldn't work on OS X. */
+ currentLoad = settings.nixStateDir + "/current-load";
std::shared_ptr<Store> sshStore;
AutoCloseFD bestSlotLock;
- auto machines = readConf();
+ auto machines = getMachines();
+ debug("got %d remote builders", machines.size());
+
+ if (machines.empty()) {
+ std::cerr << "# decline-permanently\n";
+ return;
+ }
+
string drvPath;
- string hostName;
+ string storeUri;
for (string line; getline(cin, line);) {
auto tokens = tokenizeString<std::vector<string>>(line);
auto sz = tokens.size();
@@ -173,6 +99,8 @@ int main (int argc, char * * argv)
Machine * bestMachine = nullptr;
unsigned long long bestLoad = 0;
for (auto & m : machines) {
+ debug("considering building on ‘%s’", m.storeUri);
+
if (m.enabled && std::find(m.systemTypes.begin(),
m.systemTypes.end(),
neededSystem) != m.systemTypes.end() &&
@@ -233,16 +161,22 @@ int main (int argc, char * * argv)
lock = -1;
try {
- sshStore = openStore("ssh-ng://" + bestMachine->hostName,
- { {"ssh-key", bestMachine->sshKey },
- {"max-connections", "1" } });
- hostName = bestMachine->hostName;
+
+ Store::Params storeParams{{"max-connections", "1"}, {"log-fd", "4"}};
+ if (bestMachine->sshKey != "")
+ storeParams["ssh-key"] = bestMachine->sshKey;
+
+ sshStore = openStore(bestMachine->storeUri, storeParams);
+ sshStore->connect();
+ storeUri = bestMachine->storeUri;
+
} catch (std::exception & e) {
printError("unable to open SSH connection to ‘%s’: %s; trying other available machines...",
- bestMachine->hostName, e.what());
+ bestMachine->storeUri, e.what());
bestMachine->enabled = false;
continue;
}
+
goto connected;
}
}
@@ -252,22 +186,32 @@ connected:
string line;
if (!getline(cin, line))
throw Error("hook caller didn't send inputs");
+
auto inputs = tokenizeString<PathSet>(line);
if (!getline(cin, line))
throw Error("hook caller didn't send outputs");
+
auto outputs = tokenizeString<PathSet>(line);
- AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + hostName + ".upload-lock", true);
+
+ AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + escapeUri(storeUri) + ".upload-lock", true);
+
auto old = signal(SIGALRM, handleAlarm);
alarm(15 * 60);
if (!lockFile(uploadLock.get(), ltWrite, true))
printError("somebody is hogging the upload lock for ‘%s’, continuing...");
alarm(0);
signal(SIGALRM, old);
- copyPaths(store, ref<Store>(sshStore), inputs);
+ copyPaths(store, ref<Store>(sshStore), inputs, false, true);
uploadLock = -1;
- printError("building ‘%s’ on ‘%s’", drvPath, hostName);
- sshStore->buildDerivation(drvPath, readDerivation(drvPath));
+ BasicDerivation drv(readDerivation(drvPath));
+ drv.inputSrcs = inputs;
+
+ printError("building ‘%s’ on ‘%s’", drvPath, storeUri);
+ auto result = sshStore->buildDerivation(drvPath, drv);
+
+ if (!result.success())
+ throw Error("build of ‘%s’ on ‘%s’ failed: %s", drvPath, storeUri, result.errorMsg);
PathSet missing;
for (auto & path : outputs)
@@ -275,7 +219,7 @@ connected:
if (!missing.empty()) {
setenv("NIX_HELD_LOCKS", concatStringsSep(" ", missing).c_str(), 1); /* FIXME: ugly */
- copyPaths(ref<Store>(sshStore), store, missing);
+ copyPaths(ref<Store>(sshStore), store, missing, false, true);
}
return;