at 22.05-pre 9.8 kB view raw
1{ config, pkgs, lib, options, ... }: 2 3let 4 inherit (lib) concatStrings foldl foldl' genAttrs literalExpression maintainers 5 mapAttrsToList mkDefault mkEnableOption mkIf mkMerge mkOption 6 optional types mkOptionDefault flip attrNames; 7 8 cfg = config.services.prometheus.exporters; 9 10 # each attribute in `exporterOpts` is expected to have specified: 11 # - port (types.int): port on which the exporter listens 12 # - serviceOpts (types.attrs): config that is merged with the 13 # default definition of the exporter's 14 # systemd service 15 # - extraOpts (types.attrs): extra configuration options to 16 # configure the exporter with, which 17 # are appended to the default options 18 # 19 # Note that `extraOpts` is optional, but a script for the exporter's 20 # systemd service must be provided by specifying either 21 # `serviceOpts.script` or `serviceOpts.serviceConfig.ExecStart` 22 23 exporterOpts = genAttrs [ 24 "apcupsd" 25 "artifactory" 26 "bind" 27 "bird" 28 "bitcoin" 29 "blackbox" 30 "buildkite-agent" 31 "collectd" 32 "dnsmasq" 33 "domain" 34 "dovecot" 35 "fastly" 36 "fritzbox" 37 "influxdb" 38 "json" 39 "jitsi" 40 "kea" 41 "keylight" 42 "knot" 43 "lnd" 44 "mail" 45 "mikrotik" 46 "minio" 47 "modemmanager" 48 "nextcloud" 49 "nginx" 50 "nginxlog" 51 "node" 52 "openldap" 53 "openvpn" 54 "pihole" 55 "postfix" 56 "postgres" 57 "process" 58 "py-air-control" 59 "redis" 60 "rspamd" 61 "rtl_433" 62 "script" 63 "snmp" 64 "smokeping" 65 "sql" 66 "surfboard" 67 "systemd" 68 "tor" 69 "unbound" 70 "unifi" 71 "unifi-poller" 72 "varnish" 73 "wireguard" 74 "flow" 75 ] (name: 76 import (./. + "/exporters/${name}.nix") { inherit config lib pkgs options; } 77 ); 78 79 mkExporterOpts = ({ name, port }: { 80 enable = mkEnableOption "the prometheus ${name} exporter"; 81 port = mkOption { 82 type = types.port; 83 default = port; 84 description = '' 85 Port to listen on. 86 ''; 87 }; 88 listenAddress = mkOption { 89 type = types.str; 90 default = "0.0.0.0"; 91 description = '' 92 Address to listen on. 93 ''; 94 }; 95 extraFlags = mkOption { 96 type = types.listOf types.str; 97 default = []; 98 description = '' 99 Extra commandline options to pass to the ${name} exporter. 100 ''; 101 }; 102 openFirewall = mkOption { 103 type = types.bool; 104 default = false; 105 description = '' 106 Open port in firewall for incoming connections. 107 ''; 108 }; 109 firewallFilter = mkOption { 110 type = types.nullOr types.str; 111 default = null; 112 example = literalExpression '' 113 "-i eth0 -p tcp -m tcp --dport ${toString port}" 114 ''; 115 description = '' 116 Specify a filter for iptables to use when 117 <option>services.prometheus.exporters.${name}.openFirewall</option> 118 is true. It is used as `ip46tables -I nixos-fw <option>firewallFilter</option> -j nixos-fw-accept`. 119 ''; 120 }; 121 user = mkOption { 122 type = types.str; 123 default = "${name}-exporter"; 124 description = '' 125 User name under which the ${name} exporter shall be run. 126 ''; 127 }; 128 group = mkOption { 129 type = types.str; 130 default = "${name}-exporter"; 131 description = '' 132 Group under which the ${name} exporter shall be run. 133 ''; 134 }; 135 }); 136 137 mkSubModule = { name, port, extraOpts, imports }: { 138 ${name} = mkOption { 139 type = types.submodule [{ 140 inherit imports; 141 options = (mkExporterOpts { 142 inherit name port; 143 } // extraOpts); 144 } ({ config, ... }: mkIf config.openFirewall { 145 firewallFilter = mkDefault "-p tcp -m tcp --dport ${toString config.port}"; 146 })]; 147 internal = true; 148 default = {}; 149 }; 150 }; 151 152 mkSubModules = (foldl' (a: b: a//b) {} 153 (mapAttrsToList (name: opts: mkSubModule { 154 inherit name; 155 inherit (opts) port; 156 extraOpts = opts.extraOpts or {}; 157 imports = opts.imports or []; 158 }) exporterOpts) 159 ); 160 161 mkExporterConf = { name, conf, serviceOpts }: 162 let 163 enableDynamicUser = serviceOpts.serviceConfig.DynamicUser or true; 164 in 165 mkIf conf.enable { 166 warnings = conf.warnings or []; 167 users.users."${name}-exporter" = (mkIf (conf.user == "${name}-exporter" && !enableDynamicUser) { 168 description = "Prometheus ${name} exporter service user"; 169 isSystemUser = true; 170 inherit (conf) group; 171 }); 172 users.groups = (mkIf (conf.group == "${name}-exporter" && !enableDynamicUser) { 173 "${name}-exporter" = {}; 174 }); 175 networking.firewall.extraCommands = mkIf conf.openFirewall (concatStrings [ 176 "ip46tables -A nixos-fw ${conf.firewallFilter} " 177 "-m comment --comment ${name}-exporter -j nixos-fw-accept" 178 ]); 179 systemd.services."prometheus-${name}-exporter" = mkMerge ([{ 180 wantedBy = [ "multi-user.target" ]; 181 after = [ "network.target" ]; 182 serviceConfig.Restart = mkDefault "always"; 183 serviceConfig.PrivateTmp = mkDefault true; 184 serviceConfig.WorkingDirectory = mkDefault /tmp; 185 serviceConfig.DynamicUser = mkDefault enableDynamicUser; 186 serviceConfig.User = mkDefault conf.user; 187 serviceConfig.Group = conf.group; 188 # Hardening 189 serviceConfig.CapabilityBoundingSet = mkDefault [ "" ]; 190 serviceConfig.DeviceAllow = [ "" ]; 191 serviceConfig.LockPersonality = true; 192 serviceConfig.MemoryDenyWriteExecute = true; 193 serviceConfig.NoNewPrivileges = true; 194 serviceConfig.PrivateDevices = true; 195 serviceConfig.ProtectClock = mkDefault true; 196 serviceConfig.ProtectControlGroups = true; 197 serviceConfig.ProtectHome = true; 198 serviceConfig.ProtectHostname = true; 199 serviceConfig.ProtectKernelLogs = true; 200 serviceConfig.ProtectKernelModules = true; 201 serviceConfig.ProtectKernelTunables = true; 202 serviceConfig.ProtectSystem = mkDefault "strict"; 203 serviceConfig.RemoveIPC = true; 204 serviceConfig.RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; 205 serviceConfig.RestrictNamespaces = true; 206 serviceConfig.RestrictRealtime = true; 207 serviceConfig.RestrictSUIDSGID = true; 208 serviceConfig.SystemCallArchitectures = "native"; 209 serviceConfig.UMask = "0077"; 210 } serviceOpts ]); 211 }; 212in 213{ 214 215 imports = (lib.forEach [ "blackboxExporter" "collectdExporter" "fritzboxExporter" 216 "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" 217 "snmpExporter" "unifiExporter" "varnishExporter" ] 218 (opt: lib.mkRemovedOptionModule [ "services" "prometheus" "${opt}" ] '' 219 The prometheus exporters are now configured using `services.prometheus.exporters'. 220 See the 18.03 release notes for more information. 221 '' )); 222 223 options.services.prometheus.exporters = mkOption { 224 type = types.submodule { 225 options = (mkSubModules); 226 }; 227 description = "Prometheus exporter configuration"; 228 default = {}; 229 example = literalExpression '' 230 { 231 node = { 232 enable = true; 233 enabledCollectors = [ "systemd" ]; 234 }; 235 varnish.enable = true; 236 } 237 ''; 238 }; 239 240 config = mkMerge ([{ 241 assertions = [ { 242 assertion = cfg.snmp.enable -> ( 243 (cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null) 244 ); 245 message = '' 246 Please ensure you have either `services.prometheus.exporters.snmp.configuration' 247 or `services.prometheus.exporters.snmp.configurationPath' set! 248 ''; 249 } { 250 assertion = cfg.mikrotik.enable -> ( 251 (cfg.mikrotik.configFile == null) != (cfg.mikrotik.configuration == null) 252 ); 253 message = '' 254 Please specify either `services.prometheus.exporters.mikrotik.configuration' 255 or `services.prometheus.exporters.mikrotik.configFile'. 256 ''; 257 } { 258 assertion = cfg.mail.enable -> ( 259 (cfg.mail.configFile == null) != (cfg.mail.configuration == null) 260 ); 261 message = '' 262 Please specify either 'services.prometheus.exporters.mail.configuration' 263 or 'services.prometheus.exporters.mail.configFile'. 264 ''; 265 } { 266 assertion = cfg.sql.enable -> ( 267 (cfg.sql.configFile == null) != (cfg.sql.configuration == null) 268 ); 269 message = '' 270 Please specify either 'services.prometheus.exporters.sql.configuration' or 271 'services.prometheus.exporters.sql.configFile' 272 ''; 273 } ] ++ (flip map (attrNames cfg) (exporter: { 274 assertion = cfg.${exporter}.firewallFilter != null -> cfg.${exporter}.openFirewall; 275 message = '' 276 The `firewallFilter'-option of exporter ${exporter} doesn't have any effect unless 277 `openFirewall' is set to `true'! 278 ''; 279 })); 280 }] ++ [(mkIf config.services.minio.enable { 281 services.prometheus.exporters.minio.minioAddress = mkDefault "http://localhost:9000"; 282 services.prometheus.exporters.minio.minioAccessKey = mkDefault config.services.minio.accessKey; 283 services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey; 284 })] ++ [(mkIf config.services.prometheus.exporters.rtl_433.enable { 285 hardware.rtl-sdr.enable = mkDefault true; 286 })] ++ [(mkIf config.services.postfix.enable { 287 services.prometheus.exporters.postfix.group = mkDefault config.services.postfix.setgidGroup; 288 })] ++ (mapAttrsToList (name: conf: 289 mkExporterConf { 290 inherit name; 291 inherit (conf) serviceOpts; 292 conf = cfg.${name}; 293 }) exporterOpts) 294 ); 295 296 meta = { 297 doc = ./exporters.xml; 298 maintainers = [ maintainers.willibutz ]; 299 }; 300}