aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/dashboards.nix52
1 files changed, 42 insertions, 10 deletions
diff --git a/modules/dashboards.nix b/modules/dashboards.nix
index 125e3e2..2fc24c8 100644
--- a/modules/dashboards.nix
+++ b/modules/dashboards.nix
@@ -2,7 +2,7 @@
#
# Returns an attrset of { name = derivation; }, where each derivation is a single
# dashboard JSON file. modules/server.nix drops these into /etc/grafana-dashboards.
-{ lib, runCommand, fetchurl, jq, dsUid }:
+{ lib, runCommand, fetchurl, jq, python3, dsUid }:
let
# Dashboards exported from grafana.com carry an `__inputs` block and reference their
@@ -29,12 +29,23 @@ let
| .id = null
'';
+ # One jq invocation, shared by both sources of dashboards below.
+ #
+ # Deliberately a single line with no trailing newline: callers append redirections
+ # (`< $src > "$out"`), and a multi-line string would put those on a line of their own
+ # as a separate command -- which truncates $out to zero bytes and sends jq's output to
+ # the build log, without failing the build.
+ jqFixup = lib.concatStringsSep " " [
+ "jq"
+ "--arg prom ${lib.escapeShellArg dsUid.prometheus}"
+ "--arg loki ${lib.escapeShellArg dsUid.loki}"
+ (lib.escapeShellArg fixupProgram)
+ ];
+
fixup = name: src: runCommand "grafana-dashboard-${name}.json"
{ nativeBuildInputs = [ jq ]; }
''
- jq --arg prom ${lib.escapeShellArg dsUid.prometheus} \
- --arg loki ${lib.escapeShellArg dsUid.loki} \
- ${lib.escapeShellArg fixupProgram} < ${src} > "$out"
+ ${jqFixup} < ${src} > "$out"
'';
fromGrafanaCom = { name, id, rev, hash }:
@@ -42,6 +53,28 @@ let
url = "https://grafana.com/api/dashboards/${toString id}/revisions/${toString rev}/download";
inherit hash;
});
+
+ # The generators and the panel helpers they import.
+ generators = ../dashboards;
+
+ # Our own dashboards are generated here rather than committed as JSON. The JSON is
+ # machine-written and the generator beside it is the only source of truth, so keeping
+ # both in git only creates a way for them to drift -- and a build that runs the
+ # generator cannot serve a stale dashboard. Note flakes copy only git-tracked files
+ # into the store, so committing the .json is the *only* way to also read it from disk;
+ # there is no "gitignore it and read it anyway" option.
+ fromGenerator = { name, generator }:
+ runCommand "grafana-dashboard-${name}.json"
+ {
+ nativeBuildInputs = [ jq python3 ];
+ # panels.py sits next to the generators and is imported by both of them.
+ PYTHONPATH = generators;
+ # The store path is read-only; without this Python warns about __pycache__.
+ PYTHONDONTWRITEBYTECODE = 1;
+ }
+ ''
+ python3 ${generators}/${generator} | ${jqFixup} > "$out"
+ '';
in
{
# https://grafana.com/grafana/dashboards/1860
@@ -65,11 +98,10 @@ in
# can never render against Prometheus, however it is provisioned. This is a
# Prometheus-native replacement built on the metrics we actually export: node
# exporter's zfs collector plus the ZFS textfile collector.
- # Generated by dashboards/gen_zfs.py.
- zfs-pools = fixup "zfs-pools" ../dashboards/zfs-pools.json;
+ zfs-pools = fromGenerator { name = "zfs-pools"; generator = "gen_zfs.py"; };
- # CrystalDiskInfo-style per-drive SMART view. Generated by dashboards/gen_smart.py.
- # The Good/Caution/Bad verdict and the per-drive row titles both come from the
- # recording rules in rules/smartctl.yml, so this one needs those loaded to be useful.
- drive-health = fixup "drive-health" ../dashboards/smart.json;
+ # CrystalDiskInfo-style per-drive SMART view. The Good/Caution/Bad verdict and the
+ # per-drive row titles both come from the recording rules in rules/smartctl.yml, so
+ # this one needs those loaded to be useful.
+ drive-health = fromGenerator { name = "drive-health"; generator = "gen_smart.py"; };
}