1{
2 config,
3 lib,
4 pkgs,
5 options,
6 ...
7}:
8
9let
10 cfg = config.services.prometheus.exporters.smartctl;
11
12 inherit (lib) mkOption types literalExpression;
13
14 args = lib.escapeShellArgs (
15 [
16 "--web.listen-address=${cfg.listenAddress}:${toString cfg.port}"
17 "--smartctl.interval=${cfg.maxInterval}"
18 ]
19 ++ map (device: "--smartctl.device=${device}") cfg.devices
20 ++ cfg.extraFlags
21 );
22
23in
24{
25 port = 9633;
26
27 extraOpts = {
28 devices = mkOption {
29 type = types.listOf types.str;
30 default = [ ];
31 example = literalExpression ''
32 [ "/dev/sda", "/dev/nvme0n1" ];
33 '';
34 description = ''
35 Paths to the disks that will be monitored. Will autodiscover
36 all disks if none given.
37 '';
38 };
39
40 maxInterval = mkOption {
41 type = types.str;
42 default = "60s";
43 example = "2m";
44 description = ''
45 Interval that limits how often a disk can be queried.
46 '';
47 };
48 };
49
50 serviceOpts = {
51 serviceConfig = {
52 AmbientCapabilities = [
53 "CAP_SYS_RAWIO"
54 "CAP_SYS_ADMIN"
55 ];
56 CapabilityBoundingSet = [
57 "CAP_SYS_RAWIO"
58 "CAP_SYS_ADMIN"
59 ];
60 DevicePolicy = "closed";
61 DeviceAllow = lib.mkOverride 50 [
62 "block-blkext rw"
63 "block-sd rw"
64 "char-nvme rw"
65 ];
66 ExecStart = "${pkgs.prometheus-smartctl-exporter}/bin/smartctl_exporter ${args}";
67 PrivateDevices = lib.mkForce false;
68 ProtectProc = "invisible";
69 ProcSubset = "pid";
70 SupplementaryGroups = [
71 "disk"
72 "smartctl-exporter-access"
73 ];
74 SystemCallFilter = [
75 "@system-service"
76 "~@privileged"
77 ];
78 };
79 };
80}