nix: split module-eval into per-subsystem checks
The single module-eval derivation forced ~62 full nixosSystem fixtures live at once to compute its cases list: 10.6GB peak RSS / 5m25s to evaluate, by far the dominant cost in nix flake check. Splits it into 21 independent checks.module-eval-* derivations (1-7 fixtures each) sharing builders/helpers via module-eval/lib.nix, so no single derivation needs more than a handful of fixtures live at once. A few cases spanning two clusters carry a small duplicated fixture rather than threading shared state through lib.nix.
This commit is contained in:
parent
69b70a9c6f
commit
dc418a5223
24 changed files with 3760 additions and 2997 deletions
95
nix/module-eval/agent-otel.nix
Normal file
95
nix/module-eval/agent-otel.nix
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# `checks.module-eval-agent-otel` — see ./lib.nix for the shared
|
||||
# rationale (why this suite exists, naming convention, "evaluates
|
||||
# not executes").
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
self,
|
||||
nixosSystem,
|
||||
}:
|
||||
let
|
||||
inherit
|
||||
(import ./lib.nix {
|
||||
inherit
|
||||
pkgs
|
||||
lib
|
||||
self
|
||||
nixosSystem
|
||||
;
|
||||
})
|
||||
agent
|
||||
runGroup
|
||||
;
|
||||
|
||||
# The log path's three hops, one fixture each. Nothing carries a journal
|
||||
# record end to end at eval time, so what these defend is the part no tier
|
||||
# can check for itself: each hop's output is the next hop's input, and
|
||||
# every mismatch between them is silent — a push accepted and routed
|
||||
# nowhere, a receiver pointed at an empty directory, a pipeline that does
|
||||
# not exist.
|
||||
agentBridge = "http://10.42.0.1:4318";
|
||||
|
||||
agentOtel = agent {
|
||||
otel.enable = true;
|
||||
otel.endpoint = agentBridge;
|
||||
};
|
||||
|
||||
# The same agent over the other wire protocol. An exporter's NAME is what
|
||||
# selects it, so this is where a defined exporter and the pipeline's
|
||||
# reference to it can drift apart.
|
||||
agentOtelGrpc = agent {
|
||||
otel.enable = true;
|
||||
otel.endpoint = agentBridge;
|
||||
otel.protocol = "grpc";
|
||||
};
|
||||
|
||||
agentNoOtel = agent { };
|
||||
|
||||
agentSettings = machine: machine.services.opentelemetry-collector.settings;
|
||||
cases = [
|
||||
{
|
||||
# The journald receiver's own default directory is the RUNTIME
|
||||
# journal, and a container that stores persistently leaves that
|
||||
# empty. At the default the forwarder validates, starts, reports
|
||||
# healthy and ships nothing, so this one literal is the difference
|
||||
# between the path working and silently not.
|
||||
name = "the agent forwarder reads the persistent journal, not the runtime one";
|
||||
ok = ((agentSettings agentOtel).receivers.journald.directory or null) == "/var/log/journal";
|
||||
}
|
||||
{
|
||||
# The hop's two ends: what it reads, and where what it reads goes.
|
||||
# The endpoint is compared against the value the fixture handed the
|
||||
# option rather than a literal spelled here, so an exporter that
|
||||
# stopped reading the option fails instead of matching a constant
|
||||
# that travelled beside it.
|
||||
name = "the agent forwarder ships the journal to the endpoint its hive gave it";
|
||||
ok =
|
||||
let
|
||||
s = agentSettings agentOtel;
|
||||
p = s.service.pipelines.logs;
|
||||
in
|
||||
p.receivers == [ "journald" ]
|
||||
&& p.exporters != [ ]
|
||||
&& lib.all (e: (s.exporters ? ${e}) && s.exporters.${e}.endpoint == agentBridge) p.exporters;
|
||||
}
|
||||
{
|
||||
# Presence control for the two cases above: with the switch off there
|
||||
# is no collector in the container at all, so their passing is about
|
||||
# the wiring rather than about a unit that renders regardless.
|
||||
name = "an agent that has not opted into telemetry runs no collector";
|
||||
ok = !agentNoOtel.services.opentelemetry-collector.enable;
|
||||
}
|
||||
{
|
||||
# `otlp` and `otlphttp` are different components and the protocol
|
||||
# option picks which one is defined. A pipeline left naming the other
|
||||
# is a startup failure; an exporter no pipeline names is silence.
|
||||
name = "the agent forwarder's exporter and its pipeline agree on the protocol";
|
||||
ok =
|
||||
let
|
||||
s = agentSettings agentOtelGrpc;
|
||||
in
|
||||
(s.exporters ? otlp) && s.service.pipelines.logs.exporters == [ "otlp" ];
|
||||
}
|
||||
];
|
||||
in
|
||||
runGroup "agent-otel" cases
|
||||
Loading…
Reference in a new issue