#include "ssh-store.hh" #include "store-api.hh" #include "remote-store.hh" #include "remote-store-connection.hh" #include "worker-protocol.hh" #include "pool.hh" #include "ssh.hh" #include "strings.hh" namespace nix { struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig { using RemoteStoreConfig::RemoteStoreConfig; using CommonSSHStoreConfig::CommonSSHStoreConfig; const Setting remoteProgram{this, "nix-daemon", "remote-program", "Path to the `nix-daemon` executable on the remote machine."}; const std::string name() override { return "Experimental SSH Store"; } std::string doc() override { return #include "ssh-store.md" ; } }; class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore { public: // Hack for getting remote build log output. // Intentionally not in `SSHStoreConfig` so that it doesn't appear in // the documentation const Setting logFD{(StoreConfig*) this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"}; SSHStore(const std::string & scheme, const std::string & host, const Params & params) : StoreConfig(params) , RemoteStoreConfig(params) , CommonSSHStoreConfig(params) , SSHStoreConfig(params) , Store(params) , RemoteStore(params) , host(host) , master( host, sshKey, sshPublicHostKey, // Use SSH master only if using more than 1 connection. connections->capacity() > 1, compress, logFD) { } static std::set uriSchemes() { return {"ssh-ng"}; } std::string getUri() override { return *uriSchemes().begin() + "://" + host; } // FIXME extend daemon protocol, move implementation to RemoteStore std::optional getBuildLogExact(const StorePath & path) override { unsupported("getBuildLogExact"); } protected: struct Connection : RemoteStore::Connection { std::unique_ptr sshConn; void closeWrite() override { sshConn->in.close(); } }; ref openConnection() override; std::string host; SSHMaster master; void setOptions(RemoteStore::Connection & conn) override { /* TODO Add a way to explicitly ask for some options to be forwarded. One option: A way to query the daemon for its settings, and then a series of params to SSHStore like forward-cores or forward-overridden-cores that only override the requested settings. */ }; }; ref SSHStore::openConnection() { auto conn = make_ref(); std::string command = remoteProgram + " --stdio"; if (remoteStore.get() != "") command += " --store " + shellEscape(remoteStore.get()); conn->sshConn = master.startCommand(command); conn->to = FdSink(conn->sshConn->in.get()); conn->from = FdSource(conn->sshConn->out.get()); return conn; } void registerSSHStore() { StoreImplementations::add(); } }