ssh-ng: better way to keep SSH errors visible

A better fix than in 104448e75d, hence a
revert + the fix.

It turns out that this commit has the side-effect that when having e.g.
`StrictHostKeyChecking=accept-new` for a remote builder, the warnings à la

    Warning: Permanently added 'builder' (ED25519) to the list of known hosts.

actually end up in the derivation's log whereas hostkey verification
errors don't, but only in the stderr of the `nix-build` invocation
(which was the motivation for the patch).

This change writes the stderr from the build-hook to

* the daemon's stderr, so that the SSH errors appear in the journal
  (which was the case before 104448e75d)
* the client's stderr, as a log message
* NOT to the drv log (this is handled via `handleJSONLogMessage`)

I tried to fix the issue for legacy-ssh as well, but failed and
ultimately decided to not bother.

I know that we'll sooner or later replace the entire component, however
this is the part of the patch I have working for a while, so I figured I
might still submit it for the time being.

Change-Id: I21ca1aa0d8ae281d2eacddf26e0aa825272707e5
This commit is contained in:
Maximilian Bosch 2024-10-12 23:42:59 +02:00
parent 326cbecb61
commit 4682e40183
4 changed files with 5 additions and 9 deletions

View file

@ -1211,6 +1211,7 @@ HookReply DerivationGoal::tryBuildHook()
else { else {
s += "\n"; s += "\n";
writeLogsToStderr(s); writeLogsToStderr(s);
logger->log(lvlInfo, s);
} }
} }

View file

@ -68,11 +68,11 @@ ref<Store> Machine::openStore() const
{ {
Store::Params storeParams; Store::Params storeParams;
if (storeUri.starts_with("ssh://")) { if (storeUri.starts_with("ssh://")) {
storeParams["log-fd"] = "4";
storeParams["max-connections"] = "1"; storeParams["max-connections"] = "1";
} }
if (storeUri.starts_with("ssh://") || storeUri.starts_with("ssh-ng://")) { if (storeUri.starts_with("ssh://") || storeUri.starts_with("ssh-ng://")) {
storeParams["log-fd"] = "4";
if (sshKey != "") if (sshKey != "")
storeParams["ssh-key"] = sshKey; storeParams["ssh-key"] = sshKey;
if (sshPublicHostKey != "") if (sshPublicHostKey != "")

View file

@ -30,11 +30,6 @@ struct SSHStoreConfig : virtual RemoteStoreConfig, virtual CommonSSHStoreConfig
class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore
{ {
public: public:
// Hack for getting remote build log output.
// Intentionally not in `SSHStoreConfig` so that it doesn't appear in
// the documentation
const Setting<int> 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) SSHStore(const std::string & scheme, const std::string & host, const Params & params)
: StoreConfig(params) : StoreConfig(params)
, RemoteStoreConfig(params) , RemoteStoreConfig(params)
@ -49,8 +44,7 @@ public:
sshPublicHostKey, sshPublicHostKey,
// Use SSH master only if using more than 1 connection. // Use SSH master only if using more than 1 connection.
connections->capacity() > 1, connections->capacity() > 1,
compress, compress)
logFD)
{ {
} }

View file

@ -97,7 +97,8 @@ in
builder.wait_for_unit("sshd.service") builder.wait_for_unit("sshd.service")
out = client.fail("nix-build ${expr nodes.client 1} 2>&1") out = client.fail("nix-build ${expr nodes.client 1} 2>&1")
assert "error: failed to start SSH connection to 'root@builder': Host key verification failed" in out, f"No host verification error in {out}" assert "Host key verification failed." in out, f"No host verification error:\n{out}"
assert "warning: SSH to 'root@builder' failed, stdout first line: '''" in out, f"No details about which host:\n{out}"
client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world' >&2") client.succeed(f"ssh -o StrictHostKeyChecking=no {builder.name} 'echo hello world' >&2")