From d2d1386abb358fa547a40fc8df613d799155b56d Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Thu, 27 Aug 2026 12:45:44 -0500 Subject: split into a flake with separable collectors/server modules Replaces the single lgtm.nix with a flake exposing two NixOS modules under services.telemetry, so the web services can move into a container declared in the consuming config rather than one hardcoded here. modules/collectors.nix host-side: node + smartctl exporters, the ZFS and SMART textfile collector timers, Alloy journal shipping. Must run on the host -- reads /proc, /sys, raw block devices and ZFS ioctls. modules/server.nix Prometheus, Loki, Grafana, optional Caddy. modules/common.nix ports, shared by both halves. modules/dashboards.nix jq fixup and grafana.com fetches. modules/packages.nix the two collectors as ordinary packages. Modules are exported as paths, not functions, so they evaluate with the consumer's nixpkgs; the flake's own input only affects packages/checks/devShells. Multi-host support. collectorHosts is a list, both scrape jobs relabel __address__ into a `host` label, and all 133 queries in the two generated dashboards are scoped to host=~"$host" behind a single-select Host picker. `instance` could not serve as that key: one machine is scraped twice on different ports (textfile metrics on :9100, smartctl_* on :9633) and the recording rules join across that boundary. Grafana's secret key becomes a plain secretKeyFile path wired through LoadCredential, with an assertion -- nixpkgs 26.05 dropped the default. No sops-nix input. nix flake check runs promtool over the rules, diffs the committed dashboard JSON against what the generators produce, and evaluates both modules. Also fixes smart-selftest emitting a placeholder identity line when smartctl cannot open a device. smartctl exits 0 with well-formed but empty JSON in that case, so "SSD - unknown model - no serial" was reaching a dashboard row title; it now emits nothing and lets the smartctl:ident fallback apply. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JKczN1f66kmLxNBLX37voQ --- modules/common.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 modules/common.nix (limited to 'modules/common.nix') diff --git a/modules/common.nix b/modules/common.nix new file mode 100644 index 0000000..480aa62 --- /dev/null +++ b/modules/common.nix @@ -0,0 +1,46 @@ +# Options both halves need to agree on. +# +# The collectors bind these ports; the server scrapes them and pushes to them. When the +# two halves live in separate NixOS configurations (host + container) there is no shared +# `config` to read, so each side sets its own copy and it is on you to keep them equal — +# which is why they are gathered in one small file rather than scattered. +# +# Imported by both modules/collectors.nix and modules/server.nix. Importing the same +# path twice is harmless: the module system deduplicates imports by path, so a +# configuration that uses both halves does not end up declaring these twice. +{ lib, ... }: + +let + inherit (lib) mkOption types; + + portOption = default: description: mkOption { + inherit default description; + type = types.port; + }; +in +{ + options.services.telemetry.ports = { + node = portOption 9100 '' + Port the Prometheus node exporter listens on. Also where the server's `node` + scrape job points. + ''; + + smartctl = portOption 9633 '' + Port the smartctl exporter listens on. Also where the server's `smartctl` scrape + job points. + ''; + + loki = portOption 3100 '' + Port Loki listens on. Also where the collectors' log shipper pushes to. + ''; + + prometheus = portOption 9090 '' + Port Prometheus listens on. + ''; + + grafana = portOption 3000 '' + Port Grafana listens on. If the reverse proxy is enabled this stays internal and + the proxy is what you connect to. + ''; + }; +} -- cgit v1.3.1