Skip to content

Commit

Permalink
Merge pull request #3924 from obsidiansystems/features-per-store
Browse files Browse the repository at this point in the history
Make `system-features` a store setting
  • Loading branch information
edolstra authored Aug 14, 2020
2 parents 9b9d529 + 4720853 commit 7714d9a
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 38 deletions.
16 changes: 4 additions & 12 deletions src/build-remote/build-remote.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot)
return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true);
}

static bool allSupportedLocally(const std::set<std::string>& requiredFeatures) {
static bool allSupportedLocally(Store & store, const std::set<std::string>& requiredFeatures) {
for (auto & feature : requiredFeatures)
if (!settings.systemFeatures.get().count(feature)) return false;
if (!store.systemFeatures.get().count(feature)) return false;
return true;
}

Expand Down Expand Up @@ -106,7 +106,7 @@ static int _main(int argc, char * * argv)
auto canBuildLocally = amWilling
&& ( neededSystem == settings.thisSystem
|| settings.extraPlatforms.get().count(neededSystem) > 0)
&& allSupportedLocally(requiredFeatures);
&& allSupportedLocally(*store, requiredFeatures);

/* Error ignored here, will be caught later */
mkdir(currentLoad.c_str(), 0777);
Expand Down Expand Up @@ -224,15 +224,7 @@ static int _main(int argc, char * * argv)

Activity act(*logger, lvlTalkative, actUnknown, fmt("connecting to '%s'", bestMachine->storeUri));

Store::Params storeParams;
if (hasPrefix(bestMachine->storeUri, "ssh://")) {
storeParams["max-connections"] = "1";
storeParams["log-fd"] = "4";
if (bestMachine->sshKey != "")
storeParams["ssh-key"] = bestMachine->sshKey;
}

sshStore = openStore(bestMachine->storeUri, storeParams);
sshStore = bestMachine->openStore();
sshStore->connect();
storeUri = bestMachine->storeUri;

Expand Down
8 changes: 4 additions & 4 deletions src/libstore/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ void DerivationGoal::tryToBuild()
/* Don't do a remote build if the derivation has the attribute
`preferLocalBuild' set. Also, check and repair modes are only
supported for local builds. */
bool buildLocally = buildMode != bmNormal || parsedDrv->willBuildLocally();
bool buildLocally = buildMode != bmNormal || parsedDrv->willBuildLocally(worker.store);

/* Is the build hook willing to accept this job? */
if (!buildLocally) {
Expand Down Expand Up @@ -1964,13 +1964,13 @@ void linkOrCopy(const Path & from, const Path & to)
void DerivationGoal::startBuilder()
{
/* Right platform? */
if (!parsedDrv->canBuildLocally())
if (!parsedDrv->canBuildLocally(worker.store))
throw Error("a '%s' with features {%s} is required to build '%s', but I am a '%s' with features {%s}",
drv->platform,
concatStringsSep(", ", parsedDrv->getRequiredSystemFeatures()),
worker.store.printStorePath(drvPath),
settings.thisSystem,
concatStringsSep<StringSet>(", ", settings.systemFeatures));
concatStringsSep<StringSet>(", ", worker.store.systemFeatures));

if (drv->isBuiltin())
preloadNSS();
Expand Down Expand Up @@ -3180,7 +3180,7 @@ void DerivationGoal::runChild()
createDirs(chrootRootDir + "/dev/shm");
createDirs(chrootRootDir + "/dev/pts");
ss.push_back("/dev/full");
if (settings.systemFeatures.get().count("kvm") && pathExists("/dev/kvm"))
if (worker.store.systemFeatures.get().count("kvm") && pathExists("/dev/kvm"))
ss.push_back("/dev/kvm");
ss.push_back("/dev/null");
ss.push_back("/dev/random");
Expand Down
24 changes: 24 additions & 0 deletions src/libstore/machines.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "machines.hh"
#include "util.hh"
#include "globals.hh"
#include "store-api.hh"

#include <algorithm>

Expand Down Expand Up @@ -48,6 +49,29 @@ bool Machine::mandatoryMet(const std::set<string> & features) const {
});
}

ref<Store> Machine::openStore() const {
Store::Params storeParams;
if (hasPrefix(storeUri, "ssh://")) {
storeParams["max-connections"] = "1";
storeParams["log-fd"] = "4";
if (sshKey != "")
storeParams["ssh-key"] = sshKey;
}
{
auto & fs = storeParams["system-features"];
auto append = [&](auto feats) {
for (auto & f : feats) {
if (fs.size() > 0) fs += ' ';
fs += f;
}
};
append(supportedFeatures);
append(mandatoryFeatures);
}

return nix::openStore(storeUri, storeParams);
}

