at 23.05-pre 11 kB view raw
1{ config, pkgs, lib, ... }: 2 3with lib; 4 5let 6 cfg = config.services.netdata; 7 8 wrappedPlugins = pkgs.runCommand "wrapped-plugins" { preferLocalBuild = true; } '' 9 mkdir -p $out/libexec/netdata/plugins.d 10 ln -s /run/wrappers/bin/apps.plugin $out/libexec/netdata/plugins.d/apps.plugin 11 ln -s /run/wrappers/bin/cgroup-network $out/libexec/netdata/plugins.d/cgroup-network 12 ln -s /run/wrappers/bin/perf.plugin $out/libexec/netdata/plugins.d/perf.plugin 13 ln -s /run/wrappers/bin/slabinfo.plugin $out/libexec/netdata/plugins.d/slabinfo.plugin 14 ln -s /run/wrappers/bin/freeipmi.plugin $out/libexec/netdata/plugins.d/freeipmi.plugin 15 ''; 16 17 plugins = [ 18 "${cfg.package}/libexec/netdata/plugins.d" 19 "${wrappedPlugins}/libexec/netdata/plugins.d" 20 ] ++ cfg.extraPluginPaths; 21 22 configDirectory = pkgs.runCommand "netdata-config-d" { } '' 23 mkdir $out 24 ${concatStringsSep "\n" (mapAttrsToList (path: file: '' 25 mkdir -p "$out/$(dirname ${path})" 26 ln -s "${file}" "$out/${path}" 27 '') cfg.configDir)} 28 ''; 29 30 localConfig = { 31 global = { 32 "config directory" = "/etc/netdata/conf.d"; 33 "plugins directory" = concatStringsSep " " plugins; 34 }; 35 web = { 36 "web files owner" = "root"; 37 "web files group" = "root"; 38 }; 39 "plugin:cgroups" = { 40 "script to get cgroup network interfaces" = "${wrappedPlugins}/libexec/netdata/plugins.d/cgroup-network"; 41 "use unified cgroups" = "yes"; 42 }; 43 }; 44 mkConfig = generators.toINI {} (recursiveUpdate localConfig cfg.config); 45 configFile = pkgs.writeText "netdata.conf" (if cfg.configText != null then cfg.configText else mkConfig); 46 47 defaultUser = "netdata"; 48 49in { 50 options = { 51 services.netdata = { 52 enable = mkEnableOption (lib.mdDoc "netdata"); 53 54 package = mkOption { 55 type = types.package; 56 default = pkgs.netdata; 57 defaultText = literalExpression "pkgs.netdata"; 58 description = lib.mdDoc "Netdata package to use."; 59 }; 60 61 user = mkOption { 62 type = types.str; 63 default = "netdata"; 64 description = lib.mdDoc "User account under which netdata runs."; 65 }; 66 67 group = mkOption { 68 type = types.str; 69 default = "netdata"; 70 description = lib.mdDoc "Group under which netdata runs."; 71 }; 72 73 configText = mkOption { 74 type = types.nullOr types.lines; 75 description = lib.mdDoc "Verbatim netdata.conf, cannot be combined with config."; 76 default = null; 77 example = '' 78 [global] 79 debug log = syslog 80 access log = syslog 81 error log = syslog 82 ''; 83 }; 84 85 python = { 86 enable = mkOption { 87 type = types.bool; 88 default = true; 89 description = lib.mdDoc '' 90 Whether to enable python-based plugins 91 ''; 92 }; 93 extraPackages = mkOption { 94 type = types.functionTo (types.listOf types.package); 95 default = ps: []; 96 defaultText = literalExpression "ps: []"; 97 example = literalExpression '' 98 ps: [ 99 ps.psycopg2 100 ps.docker 101 ps.dnspython 102 ] 103 ''; 104 description = lib.mdDoc '' 105 Extra python packages available at runtime 106 to enable additional python plugins. 107 ''; 108 }; 109 }; 110 111 extraPluginPaths = mkOption { 112 type = types.listOf types.path; 113 default = [ ]; 114 example = literalExpression '' 115 [ "/path/to/plugins.d" ] 116 ''; 117 description = lib.mdDoc '' 118 Extra paths to add to the netdata global "plugins directory" 119 option. Useful for when you want to include your own 120 collection scripts. 121 122 Details about writing a custom netdata plugin are available at: 123 <https://docs.netdata.cloud/collectors/plugins.d/> 124 125 Cannot be combined with configText. 126 ''; 127 }; 128 129 config = mkOption { 130 type = types.attrsOf types.attrs; 131 default = {}; 132 description = lib.mdDoc "netdata.conf configuration as nix attributes. cannot be combined with configText."; 133 example = literalExpression '' 134 global = { 135 "debug log" = "syslog"; 136 "access log" = "syslog"; 137 "error log" = "syslog"; 138 }; 139 ''; 140 }; 141 142 configDir = mkOption { 143 type = types.attrsOf types.path; 144 default = {}; 145 description = lib.mdDoc '' 146 Complete netdata config directory except netdata.conf. 147 The default configuration is merged with changes 148 defined in this option. 149 Each top-level attribute denotes a path in the configuration 150 directory as in environment.etc. 151 Its value is the absolute path and must be readable by netdata. 152 Cannot be combined with configText. 153 ''; 154 example = literalExpression '' 155 "health_alarm_notify.conf" = pkgs.writeText "health_alarm_notify.conf" ''' 156 sendmail="/path/to/sendmail" 157 '''; 158 "health.d" = "/run/secrets/netdata/health.d"; 159 ''; 160 }; 161 162 enableAnalyticsReporting = mkOption { 163 type = types.bool; 164 default = false; 165 description = lib.mdDoc '' 166 Enable reporting of anonymous usage statistics to Netdata Inc. via either 167 Google Analytics (in versions prior to 1.29.4), or Netdata Inc.'s 168 self-hosted PostHog (in versions 1.29.4 and later). 169 See: <https://learn.netdata.cloud/docs/agent/anonymous-statistics> 170 ''; 171 }; 172 }; 173 }; 174 175 config = mkIf cfg.enable { 176 assertions = 177 [ { assertion = cfg.config != {} -> cfg.configText == null ; 178 message = "Cannot specify both config and configText"; 179 } 180 ]; 181 182 environment.etc."netdata/netdata.conf".source = configFile; 183 environment.etc."netdata/conf.d".source = configDirectory; 184 185 systemd.services.netdata = { 186 description = "Real time performance monitoring"; 187 after = [ "network.target" ]; 188 wantedBy = [ "multi-user.target" ]; 189 path = (with pkgs; [ curl gawk iproute2 which procps bash ]) 190 ++ lib.optional cfg.python.enable (pkgs.python3.withPackages cfg.python.extraPackages) 191 ++ lib.optional config.virtualisation.libvirtd.enable (config.virtualisation.libvirtd.package); 192 environment = { 193 PYTHONPATH = "${cfg.package}/libexec/netdata/python.d/python_modules"; 194 } // lib.optionalAttrs (!cfg.enableAnalyticsReporting) { 195 DO_NOT_TRACK = "1"; 196 }; 197 restartTriggers = [ 198 config.environment.etc."netdata/netdata.conf".source 199 config.environment.etc."netdata/conf.d".source 200 ]; 201 serviceConfig = { 202 ExecStart = "${cfg.package}/bin/netdata -P /run/netdata/netdata.pid -D -c /etc/netdata/netdata.conf"; 203 ExecReload = "${pkgs.util-linux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID"; 204 ExecStartPost = pkgs.writeShellScript "wait-for-netdata-up" '' 205 while [ "$(${pkgs.netdata}/bin/netdatacli ping)" != pong ]; do sleep 0.5; done 206 ''; 207 208 TimeoutStopSec = 60; 209 Restart = "on-failure"; 210 # User and group 211 User = cfg.user; 212 Group = cfg.group; 213 # Performance 214 LimitNOFILE = "30000"; 215 # Runtime directory and mode 216 RuntimeDirectory = "netdata"; 217 RuntimeDirectoryMode = "0750"; 218 # State directory and mode 219 StateDirectory = "netdata"; 220 StateDirectoryMode = "0750"; 221 # Cache directory and mode 222 CacheDirectory = "netdata"; 223 CacheDirectoryMode = "0750"; 224 # Logs directory and mode 225 LogsDirectory = "netdata"; 226 LogsDirectoryMode = "0750"; 227 # Configuration directory and mode 228 ConfigurationDirectory = "netdata"; 229 ConfigurationDirectoryMode = "0755"; 230 # Capabilities 231 CapabilityBoundingSet = [ 232 "CAP_DAC_OVERRIDE" # is required for freeipmi and slabinfo plugins 233 "CAP_DAC_READ_SEARCH" # is required for apps plugin 234 "CAP_FOWNER" # is required for freeipmi plugin 235 "CAP_SETPCAP" # is required for apps, perf and slabinfo plugins 236 "CAP_SYS_ADMIN" # is required for perf plugin 237 "CAP_SYS_PTRACE" # is required for apps plugin 238 "CAP_SYS_RESOURCE" # is required for ebpf plugin 239 "CAP_NET_RAW" # is required for fping app 240 "CAP_SYS_CHROOT" # is required for cgroups plugin 241 "CAP_SETUID" # is required for cgroups and cgroups-network plugins 242 ]; 243 # Sandboxing 244 ProtectSystem = "full"; 245 ProtectHome = "read-only"; 246 PrivateTmp = true; 247 ProtectControlGroups = true; 248 PrivateMounts = true; 249 }; 250 }; 251 252 systemd.enableCgroupAccounting = true; 253 254 security.wrappers = { 255 "apps.plugin" = { 256 source = "${cfg.package}/libexec/netdata/plugins.d/apps.plugin.org"; 257 capabilities = "cap_dac_read_search,cap_sys_ptrace+ep"; 258 owner = cfg.user; 259 group = cfg.group; 260 permissions = "u+rx,g+x,o-rwx"; 261 }; 262 263 "cgroup-network" = { 264 source = "${cfg.package}/libexec/netdata/plugins.d/cgroup-network.org"; 265 capabilities = "cap_setuid+ep"; 266 owner = cfg.user; 267 group = cfg.group; 268 permissions = "u+rx,g+x,o-rwx"; 269 }; 270 271 "perf.plugin" = { 272 source = "${cfg.package}/libexec/netdata/plugins.d/perf.plugin.org"; 273 capabilities = "cap_sys_admin+ep"; 274 owner = cfg.user; 275 group = cfg.group; 276 permissions = "u+rx,g+x,o-rwx"; 277 }; 278 279 "slabinfo.plugin" = { 280 source = "${cfg.package}/libexec/netdata/plugins.d/slabinfo.plugin.org"; 281 capabilities = "cap_dac_override+ep"; 282 owner = cfg.user; 283 group = cfg.group; 284 permissions = "u+rx,g+x,o-rwx"; 285 }; 286 287 } // optionalAttrs (cfg.package.withIpmi) { 288 "freeipmi.plugin" = { 289 source = "${cfg.package}/libexec/netdata/plugins.d/freeipmi.plugin.org"; 290 capabilities = "cap_dac_override,cap_fowner+ep"; 291 owner = cfg.user; 292 group = cfg.group; 293 permissions = "u+rx,g+x,o-rwx"; 294 }; 295 }; 296 297 security.pam.loginLimits = [ 298 { domain = "netdata"; type = "soft"; item = "nofile"; value = "10000"; } 299 { domain = "netdata"; type = "hard"; item = "nofile"; value = "30000"; } 300 ]; 301 302 users.users = optionalAttrs (cfg.user == defaultUser) { 303 ${defaultUser} = { 304 group = defaultUser; 305 isSystemUser = true; 306 }; 307 }; 308 309 users.groups = optionalAttrs (cfg.group == defaultUser) { 310 ${defaultUser} = { }; 311 }; 312 313 }; 314}