2020-10-11 16:17:24 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "parsed-derivations.hh"
|
|
|
|
#include "lock.hh"
|
|
|
|
#include "local-store.hh"
|
2020-10-12 17:15:32 +00:00
|
|
|
#include "goal.hh"
|
2009-01-12 16:30:32 +00:00
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
using std::map;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2014-01-21 17:29:55 +00:00
|
|
|
struct HookInstance;
|
2004-06-18 18:09:32 +00:00
|
|
|
|
2010-08-25 20:44:28 +00:00
|
|
|
typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;
|
|
|
|
|
2020-09-15 15:19:45 +00:00
|
|
|
/* Unless we are repairing, we don't both to test validity and just assume it,
|
|
|
|
so the choices are `Absent` or `Valid`. */
|
|
|
|
enum struct PathStatus {
|
|
|
|
Corrupt,
|
|
|
|
Absent,
|
|
|
|
Valid,
|
|
|
|
};
|
|
|
|
|
2020-09-04 15:15:51 +00:00
|
|
|
struct InitialOutputStatus {
|
2020-08-07 19:09:26 +00:00
|
|
|
StorePath path;
|
2020-09-15 15:19:45 +00:00
|
|
|
PathStatus status;
|
2020-08-07 19:09:26 +00:00
|
|
|
/* Valid in the store, and additionally non-corrupt if we are repairing */
|
|
|
|
bool isValid() const {
|
2020-09-15 15:19:45 +00:00
|
|
|
return status == PathStatus::Valid;
|
|
|
|
}
|
|
|
|
/* Merely present, allowed to be corrupt */
|
|
|
|
bool isPresent() const {
|
|
|
|
return status == PathStatus::Corrupt
|
|
|
|
|| status == PathStatus::Valid;
|
2020-08-07 19:09:26 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-09-04 15:15:51 +00:00
|
|
|
struct InitialOutput {
|
2020-08-07 19:09:26 +00:00
|
|
|
bool wanted;
|
2020-09-04 15:15:51 +00:00
|
|
|
std::optional<InitialOutputStatus> known;
|
2020-08-07 19:09:26 +00:00
|
|
|
};
|
|
|
|
|
2005-01-19 11:16:11 +00:00
|
|
|
class DerivationGoal : public Goal
|
2004-05-11 18:05:44 +00:00
|
|
|
{
|
2004-06-18 18:09:32 +00:00
|
|
|
private:
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 15:57:40 +00:00
|
|
|
/* Whether to use an on-disk .drv file. */
|
|
|
|
bool useDerivation;
|
|
|
|
|
2005-01-20 16:01:07 +00:00
|
|
|
/* The path of the derivation. */
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePath drvPath;
|
2004-05-11 18:05:44 +00:00
|
|
|
|
2012-11-26 16:15:09 +00:00
|
|
|
/* The specific outputs that we need to build. Empty means all of
|
|
|
|
them. */
|
|
|
|
StringSet wantedOutputs;
|
|
|
|
|
|
|
|
/* Whether additional wanted outputs have been added. */
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 15:57:40 +00:00
|
|
|
bool needRestart = false;
|
2012-11-26 16:15:09 +00:00
|
|
|
|
2013-01-02 11:38:28 +00:00
|
|
|
/* Whether to retry substituting the outputs after building the
|
|
|
|
inputs. */
|
2018-06-05 14:04:41 +00:00
|
|
|
bool retrySubstitution;
|
2013-01-02 11:38:28 +00:00
|
|
|
|
2005-01-20 16:01:07 +00:00
|
|
|
/* The derivation stored at drvPath. */
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 15:57:40 +00:00
|
|
|
std::unique_ptr<BasicDerivation> drv;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2018-09-28 12:31:16 +00:00
|
|
|
std::unique_ptr<ParsedDerivation> parsedDrv;
|
2018-09-28 10:43:01 +00:00
|
|
|
|
2004-05-11 18:05:44 +00:00
|
|
|
/* The remainder is state held during the build. */
|
|
|
|
|
2020-08-07 19:09:26 +00:00
|
|
|
/* Locks on (fixed) output paths. */
|
2004-05-11 18:05:44 +00:00
|
|
|
PathLocks outputLocks;
|
|
|
|
|
2005-01-19 11:16:11 +00:00
|
|
|
/* All input paths (that is, the union of FS closures of the
|
|
|
|
immediate input paths). */
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePathSet inputPaths;
|
2004-05-11 18:05:44 +00:00
|
|
|
|
2020-09-04 15:15:51 +00:00
|
|
|
std::map<std::string, InitialOutput> initialOutputs;
|
2013-06-13 14:43:20 +00:00
|
|
|
|
2005-10-17 15:33:24 +00:00
|
|
|
/* User selected for running the builder. */
|
2017-01-25 11:45:38 +00:00
|
|
|
std::unique_ptr<UserLock> buildUser;
|
2005-10-17 15:33:24 +00:00
|
|
|
|
2004-05-11 18:05:44 +00:00
|
|
|
/* The process ID of the builder. */
|
2004-06-22 09:51:44 +00:00
|
|
|
Pid pid;
|
2004-05-11 18:05:44 +00:00
|
|
|
|
|
|
|
/* The temporary directory. */
|
|
|
|
Path tmpDir;
|
|
|
|
|
2015-12-02 13:59:07 +00:00
|
|
|
/* The path of the temporary directory in the sandbox. */
|
|
|
|
Path tmpDirInSandbox;
|
|
|
|
|
2004-05-11 18:05:44 +00:00
|
|
|
/* File descriptor for the log file. */
|
2012-07-17 13:40:12 +00:00
|
|
|
AutoCloseFD fdLogFile;
|
2016-05-04 13:46:25 +00:00
|
|
|
std::shared_ptr<BufferedSink> logFileSink, logSink;
|
2004-05-11 18:05:44 +00:00
|
|
|
|
2013-09-02 09:58:18 +00:00
|
|
|
/* Number of bytes received from the builder's stdout/stderr. */
|
|
|
|
unsigned long logSize;
|
|
|
|
|
2016-04-25 14:47:46 +00:00
|
|
|
/* The most recent log lines. */
|
|
|
|
std::list<std::string> logTail;
|
|
|
|
|
|
|
|
std::string currentLogLine;
|
2016-04-28 12:27:00 +00:00
|
|
|
size_t currentLogLinePos = 0; // to handle carriage return
|
2016-04-25 14:47:46 +00:00
|
|
|
|
2017-10-24 11:41:52 +00:00
|
|
|
std::string currentHookLine;
|
|
|
|
|
2004-05-11 18:05:44 +00:00
|
|
|
/* Pipe for the builder's standard output/error. */
|
2010-08-30 14:53:03 +00:00
|
|
|
Pipe builderOut;
|
2004-05-13 19:14:49 +00:00
|
|
|
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
/* Pipe for synchronising updates to the builder namespaces. */
|
2016-06-09 16:27:39 +00:00
|
|
|
Pipe userNamespaceSync;
|
|
|
|
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
/* The mount namespace of the builder, used to add additional
|
|
|
|
paths to the sandbox as a result of recursive Nix calls. */
|
|
|
|
AutoCloseFD sandboxMountNamespace;
|
|
|
|
|
2020-10-07 20:02:36 +00:00
|
|
|
/* On Linux, whether we're doing the build in its own user
|
|
|
|
namespace. */
|
|
|
|
bool usingUserNamespace = true;
|
|
|
|
|
2010-08-25 20:44:28 +00:00
|
|
|
/* The build hook. */
|
2017-01-19 14:15:09 +00:00
|
|
|
std::unique_ptr<HookInstance> hook;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2007-10-27 00:46:59 +00:00
|
|
|
/* Whether we're currently doing a chroot build. */
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 15:57:40 +00:00
|
|
|
bool useChroot = false;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2008-12-11 18:57:10 +00:00
|
|
|
Path chrootRootDir;
|
2007-10-27 00:46:59 +00:00
|
|
|
|
2008-12-11 17:00:12 +00:00
|
|
|
/* RAII object to delete the chroot directory. */
|
2014-03-29 23:49:23 +00:00
|
|
|
std::shared_ptr<AutoDelete> autoDelChroot;
|
2009-03-25 21:05:42 +00:00
|
|
|
|
2020-03-15 06:23:17 +00:00
|
|
|
/* The sort of derivation we are building. */
|
|
|
|
DerivationType derivationType;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2016-06-03 13:45:11 +00:00
|
|
|
/* Whether to run the build in a private network namespace. */
|
|
|
|
bool privateNetwork = false;
|
|
|
|
|
2005-01-19 11:16:11 +00:00
|
|
|
typedef void (DerivationGoal::*GoalState)();
|
2004-06-18 18:09:32 +00:00
|
|
|
GoalState state;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2012-06-25 19:45:16 +00:00
|
|
|
/* Stuff we need to pass to initChild(). */
|
2016-10-31 16:09:52 +00:00
|
|
|
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
|
2012-12-29 22:04:02 +00:00
|
|
|
DirsInChroot dirsInChroot;
|
2017-01-25 11:00:28 +00:00
|
|
|
|
2012-06-25 19:45:16 +00:00
|
|
|
typedef map<string, string> Environment;
|
|
|
|
Environment env;
|
2015-12-03 15:30:19 +00:00
|
|
|
|
|
|
|
#if __APPLE__
|
2015-11-13 03:00:16 +00:00
|
|
|
typedef string SandboxProfile;
|
|
|
|
SandboxProfile additionalSandboxProfile;
|
2015-11-15 11:08:50 +00:00
|
|
|
#endif
|
2012-06-25 19:45:16 +00:00
|
|
|
|
2012-09-11 22:39:22 +00:00
|
|
|
/* Hash rewriting. */
|
2018-03-29 22:56:13 +00:00
|
|
|
StringMap inputRewrites, outputRewrites;
|
2019-12-05 18:11:09 +00:00
|
|
|
typedef map<StorePath, StorePath> RedirectedOutputs;
|
2014-02-18 00:01:14 +00:00
|
|
|
RedirectedOutputs redirectedOutputs;
|
2012-09-11 22:39:22 +00:00
|
|
|
|
2020-08-07 19:09:26 +00:00
|
|
|
/* The outputs paths used during the build.
|
|
|
|
|
|
|
|
- Input-addressed derivations or fixed content-addressed outputs are
|
|
|
|
sometimes built when some of their outputs already exist, and can not
|
|
|
|
be hidden via sandboxing. We use temporary locations instead and
|
|
|
|
rewrite after the build. Otherwise the regular predetermined paths are
|
|
|
|
put here.
|
|
|
|
|
|
|
|
- Floating content-addressed derivations do not know their final build
|
|
|
|
output paths until the outputs are hashed, so random locations are
|
|
|
|
used, and then renamed. The randomness helps guard against hidden
|
|
|
|
self-references.
|
|
|
|
*/
|
|
|
|
OutputPathMap scratchOutputs;
|
|
|
|
|
|
|
|
/* The final output paths of the build.
|
|
|
|
|
|
|
|
- For input-addressed derivations, always the precomputed paths
|
|
|
|
|
|
|
|
- For content-addressed derivations, calcuated from whatever the hash
|
|
|
|
ends up being. (Note that fixed outputs derivations that produce the
|
|
|
|
"wrong" output still install that data under its true content-address.)
|
|
|
|
*/
|
2020-08-11 20:49:10 +00:00
|
|
|
OutputPathMap finalOutputs;
|
2020-08-07 19:09:26 +00:00
|
|
|
|
2014-02-17 22:04:52 +00:00
|
|
|
BuildMode buildMode;
|
|
|
|
|
|
|
|
/* If we're repairing without a chroot, there may be outputs that
|
|
|
|
are valid but corrupt. So we redirect these outputs to
|
|
|
|
temporary paths. */
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePathSet redirectedBadOutputs;
|
2012-10-02 21:13:46 +00:00
|
|
|
|
2015-07-20 01:15:45 +00:00
|
|
|
BuildResult result;
|
|
|
|
|
2015-11-09 22:16:24 +00:00
|
|
|
/* The current round, if we're building multiple times. */
|
2018-05-02 11:56:34 +00:00
|
|
|
size_t curRound = 1;
|
2015-11-09 22:16:24 +00:00
|
|
|
|
2018-05-02 11:56:34 +00:00
|
|
|
size_t nrRounds;
|
2015-11-09 22:16:24 +00:00
|
|
|
|
|
|
|
/* Path registration info from the previous round, if we're
|
|
|
|
building multiple times. Since this contains the hash, it
|
|
|
|
allows us to compare whether two rounds produced the same
|
|
|
|
result. */
|
2018-10-22 19:49:56 +00:00
|
|
|
std::map<Path, ValidPathInfo> prevInfos;
|
2015-11-09 22:16:24 +00:00
|
|
|
|
2020-10-07 20:46:01 +00:00
|
|
|
uid_t sandboxUid() { return usingUserNamespace ? 1000 : buildUser->getUID(); }
|
|
|
|
gid_t sandboxGid() { return usingUserNamespace ? 100 : buildUser->getGID(); }
|
2016-12-19 10:52:57 +00:00
|
|
|
|
2017-01-25 11:00:28 +00:00
|
|
|
const static Path homeDir;
|
|
|
|
|
2017-08-15 13:31:59 +00:00
|
|
|
std::unique_ptr<MaintainCount<uint64_t>> mcExpectedBuilds, mcRunningBuilds;
|
|
|
|
|
|
|
|
std::unique_ptr<Activity> act;
|
|
|
|
|
2020-06-15 14:03:29 +00:00
|
|
|
/* Activity that denotes waiting for a lock. */
|
|
|
|
std::unique_ptr<Activity> actLock;
|
|
|
|
|
2017-08-21 10:01:21 +00:00
|
|
|
std::map<ActivityId, Activity> builderActivities;
|
|
|
|
|
2017-10-24 12:24:57 +00:00
|
|
|
/* The remote machine on which we're building. */
|
|
|
|
std::string machineName;
|
|
|
|
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
/* The recursive Nix daemon socket. */
|
|
|
|
AutoCloseFD daemonSocket;
|
|
|
|
|
|
|
|
/* The daemon main thread. */
|
|
|
|
std::thread daemonThread;
|
|
|
|
|
2019-11-04 13:27:28 +00:00
|
|
|
/* The daemon worker threads. */
|
|
|
|
std::vector<std::thread> daemonWorkerThreads;
|
|
|
|
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
/* Paths that were added via recursive Nix calls. */
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePathSet addedPaths;
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
|
|
|
|
/* Recursive Nix calls are only allowed to build or realize paths
|
|
|
|
in the original input closure or added via a recursive Nix call
|
|
|
|
(so e.g. you can't do 'nix-store -r /nix/store/<bla>' where
|
|
|
|
/nix/store/<bla> is some arbitrary path in a binary cache). */
|
2019-12-05 18:11:09 +00:00
|
|
|
bool isAllowed(const StorePath & path)
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
{
|
|
|
|
return inputPaths.count(path) || addedPaths.count(path);
|
|
|
|
}
|
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
friend struct RestrictedStore;
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
|
2004-06-18 18:09:32 +00:00
|
|
|
public:
|
2020-08-22 20:44:47 +00:00
|
|
|
DerivationGoal(const StorePath & drvPath,
|
|
|
|
const StringSet & wantedOutputs, Worker & worker,
|
|
|
|
BuildMode buildMode = bmNormal);
|
2020-06-16 20:20:18 +00:00
|
|
|
DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv,
|
2020-08-22 20:44:47 +00:00
|
|
|
const StringSet & wantedOutputs, Worker & worker,
|
|
|
|
BuildMode buildMode = bmNormal);
|
2005-01-19 11:16:11 +00:00
|
|
|
~DerivationGoal();
|
2004-05-11 18:05:44 +00:00
|
|
|
|
2019-05-12 20:47:41 +00:00
|
|
|
/* Whether we need to perform hash rewriting if there are valid output paths. */
|
|
|
|
bool needsHashRewrite();
|
|
|
|
|
2020-06-15 17:25:35 +00:00
|
|
|
void timedOut(Error && ex) override;
|
2012-07-27 13:59:18 +00:00
|
|
|
|
2020-10-12 17:15:32 +00:00
|
|
|
string key() override;
|
2014-11-24 15:48:04 +00:00
|
|
|
|
2015-09-17 23:22:06 +00:00
|
|
|
void work() override;
|
2004-06-19 21:45:04 +00:00
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePath getDrvPath()
|
2005-02-23 11:19:27 +00:00
|
|
|
{
|
2020-06-16 20:20:18 +00:00
|
|
|
return drvPath;
|
2005-02-23 11:19:27 +00:00
|
|
|
}
|
2008-01-15 04:32:08 +00:00
|
|
|
|
2012-11-26 16:15:09 +00:00
|
|
|
/* Add wanted outputs to an already existing derivation goal. */
|
|
|
|
void addWantedOutputs(const StringSet & outputs);
|
|
|
|
|
2015-07-20 01:15:45 +00:00
|
|
|
BuildResult getResult() { return result; }
|
|
|
|
|
2004-06-19 21:45:04 +00:00
|
|
|
private:
|
2004-06-18 18:09:32 +00:00
|
|
|
/* The states. */
|
Allow remote builds without sending the derivation closure
Previously, to build a derivation remotely, we had to copy the entire
closure of the .drv file to the remote machine, even though we only
need the top-level derivation. This is very wasteful: the closure can
contain thousands of store paths, and in some Hydra use cases, include
source paths that are very large (e.g. Git/Mercurial checkouts).
So now there is a new operation, StoreAPI::buildDerivation(), that
performs a build from an in-memory representation of a derivation
(BasicDerivation) rather than from a on-disk .drv file. The only files
that need to be in the Nix store are the sources of the derivation
(drv.inputSrcs), and the needed output paths of the dependencies (as
described by drv.inputDrvs). "nix-store --serve" exposes this
interface.
Note that this is a privileged operation, because you can construct a
derivation that builds any store path whatsoever. Fixing this will
require changing the hashing scheme (i.e., the output paths should be
computed from the other fields in BasicDerivation, allowing them to be
verified without access to other derivations). However, this would be
quite nice because it would allow .drv-free building (e.g. "nix-env
-i" wouldn't have to write any .drv files to disk).
Fixes #173.
2015-07-17 15:57:40 +00:00
|
|
|
void getDerivation();
|
|
|
|
void loadDerivation();
|
2006-12-07 23:58:36 +00:00
|
|
|
void haveDerivation();
|
2020-08-07 19:09:26 +00:00
|
|
|
void outputsSubstitutionTried();
|
|
|
|
void gaveUpOnSubstitution();
|
2012-10-03 14:38:09 +00:00
|
|
|
void closureRepaired();
|
2005-01-19 11:16:11 +00:00
|
|
|
void inputsRealised();
|
2004-06-18 18:09:32 +00:00
|
|
|
void tryToBuild();
|
2020-05-14 14:00:54 +00:00
|
|
|
void tryLocalBuild();
|
2004-06-18 18:09:32 +00:00
|
|
|
void buildDone();
|
|
|
|
|
2020-08-22 20:44:47 +00:00
|
|
|
void resolvedFinished();
|
|
|
|
|
2004-06-19 21:45:04 +00:00
|
|
|
/* Is the build hook willing to perform the build? */
|
|
|
|
HookReply tryBuildHook();
|
|
|
|
|
2004-06-18 18:09:32 +00:00
|
|
|
/* Start building a derivation. */
|
|
|
|
void startBuilder();
|
|
|
|
|
2017-01-25 11:00:28 +00:00
|
|
|
/* Fill in the environment for the builder. */
|
|
|
|
void initEnv();
|
|
|
|
|
2019-10-12 23:02:57 +00:00
|
|
|
/* Setup tmp dir location. */
|
|
|
|
void initTmpDir();
|
|
|
|
|
Add support for passing structured data to builders
Previously, all derivation attributes had to be coerced into strings
so that they could be passed via the environment. This is lossy
(e.g. lists get flattened, necessitating configureFlags
vs. configureFlagsArray, of which the latter cannot be specified as an
attribute), doesn't support attribute sets at all, and has size
limitations (necessitating hacks like passAsFile).
This patch adds a new mode for passing attributes to builders, namely
encoded as a JSON file ".attrs.json" in the current directory of the
builder. This mode is activated via the special attribute
__structuredAttrs = true;
(The idea is that one day we can set this in stdenv.mkDerivation.)
For example,
stdenv.mkDerivation {
__structuredAttrs = true;
name = "foo";
buildInputs = [ pkgs.hello pkgs.cowsay ];
doCheck = true;
hardening.format = false;
}
results in a ".attrs.json" file containing (sans the indentation):
{
"buildInputs": [],
"builder": "/nix/store/ygl61ycpr2vjqrx775l1r2mw1g2rb754-bash-4.3-p48/bin/bash",
"configureFlags": [
"--with-foo",
"--with-bar=1 2"
],
"doCheck": true,
"hardening": {
"format": false
},
"name": "foo",
"nativeBuildInputs": [
"/nix/store/10h6li26i7g6z3mdpvra09yyf10mmzdr-hello-2.10",
"/nix/store/4jnvjin0r6wp6cv1hdm5jbkx3vinlcvk-cowsay-3.03"
],
"propagatedBuildInputs": [],
"propagatedNativeBuildInputs": [],
"stdenv": "/nix/store/f3hw3p8armnzy6xhd4h8s7anfjrs15n2-stdenv",
"system": "x86_64-linux"
}
"passAsFile" is ignored in this mode because it's not needed - large
strings are included directly in the JSON representation.
It is up to the builder to do something with the JSON
representation. For example, in bash-based builders, lists/attrsets of
string values could be mapped to bash (associative) arrays.
2017-01-25 15:42:07 +00:00
|
|
|
/* Write a JSON file containing the derivation attributes. */
|
|
|
|
void writeStructuredAttrs();
|
|
|
|
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
void startDaemon();
|
|
|
|
|
|
|
|
void stopDaemon();
|
|
|
|
|
|
|
|
/* Add 'path' to the set of paths that may be referenced by the
|
|
|
|
outputs, and make it appear in the sandbox. */
|
2019-12-05 18:11:09 +00:00
|
|
|
void addDependency(const StorePath & path);
|
Recursive Nix support
This allows Nix builders to call Nix to build derivations, with some
limitations.
Example:
let nixpkgs = fetchTarball channel:nixos-18.03; in
with import <nixpkgs> {};
runCommand "foo"
{
buildInputs = [ nix jq ];
NIX_PATH = "nixpkgs=${nixpkgs}";
}
''
hello=$(nix-build -E '(import <nixpkgs> {}).hello.overrideDerivation (args: { name = "hello-3.5"; })')
$hello/bin/hello
mkdir -p $out/bin
ln -s $hello/bin/hello $out/bin/hello
nix path-info -r --json $hello | jq .
''
This derivation makes a recursive Nix call to build GNU Hello and
symlinks it from its $out, i.e.
# ll ./result/bin/
lrwxrwxrwx 1 root root 63 Jan 1 1970 hello -> /nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5/bin/hello
# nix-store -qR ./result
/nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131
/nix/store/s0awxrs71gickhaqdwxl506hzccb30y5-hello-3.5
/nix/store/sgmvvyw8vhfqdqb619bxkcpfn9lvd8ss-foo
This is implemented as follows:
* Before running the outer builder, Nix creates a Unix domain socket
'.nix-socket' in the builder's temporary directory and sets
$NIX_REMOTE to point to it. It starts a thread to process
connections to this socket. (Thus you don't need to have nix-daemon
running.)
* The daemon thread uses a wrapper store (RestrictedStore) to keep
track of paths added through recursive Nix calls, to implement some
restrictions (see below), and to do some censorship (e.g. for
purity, queryPathInfo() won't return impure information such as
signatures and timestamps).
* After the build finishes, the output paths are scanned for
references to the paths added through recursive Nix calls (in
addition to the inputs closure). Thus, in the example above, $out
has a reference to $hello.
The main restriction on recursive Nix calls is that they cannot do
arbitrary substitutions. For example, doing
nix-store -r /nix/store/kmwd1hq55akdb9sc7l3finr175dajlby-hello-2.10
is forbidden unless /nix/store/kmwd... is in the inputs closure or
previously built by a recursive Nix call. This is to prevent
irreproducible derivations that have hidden dependencies on
substituters or the current store contents. Building a derivation is
fine, however, and Nix will use substitutes if available. In other
words, the builder has to present proof that it knows how to build a
desired store path from scratch by constructing a derivation graph for
that path.
Probably we should also disallow instantiating/building fixed-output
derivations (specifically, those that access the network, but
currently we have no way to mark fixed-output derivations that don't
access the network). Otherwise sandboxed derivations can bypass
sandbox restrictions and access the network.
When sandboxing is enabled, we make paths appear in the sandbox of the
builder by entering the mount namespace of the builder and
bind-mounting each path. This is tricky because we do a pivot_root()
in the builder to change the root directory of its mount namespace,
and thus the host /nix/store is not visible in the mount namespace of
the builder. To get around this, just before doing pivot_root(), we
branch a second mount namespace that shares its /nix/store mountpoint
with the parent.
Recursive Nix currently doesn't work on macOS in sandboxed mode
(because we can't change the sandbox policy of a running build) and in
non-root mode (because setns() barfs).
2018-10-02 14:01:26 +00:00
|
|
|
|
2017-01-25 11:00:28 +00:00
|
|
|
/* Make a file owned by the builder. */
|
|
|
|
void chownToBuilder(const Path & path);
|
|
|
|
|
2014-12-10 16:25:12 +00:00
|
|
|
/* Run the builder's process. */
|
|
|
|
void runChild();
|
2012-06-25 19:45:16 +00:00
|
|
|
|
|
|
|
friend int childEntry(void *);
|
|
|
|
|
2014-02-17 21:25:15 +00:00
|
|
|
/* Check that the derivation outputs all exist and register them
|
|
|
|
as valid. */
|
|
|
|
void registerOutputs();
|
2004-06-18 18:09:32 +00:00
|
|
|
|
2018-10-22 19:49:56 +00:00
|
|
|
/* Check that an output meets the requirements specified by the
|
|
|
|
'outputChecks' attribute (or the legacy
|
|
|
|
'{allowed,disallowed}{References,Requisites}' attributes). */
|
|
|
|
void checkOutputs(const std::map<std::string, ValidPathInfo> & outputs);
|
|
|
|
|
2004-06-18 18:09:32 +00:00
|
|
|
/* Open a log file and a pipe to it. */
|
2008-11-12 11:08:27 +00:00
|
|
|
Path openLogFile();
|
2004-06-18 18:09:32 +00:00
|
|
|
|
2012-05-30 14:12:29 +00:00
|
|
|
/* Close the log file. */
|
|
|
|
void closeLogFile();
|
|
|
|
|
2004-06-18 18:09:32 +00:00
|
|
|
/* Delete the temporary directory, if we have one. */
|
2004-05-11 18:05:44 +00:00
|
|
|
void deleteTmpDir(bool force);
|
2004-06-18 18:09:32 +00:00
|
|
|
|
2004-06-29 09:41:50 +00:00
|
|
|
/* Callback used by the worker to write to the log. */
|
2015-09-17 23:22:06 +00:00
|
|
|
void handleChildOutput(int fd, const string & data) override;
|
|
|
|
void handleEOF(int fd) override;
|
2016-04-25 14:47:46 +00:00
|
|
|
void flushLine();
|
2004-06-29 09:41:50 +00:00
|
|
|
|
2020-08-07 19:09:26 +00:00
|
|
|
/* Wrappers around the corresponding Store methods that first consult the
|
|
|
|
derivation. This is currently needed because when there is no drv file
|
|
|
|
there also is no DB entry. */
|
2020-08-20 18:14:12 +00:00
|
|
|
std::map<std::string, std::optional<StorePath>> queryPartialDerivationOutputMap();
|
|
|
|
OutputPathMap queryDerivationOutputMap();
|
2020-08-07 19:09:26 +00:00
|
|
|
|
2005-01-25 10:55:33 +00:00
|
|
|
/* Return the set of (in)valid paths. */
|
2020-08-07 19:09:26 +00:00
|
|
|
void checkPathValidity();
|
2009-03-25 21:05:42 +00:00
|
|
|
|
2006-12-08 18:41:48 +00:00
|
|
|
/* Forcibly kill the child process, if any. */
|
|
|
|
void killChild();
|
2012-10-02 21:13:46 +00:00
|
|
|
|
2020-09-04 15:15:51 +00:00
|
|
|
/* Create alternative path calculated from but distinct from the
|
|
|
|
input, so we can avoid overwriting outputs (or other store paths)
|
2020-08-07 19:09:26 +00:00
|
|
|
that already exist. */
|
|
|
|
StorePath makeFallbackPath(const StorePath & path);
|
2020-09-04 15:15:51 +00:00
|
|
|
/* Make a path to another based on the output name along with the
|
|
|
|
derivation hash. */
|
|
|
|
/* FIXME add option to randomize, so we can audit whether our
|
|
|
|
rewrites caught everything */
|
2020-08-11 20:49:10 +00:00
|
|
|
StorePath makeFallbackPath(std::string_view outputName);
|
2012-10-03 14:38:09 +00:00
|
|
|
|
|
|
|
void repairClosure();
|
2015-07-20 01:15:45 +00:00
|
|
|
|
2020-05-14 14:00:54 +00:00
|
|
|
void started();
|
|
|
|
|
2020-06-15 17:25:35 +00:00
|
|
|
void done(
|
|
|
|
BuildResult::Status status,
|
|
|
|
std::optional<Error> ex = {});
|
2018-04-17 10:03:27 +00:00
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePathSet exportReferences(const StorePathSet & storePaths);
|
2004-05-11 18:05:44 +00:00
|
|
|
};
|
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
}
|