aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2021-01-25 12:24:23 +0100
committerGitHub <noreply@github.com>2021-01-25 12:24:23 +0100
commit680d8a5b86979620927714f061e0ca40d6281b8e (patch)
treeb483acf9fa5441d7117032a99d86ec5a07bc7132 /src
parent29edbfe2d2578d8166bd1a13373b69bf35cf8ee9 (diff)
parent53a709535b42197a9abd3fe46406bb186ad6c751 (diff)
Merge pull request #4387 from obsidiansystems/non-local-store-build
Make `nix-build --store whatever` work
Diffstat (limited to 'src')
-rw-r--r--src/build-remote/build-remote.cc13
-rw-r--r--src/libstore/binary-cache-store.hh7
-rw-r--r--src/libstore/build/derivation-goal.cc86
-rw-r--r--src/libstore/build/entry-points.cc (renamed from src/libstore/build/local-store-build.cc)6
-rw-r--r--src/libstore/build/substitution-goal.cc4
-rw-r--r--src/libstore/build/worker.cc6
-rw-r--r--src/libstore/build/worker.hh9
-rw-r--r--src/libstore/dummy-store.cc7
-rw-r--r--src/libstore/local-store.cc7
-rw-r--r--src/libstore/local-store.hh11
-rw-r--r--src/libstore/store-api.cc23
-rw-r--r--src/libstore/store-api.hh21
12 files changed, 109 insertions, 91 deletions
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index 8348d8c91..68af3e966 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -71,11 +71,15 @@ static int main_build_remote(int argc, char * * argv)
initPlugins();
- auto store = openStore().cast<LocalStore>();
+ auto store = openStore();
/* It would be more appropriate to use $XDG_RUNTIME_DIR, since
that gets cleared on reboot, but it wouldn't work on macOS. */
- currentLoad = store->stateDir + "/current-load";
+ auto currentLoadName = "/current-load";
+ if (auto localStore = store.dynamic_pointer_cast<LocalFSStore>())
+ currentLoad = std::string { localStore->stateDir } + currentLoadName;
+ else
+ currentLoad = settings.nixStateDir + currentLoadName;
std::shared_ptr<Store> sshStore;
AutoCloseFD bestSlotLock;
@@ -288,8 +292,9 @@ connected:
if (!missing.empty()) {
Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
- for (auto & i : missing)
- store->locksHeld.insert(store->printStorePath(i)); /* FIXME: ugly */
+ if (auto localStore = store.dynamic_pointer_cast<LocalStore>())
+ for (auto & i : missing)
+ localStore->locksHeld.insert(store->printStorePath(i)); /* FIXME: ugly */
copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute);
}
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index 443a53cac..c2163166c 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -108,13 +108,6 @@ public:
void narFromPath(const StorePath & path, Sink & sink) override;
- BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
- BuildMode buildMode) override
- { unsupported("buildDerivation"); }
-
- void ensurePath(const StorePath & path) override
- { unsupported("ensurePath"); }
-
ref<FSAccessor> getFSAccessor() override;
void addSignatures(const StorePath & storePath, const StringSet & sigs) override;
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 2e74cfd6c..fa8b99118 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -597,9 +597,17 @@ void DerivationGoal::tryToBuild()
PathSet lockFiles;
/* FIXME: Should lock something like the drv itself so we don't build same
CA drv concurrently */
- for (auto & i : drv->outputsAndOptPaths(worker.store))
- if (i.second.second)
- lockFiles.insert(worker.store.Store::toRealPath(*i.second.second));
+ if (dynamic_cast<LocalStore *>(&worker.store))
+ /* If we aren't a local store, we might need to use the local store as
+ a build remote, but that would cause a deadlock. */
+ /* FIXME: Make it so we can use ourselves as a build remote even if we
+ are the local store (separate locking for building vs scheduling? */
+ /* FIXME: find some way to lock for scheduling for the other stores so
+ a forking daemon with --store still won't farm out redundant builds.
+ */
+ for (auto & i : drv->outputsAndOptPaths(worker.store))
+ if (i.second.second)
+ lockFiles.insert(worker.store.Store::toRealPath(*i.second.second));
if (!outputLocks.lockPaths(lockFiles, "", false)) {
if (!actLock)
@@ -681,6 +689,12 @@ void DerivationGoal::tryToBuild()
void DerivationGoal::tryLocalBuild() {
/* Make sure that we are allowed to start a build. */
+ if (!dynamic_cast<LocalStore *>(&worker.store)) {
+ throw Error(
+ "unable to build with a primary store that isn't a local store; "
+ "either pass a different '--store' or enable remote builds."
+ "\nhttps://nixos.org/nix/manual/#chap-distributed-builds");
+ }
unsigned int curBuilds = worker.getNrLocalBuilds();
if (curBuilds >= settings.maxBuildJobs) {
worker.waitForBuildSlot(shared_from_this());
@@ -849,14 +863,16 @@ void DerivationGoal::buildDone()
So instead, check if the disk is (nearly) full now. If
so, we don't mark this build as a permanent failure. */
#if HAVE_STATVFS
- uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable
- struct statvfs st;
- if (statvfs(worker.store.realStoreDir.c_str(), &st) == 0 &&
- (uint64_t) st.f_bavail * st.f_bsize < required)
- diskFull = true;
- if (statvfs(tmpDir.c_str(), &st) == 0 &&
- (uint64_t) st.f_bavail * st.f_bsize < required)
- diskFull = true;
+ if (auto localStore = dynamic_cast<LocalStore *>(&worker.store)) {
+ uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable
+ struct statvfs st;
+ if (statvfs(localStore->realStoreDir.c_str(), &st) == 0 &&
+ (uint64_t) st.f_bavail * st.f_bsize < required)
+ diskFull = true;
+ if (statvfs(tmpDir.c_str(), &st) == 0 &&
+ (uint64_t) st.f_bavail * st.f_bsize < required)
+ diskFull = true;
+ }
#endif
deleteTmpDir(false);
@@ -1216,12 +1232,15 @@ void DerivationGoal::startBuilder()
useChroot = !(derivationIsImpure(derivationType)) && !noChroot;
}
- if (worker.store.storeDir != worker.store.realStoreDir) {
- #if __linux__
- useChroot = true;
- #else
- throw Error("building using a diverted store is not supported on this platform");
- #endif
+ if (auto localStoreP = dynamic_cast<LocalStore *>(&worker.store)) {
+ auto & localStore = *localStoreP;
+ if (localStore.storeDir != localStore.realStoreDir) {
+ #if __linux__
+ useChroot = true;
+ #else
+ throw Error("building using a diverted store is not supported on this platform");
+ #endif
+ }
}
/* Create a temporary directory where the build will take
@@ -2181,7 +2200,8 @@ void DerivationGoal::startDaemon()
Store::Params params;
params["path-info-cache-size"] = "0";
params["store"] = worker.store.storeDir;
- params["root"] = worker.store.rootDir;
+ if (auto localStore = dynamic_cast<LocalStore *>(&worker.store))
+ params["root"] = localStore->rootDir;
params["state"] = "/no-such-path";
params["log"] = "/no-such-path";
auto store = make_ref<RestrictedStore>(params,
@@ -3269,7 +3289,13 @@ void DerivationGoal::registerOutputs()
}
}
+ auto localStoreP = dynamic_cast<LocalStore *>(&worker.store);
+ if (!localStoreP)
+ throw Unsupported("can only register outputs with local store, but this is %s", worker.store.getUri());
+ auto & localStore = *localStoreP;
+
if (buildMode == bmCheck) {
+
if (!worker.store.isValidPath(newInfo.path)) continue;
ValidPathInfo oldInfo(*worker.store.queryPathInfo(newInfo.path));
if (newInfo.narHash != oldInfo.narHash) {
@@ -3294,8 +3320,8 @@ void DerivationGoal::registerOutputs()
/* Since we verified the build, it's now ultimately trusted. */
if (!oldInfo.ultimate) {
oldInfo.ultimate = true;
- worker.store.signPathInfo(oldInfo);
- worker.store.registerValidPaths({{oldInfo.path, oldInfo}});
+ localStore.signPathInfo(oldInfo);
+ localStore.registerValidPaths({{oldInfo.path, oldInfo}});
}
continue;
@@ -3311,13 +3337,13 @@ void DerivationGoal::registerOutputs()
}
if (curRound == nrRounds) {
- worker.store.optimisePath(actualPath); // FIXME: combine with scanForReferences()
+ localStore.optimisePath(actualPath); // FIXME: combine with scanForReferences()
worker.markContentsGood(newInfo.path);
}
newInfo.deriver = drvPath;
newInfo.ultimate = true;
- worker.store.signPathInfo(newInfo);
+ localStore.signPathInfo(newInfo);
finish(newInfo.path);
@@ -3325,7 +3351,7 @@ void DerivationGoal::registerOutputs()
isn't statically known so that we can safely unlock the path before
the next iteration */
if (newInfo.ca)
- worker.store.registerValidPaths({{newInfo.path, newInfo}});
+ localStore.registerValidPaths({{newInfo.path, newInfo}});
infos.emplace(outputName, std::move(newInfo));
}
@@ -3398,11 +3424,16 @@ void DerivationGoal::registerOutputs()
paths referenced by each of them. If there are cycles in the
outputs, this will fail. */
{
+ auto localStoreP = dynamic_cast<LocalStore *>(&worker.store);
+ if (!localStoreP)
+ throw Unsupported("can only register outputs with local store, but this is %s", worker.store.getUri());
+ auto & localStore = *localStoreP;
+
ValidPathInfos infos2;
for (auto & [outputName, newInfo] : infos) {
infos2.insert_or_assign(newInfo.path, newInfo);
}
- worker.store.registerValidPaths(infos2);
+ localStore.registerValidPaths(infos2);
}
/* In case of a fixed-output derivation hash mismatch, throw an
@@ -3600,7 +3631,12 @@ Path DerivationGoal::openLogFile()
auto baseName = std::string(baseNameOf(worker.store.printStorePath(drvPath)));
/* Create a log file. */
- Path dir = fmt("%s/%s/%s/", worker.store.logDir, worker.store.drvsLogDir, string(baseName, 0, 2));
+ Path logDir;
+ if (auto localStore = dynamic_cast<LocalStore *>(&worker.store))
+ logDir = localStore->logDir;
+ else
+ logDir = settings.nixLogDir;
+ Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, string(baseName, 0, 2));
createDirs(dir);
Path logFileName = fmt("%s/%s%s", dir, string(baseName, 2),
diff --git a/src/libstore/build/local-store-build.cc b/src/libstore/build/entry-points.cc
index c91cda2fd..9f97d40ba 100644
--- a/src/libstore/build/local-store-build.cc
+++ b/src/libstore/build/entry-points.cc
@@ -5,7 +5,7 @@
namespace nix {
-void LocalStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths, BuildMode buildMode)
+void Store::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths, BuildMode buildMode)
{
Worker worker(*this);
@@ -43,7 +43,7 @@ void LocalStore::buildPaths(const std::vector<StorePathWithOutputs> & drvPaths,
}
}
-BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
+BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
BuildMode buildMode)
{
Worker worker(*this);
@@ -63,7 +63,7 @@ BuildResult LocalStore::buildDerivation(const StorePath & drvPath, const BasicDe
}
-void LocalStore::ensurePath(const StorePath & path)
+void Store::ensurePath(const StorePath & path)
{
/* If the path is already valid, we're done. */
if (isValidPath(path)) return;
diff --git a/src/libstore/build/substitution-goal.cc b/src/libstore/build/substitution-goal.cc
index d16584f65..f3c9040bc 100644
--- a/src/libstore/build/substitution-goal.cc
+++ b/src/libstore/build/substitution-goal.cc
@@ -142,9 +142,7 @@ void SubstitutionGoal::tryNext()
/* Bail out early if this substituter lacks a valid
signature. LocalStore::addToStore() also checks for this, but
only after we've downloaded the path. */
- if (worker.store.requireSigs
- && !sub->isTrusted
- && !info->checkSignatures(worker.store, worker.store.getPublicKeys()))
+ if (!sub->isTrusted && worker.store.pathInfoIsTrusted(*info))
{
logWarning({
.name = "Invalid path signature",
diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc
index 6c96a93bd..a9575fb0f 100644
--- a/src/libstore/build/worker.cc
+++ b/src/libstore/build/worker.cc
@@ -8,7 +8,7 @@
namespace nix {
-Worker::Worker(LocalStore & store)
+Worker::Worker(Store & store)
: act(*logger, actRealise)
, actDerivations(*logger, actBuilds)
, actSubstitutions(*logger, actCopyPaths)
@@ -229,7 +229,9 @@ void Worker::run(const Goals & _topGoals)
checkInterrupt();
- store.autoGC(false);
+ // TODO GC interface?
+ if (auto localStore = dynamic_cast<LocalStore *>(&store))
+ localStore->autoGC(false);
/* Call every wake goal (in the ordering established by
CompareGoalPtrs). */
diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh
index bf8cc4586..82e711191 100644
--- a/src/libstore/build/worker.hh
+++ b/src/libstore/build/worker.hh
@@ -2,9 +2,12 @@
#include "types.hh"
#include "lock.hh"
-#include "local-store.hh"
+#include "store-api.hh"
#include "goal.hh"
+#include <future>
+#include <thread>
+
namespace nix {
/* Forward definition. */
@@ -102,7 +105,7 @@ public:
/* Set if at least one derivation is not deterministic in check mode. */
bool checkMismatch;
- LocalStore & store;
+ Store & store;
std::unique_ptr<HookInstance> hook;
@@ -124,7 +127,7 @@ public:
it answers with "decline-permanently", we don't try again. */
bool tryBuildHook = true;
- Worker(LocalStore & store);
+ Worker(Store & store);
~Worker();
/* Make a goal (with caching). */
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index 3c7caf8f2..8f26af685 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -55,13 +55,6 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
void narFromPath(const StorePath & path, Sink & sink) override
{ unsupported("narFromPath"); }
- void ensurePath(const StorePath & path) override
- { unsupported("ensurePath"); }
-
- BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
- BuildMode buildMode) override
- { unsupported("buildDerivation"); }
-
std::optional<const Realisation> queryRealisation(const DrvOutput&) override
{ unsupported("queryRealisation"); }
};
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index ab78f1435..71e61cfe3 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -1098,7 +1098,6 @@ void LocalStore::invalidatePath(State & state, const StorePath & path)
}
}
-
const PublicKeys & LocalStore::getPublicKeys()
{
auto state(_state.lock());
@@ -1107,11 +1106,15 @@ const PublicKeys & LocalStore::getPublicKeys()
return *state->publicKeys;
}
+bool LocalStore::pathInfoIsTrusted(const ValidPathInfo & info)
+{
+ return requireSigs && !info.checkSignatures(*this, getPublicKeys());
+}
void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs)
{
- if (requireSigs && checkSigs && !info.checkSignatures(*this, getPublicKeys()))
+ if (checkSigs && pathInfoIsTrusted(info))
throw Error("cannot add path '%s' because it lacks a valid signature", printStorePath(info.path));
addTempRoot(info.path);
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 6c7ebac1e..9d235ba0a 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -136,6 +136,8 @@ public:
void querySubstitutablePathInfos(const StorePathCAMap & paths,
SubstitutablePathInfos & infos) override;
+ bool pathInfoIsTrusted(const ValidPathInfo &) override;
+
void addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs) override;
@@ -145,15 +147,6 @@ public:
StorePath addTextToStore(const string & name, const string & s,
const StorePathSet & references, RepairFlag repair) override;
- void buildPaths(
- const std::vector<StorePathWithOutputs> & paths,
- BuildMode buildMode) override;
-
- BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
- BuildMode buildMode) override;
-
- void ensurePath(const StorePath & path) override;
-
void addTempRoot(const StorePath & path) override;
void addIndirectRoot(const Path & path) override;
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 01e2fcc7b..d4ec1497f 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -747,29 +747,6 @@ const Store::Stats & Store::getStats()
}
-void Store::buildPaths(const std::vector<StorePathWithOutputs> & paths, BuildMode buildMode)
-{
- StorePathSet paths2;
-
- for (auto & path : paths) {
- if (path.path.isDerivation()) {
- auto outPaths = queryPartialDerivationOutputMap(path.path);
- for (auto & outputName : path.outputs) {
- auto currentOutputPathIter = outPaths.find(outputName);
- if (currentOutputPathIter == outPaths.end() ||
- !currentOutputPathIter->second ||
- !isValidPath(*currentOutputPathIter->second))
- unsupported("buildPaths");
- }
- } else
- paths2.insert(path.path);
- }
-
- if (queryValidPaths(paths2).size() != paths2.size())
- unsupported("buildPaths");
-}
-
-
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
const StorePath & storePath, RepairFlag repair, CheckSigsFlag checkSigs)
{
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index d1b83933a..9e98eb8f9 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -372,6 +372,21 @@ public:
void queryPathInfo(const StorePath & path,
Callback<ref<const ValidPathInfo>> callback) noexcept;
+ /* Check whether the given valid path info is sufficiently attested, by
+ either being signed by a trusted public key or content-addressed, in
+ order to be included in the given store.
+
+ These same checks would be performed in addToStore, but this allows an
+ earlier failure in the case where dependencies need to be added too, but
+ the addToStore wouldn't fail until those dependencies are added. Also,
+ we don't really want to add the dependencies listed in a nar info we
+ don't trust anyyways.
+ */
+ virtual bool pathInfoIsTrusted(const ValidPathInfo &)
+ {
+ return true;
+ }
+
protected:
virtual void queryPathInfoUncached(const StorePath & path,
@@ -519,17 +534,17 @@ public:
explicitly choosing to allow it).
*/
virtual BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
- BuildMode buildMode = bmNormal) = 0;
+ BuildMode buildMode = bmNormal);
/* Ensure that a path is valid. If it is not currently valid, it
may be made valid by running a substitute (if defined for the
path). */
- virtual void ensurePath(const StorePath & path) = 0;
+ virtual void ensurePath(const StorePath & path);
/* Add a store path as a temporary root of the garbage collector.
The root disappears as soon as we exit. */
virtual void addTempRoot(const StorePath & path)
- { unsupported("addTempRoot"); }
+ { warn("not creating temp root, store doesn't support GC"); }
/* Add an indirect root, which is merely a symlink to `path' from
/nix/var/nix/gcroots/auto/<hash of `path'>. `path' is supposed