@cryptotaxi247 / infra-1 / commits / c1e5ad59

prometheus-nixos-exporter: add nix 2.19.0 compat

The output of `nix path-info --json` changed from a list to an object in nix 2.19.0. Add a simple version detection, so we can support both output formats. Fixes: #346

Martin Weinelt committed Feb 3, 2024 at 17:45 UTC c1e5ad598da171864e6f3d7a05c477fc29e19958
2 files changed +34 -10
modules/prometheus/default.nix
+3 -2
@@ -28,8 +28,9 @@
28 Restart = "always";
29 RestartSec = "60s";
30 ExecStart = let
31 - python = pkgs.python3.withPackages (p: [
32 - p.prometheus_client
31 + python = pkgs.python3.withPackages (ps: with ps; [
32 + packaging
33 + prometheus-client
34 ]);
35 in ''
36 ${python}/bin/python ${./nixos-exporter.py}
modules/prometheus/nixos-exporter.py
+31 -8
@@ -1,15 +1,33 @@
1 #!/usr/bin/env nix-shell
2 -#!nix-shell -i python3 -p python3 -p python3Packages.prometheus_client
2 +#!nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ prometheus-client packaging ])"
3
4
5 import subprocess
6 import json
7 -from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily
8 -from prometheus_client import CollectorRegistry, generate_latest, start_http_server
9 -from pprint import pprint
7 +import sys
8 import time
9 +from packaging.version import Version
10 +from prometheus_client.core import GaugeMetricFamily
11 +from prometheus_client import CollectorRegistry, start_http_server
12 +
13
14 class NixosSystemCollector:
15 + def __init__(self):
16 + nix_version = self.get_nix_version()
17 +
18 + # https://github.com/NixOS/nix/pull/9242
19 + self.nix_path_info_returns_object = nix_version >= Version("2.19.0")
20 +
21 + def get_nix_version(self):
22 + result = subprocess.run(["nix", "--version"], stdout=subprocess.PIPE)
23 +
24 + if result.returncode == 0:
25 + response = result.stdout.decode().strip()
26 + return Version(response.split()[-1])
27 + else:
28 + print("Failed to determine nix version", file=sys.stderr)
29 + sys.exit(1)
30 +
31 def collect(self):
32 # note: Gauges because of rollbacks.
33 current_system = GaugeMetricFamily(
@@ -40,14 +58,19 @@ class NixosSystemCollector:
58 return None
59
60 def get_time(self, path):
43 - # nix path-info --json /run/booted-system | jq .[0].registrationTime
61 result = subprocess.run(
45 - [ "nix", "path-info", "--json", path ],
46 - stdout=subprocess.PIPE
62 + ["nix", "path-info", "--json", path], stdout=subprocess.PIPE
63 )
64 if result.returncode == 0:
65 parsed = json.loads(result.stdout)
50 - return parsed[0]['registrationTime']
66 +
67 + if self.nix_path_info_returns_object:
68 + # nix path-info --json /run/booted-system | jq .[].registrationTime
69 + for path_info in parsed.values():
70 + return path_info["registrationTime"]
71 + else:
72 + # nix path-info --json /run/booted-system | jq .[0].registrationTime
73 + return parsed[0]["registrationTime"]
74
75 return 0
76