1# Global configuration for atop.
2
3{ config, lib, pkgs, ... }:
4
5let cfg = config.programs.atop;
6
7in
8{
9 ###### interface
10
11 options = {
12
13 programs.atop = rec {
14
15 enable = lib.mkEnableOption "Atop, a tool for monitoring system resources";
16
17 package = lib.mkPackageOption pkgs "atop" { };
18
19 netatop = {
20 enable = lib.mkOption {
21 type = lib.types.bool;
22 default = false;
23 description = ''
24 Whether to install and enable the netatop kernel module.
25 Note: this sets the kernel taint flag "O" for loading out-of-tree modules.
26 '';
27 };
28 package = lib.mkOption {
29 type = lib.types.package;
30 default = config.boot.kernelPackages.netatop;
31 defaultText = lib.literalExpression "config.boot.kernelPackages.netatop";
32 description = ''
33 Which package to use for netatop.
34 '';
35 };
36 };
37
38 atopgpu.enable = lib.mkOption {
39 type = lib.types.bool;
40 default = false;
41 description = ''
42 Whether to install and enable the atopgpud daemon to get information about
43 NVIDIA gpus.
44 '';
45 };
46
47 setuidWrapper.enable = lib.mkOption {
48 type = lib.types.bool;
49 default = false;
50 description = ''
51 Whether to install a setuid wrapper for Atop. This is required to use some of
52 the features as non-root user (e.g.: ipc information, netatop, atopgpu).
53 Atop tries to drop the root privileges shortly after starting.
54 '';
55 };
56
57 atopService.enable = lib.mkOption {
58 type = lib.types.bool;
59 default = true;
60 description = ''
61 Whether to enable the atop service responsible for storing statistics for
62 long-term analysis.
63 '';
64 };
65 atopRotateTimer.enable = lib.mkOption {
66 type = lib.types.bool;
67 default = true;
68 description = ''
69 Whether to enable the atop-rotate timer, which restarts the atop service
70 daily to make sure the data files are rotate.
71 '';
72 };
73 atopacctService.enable = lib.mkOption {
74 type = lib.types.bool;
75 default = true;
76 description = ''
77 Whether to enable the atopacct service which manages process accounting.
78 This allows Atop to gather data about processes that disappeared in between
79 two refresh intervals.
80 '';
81 };
82 settings = lib.mkOption {
83 type = lib.types.attrs;
84 default = { };
85 example = {
86 flags = "a1f";
87 interval = 5;
88 };
89 description = ''
90 Parameters to be written to {file}`/etc/atoprc`.
91 '';
92 };
93 };
94 };
95
96 config = lib.mkIf cfg.enable (
97 let
98 atop =
99 if cfg.atopgpu.enable then
100 (cfg.package.override { withAtopgpu = true; })
101 else
102 cfg.package;
103 in
104 {
105 environment.etc = lib.mkIf (cfg.settings != { }) {
106 atoprc.text = lib.concatStrings
107 (lib.mapAttrsToList
108 (n: v: ''
109 ${n} ${builtins.toString v}
110 '')
111 cfg.settings);
112 };
113 environment.systemPackages = [ atop (lib.mkIf cfg.netatop.enable cfg.netatop.package) ];
114 boot.extraModulePackages = [ (lib.mkIf cfg.netatop.enable cfg.netatop.package) ];
115 systemd =
116 let
117 mkSystemd = type: name: restartTriggers: {
118 ${name} = {
119 inherit restartTriggers;
120 wantedBy = [ (if type == "services" then "multi-user.target" else if type == "timers" then "timers.target" else null) ];
121 };
122 };
123 mkService = mkSystemd "services";
124 mkTimer = mkSystemd "timers";
125 in
126 {
127 packages = [ atop (lib.mkIf cfg.netatop.enable cfg.netatop.package) ];
128 services = lib.mkMerge [
129 (lib.mkIf cfg.atopService.enable (lib.recursiveUpdate
130 (mkService "atop" [ atop ])
131 {
132 # always convert logs to newer version first
133 # XXX might trigger TimeoutStart but restarting atop.service will
134 # convert remainings logs and start eventually
135 atop.preStart = ''
136 set -e -u
137 shopt -s nullglob
138 rm -f "$LOGPATH"/atop_*.new
139 for logfile in "$LOGPATH"/atop_*
140 do
141 ${atop}/bin/atopconvert "$logfile" "$logfile".new
142 # only replace old file if version was upgraded to avoid
143 # false positives for atop-rotate.service
144 if ! ${pkgs.diffutils}/bin/cmp -s "$logfile" "$logfile".new
145 then
146 mv -v -f "$logfile".new "$logfile"
147 else
148 rm -f "$logfile".new
149 fi
150 done
151 '';
152 }))
153 (lib.mkIf cfg.atopacctService.enable (mkService "atopacct" [ atop ]))
154 (lib.mkIf cfg.netatop.enable (mkService "netatop" [ cfg.netatop.package ]))
155 (lib.mkIf cfg.atopgpu.enable (mkService "atopgpu" [ atop ]))
156 ];
157 timers = lib.mkIf cfg.atopRotateTimer.enable (mkTimer "atop-rotate" [ atop ]);
158 };
159
160 security.wrappers = lib.mkIf cfg.setuidWrapper.enable {
161 atop = {
162 setuid = true;
163 owner = "root";
164 group = "root";
165 source = "${atop}/bin/atop";
166 };
167 };
168 }
169 );
170}