1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#include "lix/libstore/ssh-store.hh"
#include "lix/libstore/store-api.hh"
#include "lix/libstore/remote-store.hh"
#include "lix/libstore/remote-store-connection.hh"
#include "lix/libstore/worker-protocol.hh"
#include "lix/libutil/pool.hh"
#include "lix/libstore/ssh.hh"
#include "lix/libutil/result.hh"
#include "lix/libutil/strings.hh"
namespace nix {
struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig
{
using RemoteStoreConfig::RemoteStoreConfig;
using CommonSSHStoreConfig::CommonSSHStoreConfig;
const Setting<Path> 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"
;
}
};
struct SSHStoreConfigWithLog : SSHStoreConfig
{
SSHStoreConfigWithLog(const Params & params)
: StoreConfig(params)
, RemoteStoreConfig(params)
, CommonSSHStoreConfig(params)
, SSHStoreConfig(params)
{
}
// Hack for getting ssh errors into build-remote.
// Intentionally not in `SSHStoreConfig` so that it doesn't appear in
// the documentation
const Setting<int> logFD{
this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"
};
};
class SSHStore final : public RemoteStore
{
SSHStoreConfigWithLog config_;
public:
SSHStore(const std::string & scheme, const std::string & host, SSHStoreConfigWithLog config)
: Store(config)
, RemoteStore(config)
, config_(std::move(config))
, host(host)
, ssh(host,
config_.port,
config_.sshKey,
config_.sshPublicHostKey,
config_.compress,
config_.logFD)
{
}
SSHStoreConfigWithLog & config() override
{
return config_;
}
const SSHStoreConfigWithLog & config() const override
{
return config_;
}
static std::set<std::string> uriSchemes() { return {"ssh-ng"}; }
std::string getUri() override
{
return *uriSchemes().begin() + "://" + host;
}
// FIXME extend daemon protocol, move implementation to RemoteStore
kj::Promise<Result<std::optional<std::string>>> getBuildLogExact(const StorePath & path) override
try {
unsupported("getBuildLogExact");
} catch (...) {
return {result::current_exception()};
}
protected:
struct Connection : RemoteStore::Connection
{
std::unique_ptr<SSH::Connection> sshConn;
int getFD() const override
{
return sshConn->socket.get();
}
};
kj::Promise<Result<ref<RemoteStore::Connection>>> openConnection() override;
std::string host;
SSH ssh;
kj::Promise<Result<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.
*/
return {result::success()};
};
};
kj::Promise<Result<ref<RemoteStore::Connection>>> SSHStore::openConnection()
try {
auto conn = make_ref<Connection>();
std::string command = config_.remoteProgram + " --stdio";
if (config_.remoteStore.get() != "")
command += " --store " + shellEscape(config_.remoteStore.get());
conn->sshConn = ssh.startCommand(command);
return {conn};
} catch (...) {
return {result::current_exception()};
}
void registerSSHStore() {
StoreImplementations::add<SSHStore, SSHStoreConfig>();
}
}
|