void parseMachines(const std::string & s, Machines & machines)
{
for (auto line : tokenizeString<std::vector<string>>(s, "\n;")) {
Expand Down
4 changes: 4 additions & 0 deletions src/libstore/machines.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace nix {

class Store;

struct Machine {

const string storeUri;
Expand All @@ -28,6 +30,8 @@ struct Machine {
decltype(supportedFeatures) supportedFeatures,
decltype(mandatoryFeatures) mandatoryFeatures,
decltype(sshPublicHostKey) sshPublicHostKey);

ref<Store> openStore() const;
};

typedef std::vector<Machine> Machines;
Expand Down
8 changes: 4 additions & 4 deletions src/libstore/parsed-derivations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,22 @@ StringSet ParsedDerivation::getRequiredSystemFeatures() const
return res;
}

bool ParsedDerivation::canBuildLocally() const
bool ParsedDerivation::canBuildLocally(Store & localStore) const
{
if (drv.platform != settings.thisSystem.get()
&& !settings.extraPlatforms.get().count(drv.platform)
&& !drv.isBuiltin())
return false;

for (auto & feature : getRequiredSystemFeatures())
if (!settings.systemFeatures.get().count(feature)) return false;
if (!localStore.systemFeatures.get().count(feature)) return false;

return true;
}

bool ParsedDerivation::willBuildLocally() const
bool ParsedDerivation::willBuildLocally(Store & localStore) const
{
return getBoolAttr("preferLocalBuild") && canBuildLocally();
return getBoolAttr("preferLocalBuild") && canBuildLocally(localStore);
}

bool ParsedDerivation::substitutesAllowed() const
Expand Down
4 changes: 2 additions & 2 deletions src/libstore/parsed-derivations.hh
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public:

StringSet getRequiredSystemFeatures() const;

bool canBuildLocally() const;
bool canBuildLocally(Store & localStore) const;

bool willBuildLocally() const;
bool willBuildLocally(Store & localStore) const;

bool substitutesAllowed() const;
};
Expand Down
4 changes: 4 additions & 0 deletions src/libstore/store-api.hh
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ public:

Setting<bool> wantMassQuery{this, false, "want-mass-query", "whether this substituter can be queried efficiently for path validity"};

Setting<StringSet> systemFeatures{this, settings.systemFeatures,
"system-features",
"Optional features that the system this store builds on implements (like \"kvm\")."};

protected:

struct PathInfoCacheValue {
Expand Down
3 changes: 2 additions & 1 deletion tests/build-hook.nix
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let
shell = busybox;
name = "build-remote-input-2";
buildCommand = "echo BAR > $out";
requiredSystemFeatures = ["bar"];
};

in
Expand All @@ -34,6 +35,6 @@ in
''
read x < ${input1}
read y < ${input2}
echo $x$y > $out
echo "$x $y" > $out
'';
}
33 changes: 19 additions & 14 deletions tests/build-remote.sh
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
source common.sh

clearStore

if ! canUseSandbox; then exit; fi
if ! [[ $busybox =~ busybox ]]; then exit; fi

chmod -R u+w $TEST_ROOT/machine0 || true
chmod -R u+w $TEST_ROOT/machine1 || true
chmod -R u+w $TEST_ROOT/machine2 || true
rm -rf $TEST_ROOT/machine0 $TEST_ROOT/machine1 $TEST_ROOT/machine2
rm -f $TEST_ROOT/result

unset NIX_STORE_DIR
unset NIX_STATE_DIR

function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

builders=(
# system-features will automatically be added to the outer URL, but not inner
# remote-store URL.
"ssh://localhost?remote-store=$TEST_ROOT/machine1?system-features=foo - - 1 1 foo"
"$TEST_ROOT/machine2 - - 1 1 bar"
)

# Note: ssh://localhost bypasses ssh, directly invoking nix-store as a
# child process. This allows us to test LegacySSHStore::buildDerivation().
# ssh-ng://... likewise allows us to test RemoteStore::buildDerivation().
nix build -L -v -f build-hook.nix -o $TEST_ROOT/result --max-jobs 0 \
--arg busybox $busybox \
--store $TEST_ROOT/machine0 \
--builders "ssh://localhost?remote-store=$TEST_ROOT/machine1; $TEST_ROOT/machine2 - - 1 1 foo" \
--system-features foo
--builders "$(join_by '; ' "${builders[@]}")"

outPath=$(readlink -f $TEST_ROOT/result)

cat $TEST_ROOT/machine0/$outPath | grep FOOBAR
grep 'FOO BAR' $TEST_ROOT/machine0/$outPath

# Ensure that input1 was built on store1 due to the required feature.
(! nix path-info --store $TEST_ROOT/machine2 --all | grep builder-build-remote-input-1.sh)
nix path-info --store $TEST_ROOT/machine1 --all | grep builder-build-remote-input-1.sh

# Ensure that input1 was built on store2 due to the required feature.
(! nix path-info --store $TEST_ROOT/machine1 --all | grep builder-build-remote-input-1.sh)
nix path-info --store $TEST_ROOT/machine2 --all | grep builder-build-remote-input-1.sh
# Ensure that input2 was built on store2 due to the required feature.
(! nix path-info --store $TEST_ROOT/machine1 --all | grep builder-build-remote-input-2.sh)
nix path-info --store $TEST_ROOT/machine2 --all | grep builder-build-remote-input-2.sh
2 changes: 1 addition & 1 deletion tests/local.mk
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
nix_tests = \
init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \
hash.sh lang.sh add.sh simple.sh dependencies.sh \
config.sh \
gc.sh \
gc-concurrent.sh \
Expand Down

0 comments on commit 7714d9a

Please sign in to comment.