Use LegacySSHStore

In https://github.com/NixOS/nix/pull/10748 it is extended with
everything we need.
This commit is contained in:
John Ericson 2024-05-20 16:22:19 -04:00
parent 881462bb4e
commit 4a4a0f901c
2 changed files with 68 additions and 118 deletions

View File

@ -9,13 +9,10 @@
#include "path.hh" #include "path.hh"
#include "legacy-ssh-store.hh" #include "legacy-ssh-store.hh"
#include "serve-protocol.hh" #include "serve-protocol.hh"
#include "serve-protocol-impl.hh"
#include "state.hh" #include "state.hh"
#include "current-process.hh" #include "current-process.hh"
#include "processes.hh" #include "processes.hh"
#include "util.hh" #include "util.hh"
#include "serve-protocol.hh"
#include "serve-protocol-impl.hh"
#include "ssh.hh" #include "ssh.hh"
#include "finally.hh" #include "finally.hh"
#include "url.hh" #include "url.hh"
@ -39,38 +36,6 @@ bool ::Machine::isLocalhost() const
namespace nix::build_remote { namespace nix::build_remote {
static std::unique_ptr<SSHMaster::Connection> openConnection(
::Machine::ptr machine, SSHMaster & master)
{
Strings command = {"nix-store", "--serve", "--write"};
if (machine->isLocalhost()) {
command.push_back("--builders");
command.push_back("");
} else {
auto remoteStore = machine->storeUri.params.find("remote-store");
if (remoteStore != machine->storeUri.params.end()) {
command.push_back("--store");
command.push_back(shellEscape(remoteStore->second));
}
}
auto ret = master.startCommand(std::move(command), {
"-a", "-oBatchMode=yes", "-oConnectTimeout=60", "-oTCPKeepAlive=yes"
});
// XXX: determine the actual max value we can use from /proc.
// FIXME: Should this be upstreamed into `startCommand` in Nix?
int pipesize = 1024 * 1024;
fcntl(ret->in.get(), F_SETPIPE_SZ, &pipesize);
fcntl(ret->out.get(), F_SETPIPE_SZ, &pipesize);
return ret;
}
static void copyClosureTo( static void copyClosureTo(
::Machine::Connection & conn, ::Machine::Connection & conn,
Store & destStore, Store & destStore,
@ -87,8 +52,8 @@ static void copyClosureTo(
// FIXME: substitute output pollutes our build log // FIXME: substitute output pollutes our build log
/* Get back the set of paths that are already valid on the remote /* Get back the set of paths that are already valid on the remote
host. */ host. */
auto present = conn.queryValidPaths( auto present = conn.store->queryValidPaths(
destStore, true, closure, useSubstitutes); closure, true, useSubstitutes);
if (present.size() == closure.size()) return; if (present.size() == closure.size()) return;
@ -103,12 +68,7 @@ static void copyClosureTo(
std::unique_lock<std::timed_mutex> sendLock(conn.machine->state->sendLock, std::unique_lock<std::timed_mutex> sendLock(conn.machine->state->sendLock,
std::chrono::seconds(600)); std::chrono::seconds(600));
conn.to << ServeProto::Command::ImportPaths; conn.store->addMultipleToStoreLegacy(destStore, missing);
destStore.exportPaths(missing, conn.to);
conn.to.flush();
if (readInt(conn.from) != 1)
throw Error("remote machine failed to import closure");
} }
@ -228,7 +188,7 @@ static BuildResult performBuild(
counter & nrStepsBuilding counter & nrStepsBuilding
) )
{ {
conn.putBuildDerivationRequest(localStore, drvPath, drv, options); auto kont = conn.store->buildDerivationAsync(drvPath, drv, options);
BuildResult result; BuildResult result;
@ -237,7 +197,10 @@ static BuildResult performBuild(
startTime = time(0); startTime = time(0);
{ {
MaintainCount<counter> mc(nrStepsBuilding); MaintainCount<counter> mc(nrStepsBuilding);
result = ServeProto::Serialise<BuildResult>::read(localStore, conn); result = kont();
// Without proper call-once functions, we need to manually
// delete after calling.
kont = {};
} }
stopTime = time(0); stopTime = time(0);
@ -253,7 +216,7 @@ static BuildResult performBuild(
// If the protocol was too old to give us `builtOutputs`, initialize // If the protocol was too old to give us `builtOutputs`, initialize
// it manually by introspecting the derivation. // it manually by introspecting the derivation.
if (GET_PROTOCOL_MINOR(conn.remoteVersion) < 6) if (GET_PROTOCOL_MINOR(conn.store->getProtocol()) < 6)
{ {
// If the remote is too old to handle CA derivations, we cant get this // If the remote is too old to handle CA derivations, we cant get this
// far anyways // far anyways
@ -298,11 +261,10 @@ static void copyPathFromRemote(
lambda function only gets executed if someone tries to read lambda function only gets executed if someone tries to read
from source2, we will send the command from here rather from source2, we will send the command from here rather
than outside the lambda. */ than outside the lambda. */
conn.to << ServeProto::Command::DumpStorePath << localStore.printStorePath(info.path); conn.store->narFromPath(info.path, [&](Source & source) {
conn.to.flush(); TeeSource tee{source, sink};
extractNarData(tee, conn.store->printStorePath(info.path), narMembers);
TeeSource tee(conn.from, sink); });
extractNarData(tee, localStore.printStorePath(info.path), narMembers);
}); });
destStore.addToStore(info, *source2, NoRepair, NoCheckSigs); destStore.addToStore(info, *source2, NoRepair, NoCheckSigs);
@ -404,30 +366,39 @@ void State::buildRemote(ref<Store> destStore,
updateStep(ssConnecting); updateStep(ssConnecting);
auto storeRef = machine->completeStoreReference(); // FIXME: rewrite to use Store.
::Machine::Connection conn {
auto * pSpecified = std::get_if<StoreReference::Specified>(&storeRef.variant); .machine = machine,
.store = [&]{
auto * pSpecified = std::get_if<StoreReference::Specified>(&machine->storeUri.variant);
if (!pSpecified || pSpecified->scheme != "ssh") { if (!pSpecified || pSpecified->scheme != "ssh") {
throw Error("Currently, only (legacy-)ssh stores are supported!"); throw Error("Currently, only (legacy-)ssh stores are supported!");
} }
LegacySSHStoreConfig storeConfig { auto remoteStore = machine->openStore().dynamic_pointer_cast<LegacySSHStore>();
pSpecified->scheme, assert(remoteStore);
pSpecified->authority,
storeRef.params remoteStore->connPipeSize = 1024 * 1024;
if (machine->isLocalhost()) {
auto rp_new = remoteStore->remoteProgram.get();
rp_new.push_back("--builders");
rp_new.push_back("");
const_cast<nix::Setting<Strings> &>(remoteStore->remoteProgram).assign(rp_new);
}
remoteStore->extraSshArgs = {
"-a", "-oBatchMode=yes", "-oConnectTimeout=60", "-oTCPKeepAlive=yes"
}; };
const_cast<nix::Setting<int> &>(remoteStore->logFD).assign(logFD.get());
auto master = storeConfig.createSSHMaster( return nix::ref{remoteStore};
false, // no SSH master yet }(),
logFD.get()); };
// FIXME: rewrite to use Store.
auto child = build_remote::openConnection(machine, master);
{ {
auto activeStepState(activeStep->state_.lock()); auto activeStepState(activeStep->state_.lock());
if (activeStepState->cancelled) throw Error("step cancelled"); if (activeStepState->cancelled) throw Error("step cancelled");
activeStepState->pid = child->sshPid; activeStepState->pid = conn.store->getConnectionPid();
} }
Finally clearPid([&]() { Finally clearPid([&]() {
@ -442,35 +413,12 @@ void State::buildRemote(ref<Store> destStore,
process. Meh. */ process. Meh. */
}); });
::Machine::Connection conn {
{
.to = child->in.get(),
.from = child->out.get(),
/* Handshake. */
.remoteVersion = 0xdadbeef, // FIXME avoid dummy initialize
},
/*.machine =*/ machine,
};
Finally updateStats([&]() { Finally updateStats([&]() {
bytesReceived += conn.from.read; auto stats = conn.store->getConnectionStats();
bytesSent += conn.to.written; bytesReceived += stats.bytesReceived;
bytesSent += stats.bytesSent;
}); });
constexpr ServeProto::Version our_version = 0x206;
try {
conn.remoteVersion = decltype(conn)::handshake(
conn.to,
conn.from,
our_version,
machine->storeUri.render());
} catch (EndOfFile & e) {
child->sshPid.wait();
std::string s = chomp(readFile(result.logFile));
throw Error("cannot connect to %1%: %2%", machine->storeUri.render(), s);
}
{ {
auto info(machine->state->connectInfo.lock()); auto info(machine->state->connectInfo.lock());
info->consecutiveFailures = 0; info->consecutiveFailures = 0;
@ -539,7 +487,7 @@ void State::buildRemote(ref<Store> destStore,
auto now1 = std::chrono::steady_clock::now(); auto now1 = std::chrono::steady_clock::now();
auto infos = conn.queryPathInfos(*localStore, outputs); auto infos = conn.store->queryPathInfosUncached(outputs);
size_t totalNarSize = 0; size_t totalNarSize = 0;
for (auto & [_, info] : infos) totalNarSize += info.narSize; for (auto & [_, info] : infos) totalNarSize += info.narSize;
@ -574,9 +522,11 @@ void State::buildRemote(ref<Store> destStore,
} }
} }
/* Shut down the connection. */ /* Shut down the connection done by RAII.
child->in = -1;
child->sshPid.wait(); Only difference is kill() instead of wait() (i.e. send signal
then wait())
*/
} catch (Error & e) { } catch (Error & e) {
/* Disable this machine until a certain period of time has /* Disable this machine until a certain period of time has

View File

@ -20,9 +20,7 @@
#include "store-api.hh" #include "store-api.hh"
#include "sync.hh" #include "sync.hh"
#include "nar-extractor.hh" #include "nar-extractor.hh"
#include "serve-protocol.hh" #include "legacy-ssh-store.hh"
#include "serve-protocol-impl.hh"
#include "serve-protocol-connection.hh"
#include "machines.hh" #include "machines.hh"
@ -292,9 +290,11 @@ struct Machine : nix::Machine
bool isLocalhost() const; bool isLocalhost() const;
// A connection to a machine // A connection to a machine
struct Connection : nix::ServeProto::BasicClientConnection { struct Connection {
// Backpointer to the machine // Backpointer to the machine
ptr machine; ptr machine;
// Opened store
nix::ref<nix::LegacySSHStore> store;
}; };
}; };