Support optional sandbox paths
For example, you can now set build-sandbox-paths = /dev/nvidiactl? to specify that /dev/nvidiactl should only be mounted in the sandbox if it exists in the host filesystem. This is useful e.g. for EC2 images that should support both CUDA and non-CUDA instances.
This commit is contained in:
parent
c4969aebaf
commit
18b7363a69
2 changed files with 32 additions and 10 deletions
|
@ -268,7 +268,12 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
|
||||||
to mount a path in a different location in the sandbox; for
|
to mount a path in a different location in the sandbox; for
|
||||||
instance, <literal>/bin=/nix-bin</literal> will mount the path
|
instance, <literal>/bin=/nix-bin</literal> will mount the path
|
||||||
<literal>/nix-bin</literal> as <literal>/bin</literal> inside the
|
<literal>/nix-bin</literal> as <literal>/bin</literal> inside the
|
||||||
sandbox.</para>
|
sandbox. If <replaceable>source</replaceable> is followed by
|
||||||
|
<literal>?</literal>, then it is not an error if
|
||||||
|
<replaceable>source</replaceable> does not exist; for example,
|
||||||
|
<literal>/dev/nvidiactl?</literal> specifies that
|
||||||
|
<filename>/dev/nvidiactl</filename> will only be mounted in the
|
||||||
|
sandbox if it exists in the host filesystem.</para>
|
||||||
|
|
||||||
<para>Depending on how Nix was built, the default value for this option
|
<para>Depending on how Nix was built, the default value for this option
|
||||||
may be empty or provide <filename>/bin/sh</filename> as a
|
may be empty or provide <filename>/bin/sh</filename> as a
|
||||||
|
|
|
@ -768,7 +768,14 @@ private:
|
||||||
GoalState state;
|
GoalState state;
|
||||||
|
|
||||||
/* Stuff we need to pass to initChild(). */
|
/* Stuff we need to pass to initChild(). */
|
||||||
typedef map<Path, Path> DirsInChroot; // maps target path to source path
|
struct ChrootPath {
|
||||||
|
Path source;
|
||||||
|
bool optional;
|
||||||
|
ChrootPath(Path source = "", bool optional = false)
|
||||||
|
: source(source), optional(optional)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
|
||||||
DirsInChroot dirsInChroot;
|
DirsInChroot dirsInChroot;
|
||||||
typedef map<string, string> Environment;
|
typedef map<string, string> Environment;
|
||||||
Environment env;
|
Environment env;
|
||||||
|
@ -1865,12 +1872,18 @@ void DerivationGoal::startBuilder()
|
||||||
|
|
||||||
dirsInChroot.clear();
|
dirsInChroot.clear();
|
||||||
|
|
||||||
for (auto & i : dirs) {
|
for (auto i : dirs) {
|
||||||
|
if (i.empty()) continue;
|
||||||
|
bool optional = false;
|
||||||
|
if (i[i.size() - 1] == '?') {
|
||||||
|
optional = true;
|
||||||
|
i.pop_back();
|
||||||
|
}
|
||||||
size_t p = i.find('=');
|
size_t p = i.find('=');
|
||||||
if (p == string::npos)
|
if (p == string::npos)
|
||||||
dirsInChroot[i] = i;
|
dirsInChroot[i] = {i, optional};
|
||||||
else
|
else
|
||||||
dirsInChroot[string(i, 0, p)] = string(i, p + 1);
|
dirsInChroot[string(i, 0, p)] = {string(i, p + 1), optional};
|
||||||
}
|
}
|
||||||
dirsInChroot[tmpDirInSandbox] = tmpDir;
|
dirsInChroot[tmpDirInSandbox] = tmpDir;
|
||||||
|
|
||||||
|
@ -1878,8 +1891,8 @@ void DerivationGoal::startBuilder()
|
||||||
PathSet closure;
|
PathSet closure;
|
||||||
for (auto & i : dirsInChroot)
|
for (auto & i : dirsInChroot)
|
||||||
try {
|
try {
|
||||||
if (worker.store.isInStore(i.second))
|
if (worker.store.isInStore(i.second.source))
|
||||||
worker.store.computeFSClosure(worker.store.toStorePath(i.second), closure);
|
worker.store.computeFSClosure(worker.store.toStorePath(i.second.source), closure);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
throw Error(format("while processing ‘build-sandbox-paths’: %s") % e.what());
|
throw Error(format("while processing ‘build-sandbox-paths’: %s") % e.what());
|
||||||
}
|
}
|
||||||
|
@ -2325,12 +2338,16 @@ void DerivationGoal::runChild()
|
||||||
environment. */
|
environment. */
|
||||||
for (auto & i : dirsInChroot) {
|
for (auto & i : dirsInChroot) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
Path source = i.second;
|
Path source = i.second.source;
|
||||||
Path target = chrootRootDir + i.first;
|
Path target = chrootRootDir + i.first;
|
||||||
if (source == "/proc") continue; // backwards compatibility
|
if (source == "/proc") continue; // backwards compatibility
|
||||||
debug(format("bind mounting ‘%1%’ to ‘%2%’") % source % target);
|
debug(format("bind mounting ‘%1%’ to ‘%2%’") % source % target);
|
||||||
if (stat(source.c_str(), &st) == -1)
|
if (stat(source.c_str(), &st) == -1) {
|
||||||
|
if (i.second.optional && errno == ENOENT)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
throw SysError(format("getting attributes of path ‘%1%’") % source);
|
throw SysError(format("getting attributes of path ‘%1%’") % source);
|
||||||
|
}
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
createDirs(target);
|
createDirs(target);
|
||||||
else {
|
else {
|
||||||
|
|
Loading…
Reference in a new issue