Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssh-ng: also store build logs to make them accessible by nix log #6029

Merged
merged 7 commits into from
Mar 7, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/libstore/build/derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1175,10 +1175,11 @@ bool DerivationGoal::isReadDesc(int fd)
return fd == hook->builderOut.readSide.get();
}


void DerivationGoal::handleChildOutput(int fd, std::string_view data)
{
if (isReadDesc(fd))
// local & `ssh://`-builds are dealt with here.
auto isWrittenToLog = isReadDesc(fd);
if (isWrittenToLog)
Ma27 marked this conversation as resolved.
Show resolved Hide resolved
{
logSize += data.size();
if (settings.maxLogSize && logSize > settings.maxLogSize) {
Expand Down Expand Up @@ -1207,7 +1208,16 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data)
if (hook && fd == hook->fromHook.readSide.get()) {
for (auto c : data)
if (c == '\n') {
handleJSONLogMessage(currentHookLine, worker.act, hook->activities, true);
auto json = parseJSONMessage(currentHookLine);
if (json) {
auto s = handleJSONLogMessage(*json, worker.act, hook->activities, true);
// ensure that logs from a builder using `ssh-ng://` as protocol
// are also available to `nix log`.
if (s && !isWrittenToLog && logSink && (*json)["type"] == resBuildLogLine) {
auto f = (*json)["fields"];
(*logSink)((f.size() > 0 ? f.at(0).get<std::string>() : "") + "\n");
}
}
currentHookLine.clear();
} else
currentHookLine += c;
Expand Down
78 changes: 45 additions & 33 deletions src/libutil/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,51 +266,63 @@ static Logger::Fields getFields(nlohmann::json & json)
return fields;
}

bool handleJSONLogMessage(const std::string & msg,
const Activity & act, std::map<ActivityId, Activity> & activities, bool trusted)
std::optional<nlohmann::json> parseJSONMessage(const std::string & msg)
{
if (!hasPrefix(msg, "@nix ")) return false;

if (!hasPrefix(msg, "@nix ")) return std::nullopt;
try {
auto json = nlohmann::json::parse(std::string(msg, 5));

std::string action = json["action"];

if (action == "start") {
auto type = (ActivityType) json["type"];
if (trusted || type == actFileTransfer)
activities.emplace(std::piecewise_construct,
std::forward_as_tuple(json["id"]),
std::forward_as_tuple(*logger, (Verbosity) json["level"], type,
json["text"], getFields(json["fields"]), act.id));
}
return nlohmann::json::parse(std::string(msg, 5));
} catch (std::exception & e) {
printError("bad JSON log message from builder: %s", e.what());
}
return std::nullopt;
}

else if (action == "stop")
activities.erase((ActivityId) json["id"]);
bool handleJSONLogMessage(nlohmann::json & json,
const Activity & act, std::map<ActivityId, Activity> & activities,
bool trusted)
{
std::string action = json["action"];

if (action == "start") {
auto type = (ActivityType) json["type"];
if (trusted || type == actFileTransfer)
activities.emplace(std::piecewise_construct,
std::forward_as_tuple(json["id"]),
std::forward_as_tuple(*logger, (Verbosity) json["level"], type,
json["text"], getFields(json["fields"]), act.id));
}

else if (action == "result") {
auto i = activities.find((ActivityId) json["id"]);
if (i != activities.end())
i->second.result((ResultType) json["type"], getFields(json["fields"]));
}
else if (action == "stop")
activities.erase((ActivityId) json["id"]);

else if (action == "setPhase") {
std::string phase = json["phase"];
act.result(resSetPhase, phase);
}
else if (action == "result") {
auto i = activities.find((ActivityId) json["id"]);
if (i != activities.end())
i->second.result((ResultType) json["type"], getFields(json["fields"]));
}

else if (action == "msg") {
std::string msg = json["msg"];
logger->log((Verbosity) json["level"], msg);
}
else if (action == "setPhase") {
std::string phase = json["phase"];
act.result(resSetPhase, phase);
}

} catch (std::exception & e) {
printError("bad JSON log message from builder: %s", e.what());
else if (action == "msg") {
std::string msg = json["msg"];
logger->log((Verbosity) json["level"], msg);
}

return true;
}

bool handleJSONLogMessage(const std::string & msg,
const Activity & act, std::map<ActivityId, Activity> & activities, bool trusted)
{
auto json = parseJSONMessage(msg);
if (!json) return false;

return handleJSONLogMessage(*json, act, activities, trusted);
}

Activity::~Activity()
{
try {
Expand Down
8 changes: 8 additions & 0 deletions src/libutil/logging.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "error.hh"
#include "config.hh"

#include <nlohmann/json_fwd.hpp>

namespace nix {

typedef enum {
Expand Down Expand Up @@ -166,6 +168,12 @@ Logger * makeSimpleLogger(bool printBuildLogs = true);

Logger * makeJSONLogger(Logger & prevLogger);

std::optional<nlohmann::json> parseJSONMessage(const std::string & msg);

bool handleJSONLogMessage(nlohmann::json & json,
const Activity & act, std::map<ActivityId, Activity> & activities,
bool trusted);

bool handleJSONLogMessage(const std::string & msg,
const Activity & act, std::map<ActivityId, Activity> & activities,
bool trusted);
Expand Down
10 changes: 6 additions & 4 deletions tests/build-hook-ca-fixed.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ let
args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")];
outputHashMode = "recursive";
outputHashAlgo = "sha256";
} // removeAttrs args ["builder" "meta"])
// { meta = args.meta or {}; };
} // removeAttrs args ["builder" "meta" "passthru"])
// { meta = args.meta or {}; passthru = args.passthru or {}; };

input1 = mkDerivation {
shell = busybox;
name = "build-remote-input-1";
buildCommand = "echo FOO > $out";
buildCommand = "echo hi; echo FOO > $out";
requiredSystemFeatures = ["foo"];
outputHash = "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=";
};

input2 = mkDerivation {
shell = busybox;
name = "build-remote-input-2";
buildCommand = "echo BAR > $out";
buildCommand = "echo hi; echo BAR > $out";
requiredSystemFeatures = ["bar"];
outputHash = "sha256-XArauVH91AVwP9hBBQNlkX9ccuPpSYx9o0zeIHb6e+Q=";
};
Expand All @@ -34,6 +34,7 @@ let
shell = busybox;
name = "build-remote-input-3";
buildCommand = ''
echo hi
read x < ${input2}
echo $x BAZ > $out
'';
Expand All @@ -46,6 +47,7 @@ in
mkDerivation {
shell = busybox;
name = "build-remote";
passthru = { inherit input1 input2 input3; };
buildCommand =
''
read x < ${input1}
Expand Down
10 changes: 6 additions & 4 deletions tests/build-hook.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,28 @@ let
inherit system;
builder = busybox;
args = ["sh" "-e" args.builder or (builtins.toFile "builder-${args.name}.sh" "if [ -e .attrs.sh ]; then source .attrs.sh; fi; eval \"$buildCommand\"")];
} // removeAttrs args ["builder" "meta"])
// { meta = args.meta or {}; };
} // removeAttrs args ["builder" "meta" "passthru"])
// { meta = args.meta or {}; passthru = args.passthru or {}; };

input1 = mkDerivation {
shell = busybox;
name = "build-remote-input-1";
buildCommand = "echo FOO > $out";
buildCommand = "echo hi; echo FOO > $out";
requiredSystemFeatures = ["foo"];
};

input2 = mkDerivation {
shell = busybox;
name = "build-remote-input-2";
buildCommand = "echo BAR > $out";
buildCommand = "echo hi; echo BAR > $out";
requiredSystemFeatures = ["bar"];
};

input3 = mkDerivation {
shell = busybox;
name = "build-remote-input-3";
buildCommand = ''
echo hi
read x < ${input2}
echo $x BAZ > $out
'';
Expand All @@ -41,6 +42,7 @@ in
mkDerivation {
shell = busybox;
name = "build-remote";
passthru = { inherit input1 input2 input3; };
buildCommand =
''
read x < ${input1}
Expand Down
8 changes: 8 additions & 0 deletions tests/build-remote.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ nix path-info --store $TEST_ROOT/machine3 --all \
| grep -v builder-build-remote-input-2.sh \
| grep builder-build-remote-input-3.sh


if [[ -z "$CONTENT_ADDRESSED" ]]; then
thufschmitt marked this conversation as resolved.
Show resolved Hide resolved
for i in input1 input3; do
drv="$(nix-instantiate $file -A passthru.$i --store $TEST_ROOT/machine0 --arg busybox $busybox)"
nix log --store $TEST_ROOT/machine0 "$drv"
Ma27 marked this conversation as resolved.
Show resolved Hide resolved
done
fi

# Behavior of keep-failed
out="$(nix-build 2>&1 failing.nix \
--builders "$(join_by '; ' "${builders[@]}")" \
Expand Down