From a91954f0c658e90b08f7f6e371305281e4d7d329 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 06:35:48 -0400 Subject: [PATCH 01/11] Merge openStore and openStoreAt with default arguments --- src/libstore/store-api.cc | 10 ++-------- src/libstore/store-api.hh | 6 +----- src/nix/command.cc | 2 +- src/nix/copy.cc | 4 ++-- src/nix/sigs.cc | 2 +- src/nix/verify.cc | 2 +- 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 5dd56f905..75456ab8c 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -506,7 +506,7 @@ namespace nix { RegisterStoreImplementation::Implementations * RegisterStoreImplementation::implementations = 0; -ref openStoreAt(const std::string & uri_) +ref openStore(const std::string & uri_) { auto uri(uri_); Store::Params params; @@ -529,12 +529,6 @@ ref openStoreAt(const std::string & uri_) } -ref openStore() -{ - return openStoreAt(getEnv("NIX_REMOTE")); -} - - static RegisterStoreImplementation regStore([]( const std::string & uri, const Store::Params & params) -> std::shared_ptr @@ -579,7 +573,7 @@ std::list> getDefaultSubstituters() auto addStore = [&](const std::string & uri) { if (done.count(uri)) return; done.insert(uri); - state->stores.push_back(openStoreAt(uri)); + state->stores.push_back(openStore(uri)); }; for (auto uri : settings.get("substituters", Strings())) diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 41fc58fc4..76a2f5e9c 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -587,11 +587,7 @@ void removeTempRoots(); If ‘uri’ is empty, it defaults to ‘direct’ or ‘daemon’ depending on whether the user has write access to the local Nix store/database. set to true *unless* you're going to collect garbage. */ -ref openStoreAt(const std::string & uri); - - -/* Open the store indicated by the ‘NIX_REMOTE’ environment variable. */ -ref openStore(); +ref openStore(const std::string & uri = getEnv("NIX_REMOTE")); /* Return the default substituter stores, defined by the diff --git a/src/nix/command.cc b/src/nix/command.cc index 37534015b..fdf6ae6af 100644 --- a/src/nix/command.cc +++ b/src/nix/command.cc @@ -81,7 +81,7 @@ StoreCommand::StoreCommand() void StoreCommand::run() { - run(openStoreAt(storeUri)); + run(openStore(storeUri)); } StorePathsCommand::StorePathsCommand() diff --git a/src/nix/copy.cc b/src/nix/copy.cc index de306cbf9..e8317dc39 100644 --- a/src/nix/copy.cc +++ b/src/nix/copy.cc @@ -43,8 +43,8 @@ struct CmdCopy : StorePathsCommand if (srcUri.empty() && dstUri.empty()) throw UsageError("you must pass ‘--from’ and/or ‘--to’"); - ref srcStore = srcUri.empty() ? store : openStoreAt(srcUri); - ref dstStore = dstUri.empty() ? store : openStoreAt(dstUri); + ref srcStore = srcUri.empty() ? store : openStore(srcUri); + ref dstStore = dstUri.empty() ? store : openStore(dstUri); std::string copiedLabel = "copied"; diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc index 9932aa4a9..0c0d7b728 100644 --- a/src/nix/sigs.cc +++ b/src/nix/sigs.cc @@ -35,7 +35,7 @@ struct CmdCopySigs : StorePathsCommand // FIXME: factor out commonality with MixVerify. std::vector> substituters; for (auto & s : substituterUris) - substituters.push_back(openStoreAt(s)); + substituters.push_back(openStore(s)); ThreadPool pool; diff --git a/src/nix/verify.cc b/src/nix/verify.cc index f2b6acdfb..519fcb6f8 100644 --- a/src/nix/verify.cc +++ b/src/nix/verify.cc @@ -52,7 +52,7 @@ struct CmdVerify : StorePathsCommand { std::vector> substituters; for (auto & s : substituterUris) - substituters.push_back(openStoreAt(s)); + substituters.push_back(openStore(s)); auto publicKeys = getDefaultPublicKeys(); From 53b27ddce22869430e2ab0932c32d8e3c3844564 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 06:39:29 -0400 Subject: [PATCH 02/11] Factor a function to get the store type from a URI out of the main RegisterStoreImplementation --- src/libstore/store-api.cc | 45 ++++++++++++++++++++++----------------- src/libstore/store-api.hh | 10 +++++++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 75456ab8c..604f0dac8 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -529,30 +529,37 @@ ref openStore(const std::string & uri_) } +StoreType getStoreType(const std::string & uri, const std::string & stateDir) +{ + if (uri == "daemon") { + return tDaemon; + } else if (uri == "local") { + return tLocal; + } else if (uri == "") { + if (access(stateDir.c_str(), R_OK | W_OK) == 0) + return tLocal; + else if (pathExists(settings.nixDaemonSocketFile)) + return tDaemon; + else + return tLocal; + } else { + return tOther; + } +} + + static RegisterStoreImplementation regStore([]( const std::string & uri, const Store::Params & params) -> std::shared_ptr { - enum { mDaemon, mLocal, mAuto } mode; - - if (uri == "daemon") mode = mDaemon; - else if (uri == "local") mode = mLocal; - else if (uri == "") mode = mAuto; - else return 0; - - if (mode == mAuto) { - auto stateDir = get(params, "state", settings.nixStateDir); - if (access(stateDir.c_str(), R_OK | W_OK) == 0) - mode = mLocal; - else if (pathExists(settings.nixDaemonSocketFile)) - mode = mDaemon; - else - mode = mLocal; + switch (getStoreType(uri, get(params, "state", settings.nixStateDir))) { + case tDaemon: + return std::shared_ptr(std::make_shared(params)); + case tLocal: + return std::shared_ptr(std::make_shared(params)); + default: + return nullptr; } - - return mode == mDaemon - ? std::shared_ptr(std::make_shared(params)) - : std::shared_ptr(std::make_shared(params)); }); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 76a2f5e9c..3d8b4fbbb 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -5,6 +5,7 @@ #include "crypto.hh" #include "lru-cache.hh" #include "sync.hh" +#include "globals.hh" #include #include @@ -590,6 +591,15 @@ void removeTempRoots(); ref openStore(const std::string & uri = getEnv("NIX_REMOTE")); +enum StoreType { + tDaemon, + tLocal, + tOther +}; + + +StoreType getStoreType(const std::string & uri = getEnv("NIX_REMOTE"), const std::string & stateDir = settings.nixStateDir); + /* Return the default substituter stores, defined by the ‘substituters’ option and various legacy options like ‘binary-caches’. */ From 7d4ccd9b17ca902438e7045e4ce950525ed554b6 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 13:30:28 -0400 Subject: [PATCH 03/11] nix-daemon: add --stdio flag for handling connections over stdin/stdout --- src/nix-daemon/nix-daemon.cc | 76 +++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index f2b59c84a..fba522540 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -22,6 +22,7 @@ #include #include #include +#include #if __APPLE__ || __FreeBSD__ #include @@ -29,6 +30,25 @@ using namespace nix; +#ifndef __linux__ +#define SPLICE_F_MOVE 0 +static ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) +{ + /* We ignore most parameters, we just have them for conformance with the linux syscall */ + char buf[8192]; + auto read_count = read(fd_in, buf, sizeof(buf)); + if (read_count == -1) + return read_count; + auto write_count = decltype(0); + while (write_count < read_count) { + auto res = write(fd_out, buf + write_count, read_count - write_count); + if (res == -1) + return res; + write_count += res; + } + return read_count; +} +#endif static FdSource from(STDIN_FILENO); static FdSink to(STDOUT_FILENO); @@ -885,6 +905,8 @@ int main(int argc, char * * argv) return handleExceptions(argv[0], [&]() { initNix(); + auto stdio = false; + parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--daemon") ; /* ignored for backwards compatibility */ @@ -892,10 +914,62 @@ int main(int argc, char * * argv) showManPage("nix-daemon"); else if (*arg == "--version") printVersion("nix-daemon"); + else if (*arg == "--stdio") + stdio = true; else return false; return true; }); - daemonLoop(argv); + if (stdio) { + if (getStoreType() == tDaemon) { + /* Forward on this connection to the real daemon */ + auto socketPath = settings.nixDaemonSocketFile; + auto s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s == -1) + throw SysError("creating Unix domain socket"); + + auto socketDir = dirOf(socketPath); + if (chdir(socketDir.c_str()) == -1) + throw SysError(format("changing to socket directory %1%") % socketDir); + + auto socketName = baseNameOf(socketPath); + auto addr = sockaddr_un{}; + addr.sun_family = AF_UNIX; + if (socketName.size() + 1 >= sizeof(addr.sun_path)) + throw Error(format("socket name %1% is too long") % socketName); + strcpy(addr.sun_path, socketName.c_str()); + + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) + throw SysError(format("cannot connect to daemon at %1%") % socketPath); + + auto nfds = (s > STDIN_FILENO ? s : STDIN_FILENO) + 1; + while (true) { + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + FD_SET(STDIN_FILENO, &fds); + if (select(nfds, &fds, nullptr, nullptr, nullptr) == -1) + throw SysError("waiting for data from client or server"); + if (FD_ISSET(s, &fds)) { + auto res = splice(s, nullptr, STDOUT_FILENO, nullptr, SIZE_MAX, SPLICE_F_MOVE); + if (res == -1) + throw SysError("splicing data from daemon socket to stdout"); + else if (res == 0) + throw EndOfFile("unexpected EOF from daemon socket"); + } + if (FD_ISSET(STDIN_FILENO, &fds)) { + auto res = splice(STDIN_FILENO, nullptr, s, nullptr, SIZE_MAX, SPLICE_F_MOVE); + if (res == -1) + throw SysError("splicing data from stdin to daemon socket"); + else if (res == 0) + return; + } + } + } else { + processConnection(true); + } + } else { + daemonLoop(argv); + } }); } From 0f3963329018d9cf930e2a0e2b0ec2f4e26b40b3 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 14:15:04 -0400 Subject: [PATCH 04/11] Factor out the unix domain socket-specific code from RemoteStore --- src/libstore/local-store.cc | 3 +- src/libstore/remote-store.cc | 65 +++++++++++++++++++++--------------- src/libstore/remote-store.hh | 33 ++++++++++++++---- src/libstore/store-api.cc | 2 +- src/libstore/store-api.hh | 2 +- 5 files changed, 69 insertions(+), 36 deletions(-) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 10056f2f1..272d48741 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -37,7 +37,8 @@ namespace nix { LocalStore::LocalStore(const Params & params) - : LocalFSStore(params) + : Store(params) + , LocalFSStore(params) , realStoreDir(get(params, "real", rootDir != "" ? rootDir + "/nix/store" : storeDir)) , dbDir(stateDir + "/db") , linksDir(realStoreDir + "/.links") diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 94075f3b9..232f62e7a 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -38,9 +38,9 @@ template T readStorePaths(Store & store, Source & from) template PathSet readStorePaths(Store & store, Source & from); - +/* TODO: Separate these store impls into different files, give them better names */ RemoteStore::RemoteStore(const Params & params, size_t maxConnections) - : LocalFSStore(params) + : Store(params) , connections(make_ref>( maxConnections, [this]() { return openConnection(); }, @@ -50,13 +50,21 @@ RemoteStore::RemoteStore(const Params & params, size_t maxConnections) } -std::string RemoteStore::getUri() +UDSRemoteStore::UDSRemoteStore(const Params & params, size_t maxConnections) + : Store(params) + , LocalFSStore(params) + , RemoteStore(params, maxConnections) +{ +} + + +std::string UDSRemoteStore::getUri() { return "daemon"; } -ref RemoteStore::openConnection() +ref UDSRemoteStore::openConnection() { auto conn = make_ref(); @@ -84,46 +92,52 @@ ref RemoteStore::openConnection() conn->from.fd = conn->fd.get(); conn->to.fd = conn->fd.get(); + initConnection(*conn); + + return conn; +} + + +void RemoteStore::initConnection(Connection & conn) +{ /* Send the magic greeting, check for the reply. */ try { - conn->to << WORKER_MAGIC_1; - conn->to.flush(); - unsigned int magic = readInt(conn->from); + conn.to << WORKER_MAGIC_1; + conn.to.flush(); + unsigned int magic = readInt(conn.from); if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch"); - conn->daemonVersion = readInt(conn->from); - if (GET_PROTOCOL_MAJOR(conn->daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION)) + conn.daemonVersion = readInt(conn.from); + if (GET_PROTOCOL_MAJOR(conn.daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION)) throw Error("Nix daemon protocol version not supported"); - if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 10) + if (GET_PROTOCOL_MINOR(conn.daemonVersion) < 10) throw Error("the Nix daemon version is too old"); - conn->to << PROTOCOL_VERSION; + conn.to << PROTOCOL_VERSION; - if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 14) { + if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 14) { int cpu = settings.lockCPU ? lockToCurrentCPU() : -1; if (cpu != -1) - conn->to << 1 << cpu; + conn.to << 1 << cpu; else - conn->to << 0; + conn.to << 0; } - if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 11) - conn->to << false; + if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 11) + conn.to << false; - conn->processStderr(); + conn.processStderr(); } catch (Error & e) { throw Error(format("cannot start daemon worker: %1%") % e.msg()); } setOptions(conn); - - return conn; } -void RemoteStore::setOptions(ref conn) +void RemoteStore::setOptions(Connection & conn) { - conn->to << wopSetOptions + conn.to << wopSetOptions << settings.keepFailed << settings.keepGoing << settings.tryFallback @@ -137,16 +151,16 @@ void RemoteStore::setOptions(ref conn) << settings.buildCores << settings.useSubstitutes; - if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 12) { + if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) { Settings::SettingsMap overrides = settings.getOverrides(); if (overrides["ssh-auth-sock"] == "") overrides["ssh-auth-sock"] = getEnv("SSH_AUTH_SOCK"); - conn->to << overrides.size(); + conn.to << overrides.size(); for (auto & i : overrides) - conn->to << i.first << i.second; + conn.to << i.first << i.second; } - conn->processStderr(); + conn.processStderr(); } @@ -528,7 +542,6 @@ RemoteStore::Connection::~Connection() { try { to.flush(); - fd = -1; } catch (...) { ignoreException(); } diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index e756805ea..a69a4f2a3 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -18,7 +18,7 @@ template class Pool; /* FIXME: RemoteStore is a misnomer - should be something like DaemonStore. */ -class RemoteStore : public LocalFSStore +class RemoteStore : public virtual Store { public: @@ -26,8 +26,6 @@ public: /* Implementations of abstract store API methods. */ - std::string getUri() override; - bool isValidPathUncached(const Path & path) override; PathSet queryValidPaths(const PathSet & paths) override; @@ -84,11 +82,10 @@ public: void addSignatures(const Path & storePath, const StringSet & sigs) override; -private: +protected: struct Connection { - AutoCloseFD fd; FdSink to; FdSource from; unsigned int daemonVersion; @@ -98,11 +95,33 @@ private: void processStderr(Sink * sink = 0, Source * source = 0); }; + virtual ref openConnection() = 0; + + void setOptions(Connection & conn); + + void initConnection(Connection & conn); + +private: + ref> connections; +}; - ref openConnection(); +class UDSRemoteStore : public LocalFSStore, public RemoteStore +{ +public: - void setOptions(ref conn); + UDSRemoteStore(const Params & params, size_t maxConnections = std::numeric_limits::max()); + + std::string getUri() override; + +private: + + struct Connection : RemoteStore::Connection + { + AutoCloseFD fd; + }; + + ref openConnection() override; }; diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 604f0dac8..1ce483ca9 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -554,7 +554,7 @@ static RegisterStoreImplementation regStore([]( { switch (getStoreType(uri, get(params, "state", settings.nixStateDir))) { case tDaemon: - return std::shared_ptr(std::make_shared(params)); + return std::shared_ptr(std::make_shared(params)); case tLocal: return std::shared_ptr(std::make_shared(params)); default: diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 3d8b4fbbb..ae1d51016 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -526,7 +526,7 @@ protected: }; -class LocalFSStore : public Store +class LocalFSStore : public virtual Store { public: const Path rootDir; From a705e8ce0a8aaf3afe885892834468e95c197a16 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 14:24:34 -0400 Subject: [PATCH 05/11] Factor a general remote FS accessor out of BinaryCacheStore --- src/libstore/binary-cache-store.cc | 66 +----------------------------- src/libstore/remote-fs-accessor.cc | 57 ++++++++++++++++++++++++++ src/libstore/remote-fs-accessor.hh | 29 +++++++++++++ 3 files changed, 88 insertions(+), 64 deletions(-) create mode 100644 src/libstore/remote-fs-accessor.cc create mode 100644 src/libstore/remote-fs-accessor.hh diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index e71ea6a57..ab80e4032 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -6,8 +6,7 @@ #include "globals.hh" #include "nar-info.hh" #include "sync.hh" -#include "worker-protocol.hh" -#include "nar-accessor.hh" +#include "remote-fs-accessor.hh" #include "nar-info-disk-cache.hh" #include @@ -232,70 +231,9 @@ Path BinaryCacheStore::addTextToStore(const string & name, const string & s, return info.path; } -/* Given requests for a path /nix/store//, this accessor will - first download the NAR for /nix/store/ from the binary cache, - build a NAR accessor for that NAR, and use that to access . */ -struct BinaryCacheStoreAccessor : public FSAccessor -{ - ref store; - - std::map> nars; - - BinaryCacheStoreAccessor(ref store) - : store(store) - { - } - - std::pair, Path> fetch(const Path & path_) - { - auto path = canonPath(path_); - - auto storePath = store->toStorePath(path); - std::string restPath = std::string(path, storePath.size()); - - if (!store->isValidPath(storePath)) - throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath); - - auto i = nars.find(storePath); - if (i != nars.end()) return {i->second, restPath}; - - StringSink sink; - store->narFromPath(storePath, sink); - - auto accessor = makeNarAccessor(sink.s); - nars.emplace(storePath, accessor); - return {accessor, restPath}; - } - - Stat stat(const Path & path) override - { - auto res = fetch(path); - return res.first->stat(res.second); - } - - StringSet readDirectory(const Path & path) override - { - auto res = fetch(path); - return res.first->readDirectory(res.second); - } - - std::string readFile(const Path & path) override - { - auto res = fetch(path); - return res.first->readFile(res.second); - } - - std::string readLink(const Path & path) override - { - auto res = fetch(path); - return res.first->readLink(res.second); - } -}; - ref BinaryCacheStore::getFSAccessor() { - return make_ref(ref( - std::dynamic_pointer_cast(shared_from_this()))); + return make_ref(ref(shared_from_this())); } } diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc new file mode 100644 index 000000000..ca14057c2 --- /dev/null +++ b/src/libstore/remote-fs-accessor.cc @@ -0,0 +1,57 @@ +#include "remote-fs-accessor.hh" +#include "nar-accessor.hh" + +namespace nix { + + +RemoteFSAccessor::RemoteFSAccessor(ref store) + : store(store) +{ +} + +std::pair, Path> RemoteFSAccessor::fetch(const Path & path_) +{ + auto path = canonPath(path_); + + auto storePath = store->toStorePath(path); + std::string restPath = std::string(path, storePath.size()); + + if (!store->isValidPath(storePath)) + throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath); + + auto i = nars.find(storePath); + if (i != nars.end()) return {i->second, restPath}; + + StringSink sink; + store->narFromPath(storePath, sink); + + auto accessor = makeNarAccessor(sink.s); + nars.emplace(storePath, accessor); + return {accessor, restPath}; +} + +FSAccessor::Stat RemoteFSAccessor::stat(const Path & path) +{ + auto res = fetch(path); + return res.first->stat(res.second); +} + +StringSet RemoteFSAccessor::readDirectory(const Path & path) +{ + auto res = fetch(path); + return res.first->readDirectory(res.second); +} + +std::string RemoteFSAccessor::readFile(const Path & path) +{ + auto res = fetch(path); + return res.first->readFile(res.second); +} + +std::string RemoteFSAccessor::readLink(const Path & path) +{ + auto res = fetch(path); + return res.first->readLink(res.second); +} + +} diff --git a/src/libstore/remote-fs-accessor.hh b/src/libstore/remote-fs-accessor.hh new file mode 100644 index 000000000..28f36c829 --- /dev/null +++ b/src/libstore/remote-fs-accessor.hh @@ -0,0 +1,29 @@ +#pragma once + +#include "fs-accessor.hh" +#include "ref.hh" +#include "store-api.hh" + +namespace nix { + +class RemoteFSAccessor : public FSAccessor +{ + ref store; + + std::map> nars; + + std::pair, Path> fetch(const Path & path_); +public: + + RemoteFSAccessor(ref store); + + Stat stat(const Path & path) override; + + StringSet readDirectory(const Path & path) override; + + std::string readFile(const Path & path) override; + + std::string readLink(const Path & path) override; +}; + +} From b4b5e9ce2f58aecea2fe3ca1fe9388e4fc7df556 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 14:26:02 -0400 Subject: [PATCH 06/11] Add narFromPath op to nix daemon --- src/libstore/worker-protocol.hh | 1 + src/nix-daemon/nix-daemon.cc | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index f8cd7cc4b..c7f024efe 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -46,6 +46,7 @@ typedef enum { wopVerifyStore = 35, wopBuildDerivation = 36, wopAddSignatures = 37, + wopNarFromPath = 38 } WorkerOp; diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index fba522540..0ef2a6872 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -576,6 +576,14 @@ static void performOp(ref store, bool trusted, unsigned int clientVe break; } + case wopNarFromPath: { + auto path = readStorePath(*store, from); + startWork(); + dumpPath(path, to); + stopWork(); + break; + } + default: throw Error(format("invalid operation %1%") % op); } From ecba88de9367f733610121fc0153310f92e05b65 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 14:31:38 -0400 Subject: [PATCH 07/11] Add ssh store implementation --- src/libstore/remote-store.hh | 8 ++-- src/libstore/ssh-store.cc | 92 ++++++++++++++++++++++++++++++++++++ src/libstore/ssh-store.hh | 40 ++++++++++++++++ 3 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 src/libstore/ssh-store.cc create mode 100644 src/libstore/ssh-store.hh diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index a69a4f2a3..5c9c617d9 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -90,20 +90,20 @@ protected: FdSource from; unsigned int daemonVersion; - ~Connection(); + virtual ~Connection(); void processStderr(Sink * sink = 0, Source * source = 0); }; virtual ref openConnection() = 0; - void setOptions(Connection & conn); - void initConnection(Connection & conn); + ref> connections; + private: - ref> connections; + void setOptions(Connection & conn); }; class UDSRemoteStore : public LocalFSStore, public RemoteStore diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc new file mode 100644 index 000000000..e1eb76659 --- /dev/null +++ b/src/libstore/ssh-store.cc @@ -0,0 +1,92 @@ +#include "ssh-store.hh" +#include "remote-fs-accessor.hh" +#include "archive.hh" +#include "worker-protocol.hh" +#include "pool.hh" + +namespace nix { + +SSHStore::SSHStore(string uri, const Params & params, size_t maxConnections) + : Store(params) + , RemoteStore(params, maxConnections) + , tmpDir(createTempDir("", "nix", true, true, 0700)) + , socketPath((Path) tmpDir + "/ssh.sock") + , sshMaster(startProcess([&]() { + auto key = get(params, "ssh-key", ""); + if (key.empty()) + execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), uri.c_str(), NULL); + else + execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), "-i", key.c_str(), uri.c_str(), NULL); + throw SysError("starting ssh master"); + })) + , uri(std::move(uri)) +{ +} + +string SSHStore::getUri() +{ + return "ssh://" + uri; +} + +class ForwardSource : public Source +{ + Source & readSource; + Sink & writeSink; +public: + ForwardSource(Source & readSource, Sink & writeSink) : readSource(readSource), writeSink(writeSink) {} + size_t read(unsigned char * data, size_t len) override + { + auto res = readSource.read(data, len); + writeSink(data, len); + return res; + } +}; + +void SSHStore::narFromPath(const Path & path, Sink & sink) +{ + auto conn(connections->get()); + conn->to << wopNarFromPath << path; + conn->processStderr(); + ParseSink ps; + auto fwd = ForwardSource(conn->from, sink); + parseDump(ps, fwd); +} + +ref SSHStore::getFSAccessor() +{ + return make_ref(ref(shared_from_this())); +} + +ref SSHStore::openConnection() +{ + auto conn = make_ref(); + Pipe in, out; + in.create(); + out.create(); + conn->sshPid = startProcess([&]() { + if (dup2(in.readSide.get(), STDIN_FILENO) == -1) + throw SysError("duping over STDIN"); + if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) + throw SysError("duping over STDOUT"); + execlp("ssh", "ssh", "-S", socketPath.c_str(), uri.c_str(), "nix-daemon", "--stdio", NULL); + throw SysError("executing nix-daemon --stdio over ssh"); + }); + in.readSide = -1; + out.writeSide = -1; + conn->out = std::move(out.readSide); + conn->in = std::move(in.writeSide); + conn->to = FdSink(conn->in.get()); + conn->from = FdSource(conn->out.get()); + initConnection(*conn); + return conn; +} + +static RegisterStoreImplementation regStore([]( + const std::string & uri, const Store::Params & params) + -> std::shared_ptr +{ + if (std::string(uri, 0, 6) != "ssh://") return 0; + return std::make_shared(uri.substr(6), params); +}); + +} diff --git a/src/libstore/ssh-store.hh b/src/libstore/ssh-store.hh new file mode 100644 index 000000000..44ece5598 --- /dev/null +++ b/src/libstore/ssh-store.hh @@ -0,0 +1,40 @@ +#pragma once + +#include "store-api.hh" +#include "remote-store.hh" + +namespace nix { + +class SSHStore : public RemoteStore +{ +public: + + SSHStore(string uri, const Params & params, size_t maxConnections = std::numeric_limits::max()); + + std::string getUri() override; + + void narFromPath(const Path & path, Sink & sink) override; + + ref getFSAccessor() override; + +private: + + struct Connection : RemoteStore::Connection + { + Pid sshPid; + AutoCloseFD out; + AutoCloseFD in; + }; + + ref openConnection() override; + + AutoDelete tmpDir; + + Path socketPath; + + Pid sshMaster; + + string uri; +}; + +} From 584f8a62de117ade154ec8208d939dc194782936 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Fri, 2 Sep 2016 14:33:58 -0400 Subject: [PATCH 08/11] Implement nar-based addToStore for remote-store --- src/libstore/remote-store.cc | 7 ++++++- src/libstore/worker-protocol.hh | 3 ++- src/nix-daemon/nix-daemon.cc | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 232f62e7a..f03f33fc1 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -345,7 +345,12 @@ Path RemoteStore::queryPathFromHashPart(const string & hashPart) void RemoteStore::addToStore(const ValidPathInfo & info, const std::string & nar, bool repair, bool dontCheckSigs) { - throw Error("RemoteStore::addToStore() not implemented"); + auto conn(connections->get()); + conn->to << wopAddToStoreNar + << info.path << info.deriver << printHash(info.narHash) + << info.references << info.registrationTime << info.narSize + << info.ultimate << info.sigs << nar << repair << dontCheckSigs; + conn->processStderr(); } diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index c7f024efe..2cd246dab 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -46,7 +46,8 @@ typedef enum { wopVerifyStore = 35, wopBuildDerivation = 36, wopAddSignatures = 37, - wopNarFromPath = 38 + wopNarFromPath = 38, + wopAddToStoreNar = 39 } WorkerOp; diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index 0ef2a6872..d37bcb3e7 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -579,7 +579,30 @@ static void performOp(ref store, bool trusted, unsigned int clientVe case wopNarFromPath: { auto path = readStorePath(*store, from); startWork(); + stopWork(); dumpPath(path, to); + break; + } + + case wopAddToStoreNar: { + ValidPathInfo info; + info.path = readStorePath(*store, from); + info.deriver = readString(from); + if (!info.deriver.empty()) + store->assertStorePath(info.deriver); + info.narHash = parseHash(htSHA256, readString(from)); + info.references = readStorePaths(*store, from); + info.registrationTime = readInt(from); + info.narSize = readLongLong(from); + info.ultimate = readLongLong(from); + info.sigs = readStrings(from); + auto nar = readString(from); + auto repair = readInt(from) ? true : false; + auto dontCheckSigs = readInt(from) ? true : false; + if (!trusted && dontCheckSigs) + dontCheckSigs = false; + startWork(); + store->addToStore(info, nar, repair, dontCheckSigs); stopWork(); break; } From ab31f9986c68f575d902582ed3e176b777cb49e1 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Mon, 12 Sep 2016 08:03:29 -0400 Subject: [PATCH 09/11] Inline ssh-store.hh into ssh-store.cc --- src/libstore/ssh-store.cc | 35 +++++++++++++++++++++++++++++++++- src/libstore/ssh-store.hh | 40 --------------------------------------- 2 files changed, 34 insertions(+), 41 deletions(-) delete mode 100644 src/libstore/ssh-store.hh diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc index e1eb76659..05992bb49 100644 --- a/src/libstore/ssh-store.cc +++ b/src/libstore/ssh-store.cc @@ -1,4 +1,5 @@ -#include "ssh-store.hh" +#include "store-api.hh" +#include "remote-store.hh" #include "remote-fs-accessor.hh" #include "archive.hh" #include "worker-protocol.hh" @@ -6,6 +7,38 @@ namespace nix { +class SSHStore : public RemoteStore +{ +public: + + SSHStore(string uri, const Params & params, size_t maxConnections = std::numeric_limits::max()); + + std::string getUri() override; + + void narFromPath(const Path & path, Sink & sink) override; + + ref getFSAccessor() override; + +private: + + struct Connection : RemoteStore::Connection + { + Pid sshPid; + AutoCloseFD out; + AutoCloseFD in; + }; + + ref openConnection() override; + + AutoDelete tmpDir; + + Path socketPath; + + Pid sshMaster; + + string uri; +}; + SSHStore::SSHStore(string uri, const Params & params, size_t maxConnections) : Store(params) , RemoteStore(params, maxConnections) diff --git a/src/libstore/ssh-store.hh b/src/libstore/ssh-store.hh deleted file mode 100644 index 44ece5598..000000000 --- a/src/libstore/ssh-store.hh +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "store-api.hh" -#include "remote-store.hh" - -namespace nix { - -class SSHStore : public RemoteStore -{ -public: - - SSHStore(string uri, const Params & params, size_t maxConnections = std::numeric_limits::max()); - - std::string getUri() override; - - void narFromPath(const Path & path, Sink & sink) override; - - ref getFSAccessor() override; - -private: - - struct Connection : RemoteStore::Connection - { - Pid sshPid; - AutoCloseFD out; - AutoCloseFD in; - }; - - ref openConnection() override; - - AutoDelete tmpDir; - - Path socketPath; - - Pid sshMaster; - - string uri; -}; - -} From 196815f70014d9e7c3a44b66d4c1eb35aa56a282 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Mon, 12 Sep 2016 08:07:50 -0400 Subject: [PATCH 10/11] ssh-store: Start master on-demand --- src/libstore/ssh-store.cc | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc index 05992bb49..516648522 100644 --- a/src/libstore/ssh-store.cc +++ b/src/libstore/ssh-store.cc @@ -37,6 +37,8 @@ private: Pid sshMaster; string uri; + + Path key; }; SSHStore::SSHStore(string uri, const Params & params, size_t maxConnections) @@ -44,15 +46,8 @@ SSHStore::SSHStore(string uri, const Params & params, size_t maxConnections) , RemoteStore(params, maxConnections) , tmpDir(createTempDir("", "nix", true, true, 0700)) , socketPath((Path) tmpDir + "/ssh.sock") - , sshMaster(startProcess([&]() { - auto key = get(params, "ssh-key", ""); - if (key.empty()) - execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), uri.c_str(), NULL); - else - execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), "-i", key.c_str(), uri.c_str(), NULL); - throw SysError("starting ssh master"); - })) , uri(std::move(uri)) + , key(get(params, "ssh-key", "")) { } @@ -92,6 +87,16 @@ ref SSHStore::getFSAccessor() ref SSHStore::openConnection() { + if ((pid_t) sshMaster == -1) { + sshMaster = startProcess([&]() { + if (key.empty()) + execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), uri.c_str(), NULL); + else + execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), "-i", key.c_str(), uri.c_str(), NULL); + throw SysError("starting ssh master"); + }); + } + auto conn = make_ref(); Pipe in, out; in.create(); From b99c6e0e2959e90ddda14d8b318e4c7b1a508674 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Mon, 12 Sep 2016 08:09:41 -0400 Subject: [PATCH 11/11] nix-daemon: Fix error message --- src/nix-daemon/nix-daemon.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index d37bcb3e7..0fe005378 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -961,7 +961,7 @@ int main(int argc, char * * argv) auto socketDir = dirOf(socketPath); if (chdir(socketDir.c_str()) == -1) - throw SysError(format("changing to socket directory %1%") % socketDir); + throw SysError(format("changing to socket directory ‘%1%’") % socketDir); auto socketName = baseNameOf(socketPath); auto addr = sockaddr_un{};