at 21.11-pre 8.6 kB view raw
1{ config, pkgs, lib, options, ... }: 2 3let 4 inherit (lib) concatStrings foldl foldl' genAttrs literalExample 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 "collectd" 31 "dnsmasq" 32 "domain" 33 "dovecot" 34 "fritzbox" 35 "json" 36 "jitsi" 37 "kea" 38 "keylight" 39 "knot" 40 "lnd" 41 "mail" 42 "mikrotik" 43 "minio" 44 "modemmanager" 45 "nextcloud" 46 "nginx" 47 "nginxlog" 48 "node" 49 "openldap" 50 "openvpn" 51 "postfix" 52 "postgres" 53 "py-air-control" 54 "redis" 55 "rspamd" 56 "rtl_433" 57 "snmp" 58 "smokeping" 59 "sql" 60 "surfboard" 61 "systemd" 62 "tor" 63 "unbound" 64 "unifi" 65 "unifi-poller" 66 "varnish" 67 "wireguard" 68 "flow" 69 ] (name: 70 import (./. + "/exporters/${name}.nix") { inherit config lib pkgs options; } 71 ); 72 73 mkExporterOpts = ({ name, port }: { 74 enable = mkEnableOption "the prometheus ${name} exporter"; 75 port = mkOption { 76 type = types.port; 77 default = port; 78 description = '' 79 Port to listen on. 80 ''; 81 }; 82 listenAddress = mkOption { 83 type = types.str; 84 default = "0.0.0.0"; 85 description = '' 86 Address to listen on. 87 ''; 88 }; 89 extraFlags = mkOption { 90 type = types.listOf types.str; 91 default = []; 92 description = '' 93 Extra commandline options to pass to the ${name} exporter. 94 ''; 95 }; 96 openFirewall = mkOption { 97 type = types.bool; 98 default = false; 99 description = '' 100 Open port in firewall for incoming connections. 101 ''; 102 }; 103 firewallFilter = mkOption { 104 type = types.nullOr types.str; 105 default = null; 106 example = literalExample '' 107 "-i eth0 -p tcp -m tcp --dport ${toString port}" 108 ''; 109 description = '' 110 Specify a filter for iptables to use when 111 <option>services.prometheus.exporters.${name}.openFirewall</option> 112 is true. It is used as `ip46tables -I nixos-fw <option>firewallFilter</option> -j nixos-fw-accept`. 113 ''; 114 }; 115 user = mkOption { 116 type = types.str; 117 default = "${name}-exporter"; 118 description = '' 119 User name under which the ${name} exporter shall be run. 120 ''; 121 }; 122 group = mkOption { 123 type = types.str; 124 default = "${name}-exporter"; 125 description = '' 126 Group under which the ${name} exporter shall be run. 127 ''; 128 }; 129 }); 130 131 mkSubModule = { name, port, extraOpts, imports }: { 132 ${name} = mkOption { 133 type = types.submodule [{ 134 inherit imports; 135 options = (mkExporterOpts { 136 inherit name port; 137 } // extraOpts); 138 } ({ config, ... }: mkIf config.openFirewall { 139 firewallFilter = mkDefault "-p tcp -m tcp --dport ${toString config.port}"; 140 })]; 141 internal = true; 142 default = {}; 143 }; 144 }; 145 146 mkSubModules = (foldl' (a: b: a//b) {} 147 (mapAttrsToList (name: opts: mkSubModule { 148 inherit name; 149 inherit (opts) port; 150 extraOpts = opts.extraOpts or {}; 151 imports = opts.imports or []; 152 }) exporterOpts) 153 ); 154 155 mkExporterConf = { name, conf, serviceOpts }: 156 let 157 enableDynamicUser = serviceOpts.serviceConfig.DynamicUser or true; 158 in 159 mkIf conf.enable { 160 warnings = conf.warnings or []; 161 users.users."${name}-exporter" = (mkIf (conf.user == "${name}-exporter" && !enableDynamicUser) { 162 description = "Prometheus ${name} exporter service user"; 163 isSystemUser = true; 164 inherit (conf) group; 165 }); 166 users.groups = (mkIf (conf.group == "${name}-exporter" && !enableDynamicUser) { 167 "${name}-exporter" = {}; 168 }); 169 networking.firewall.extraCommands = mkIf conf.openFirewall (concatStrings [ 170 "ip46tables -A nixos-fw ${conf.firewallFilter} " 171 "-m comment --comment ${name}-exporter -j nixos-fw-accept" 172 ]); 173 systemd.services."prometheus-${name}-exporter" = mkMerge ([{ 174 wantedBy = [ "multi-user.target" ]; 175 after = [ "network.target" ]; 176 serviceConfig.Restart = mkDefault "always"; 177 serviceConfig.PrivateTmp = mkDefault true; 178 serviceConfig.WorkingDirectory = mkDefault /tmp; 179 serviceConfig.DynamicUser = mkDefault enableDynamicUser; 180 serviceConfig.User = conf.user; 181 serviceConfig.Group = conf.group; 182 } serviceOpts ]); 183 }; 184in 185{ 186 187 imports = (lib.forEach [ "blackboxExporter" "collectdExporter" "fritzboxExporter" 188 "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" 189 "snmpExporter" "unifiExporter" "varnishExporter" ] 190 (opt: lib.mkRemovedOptionModule [ "services" "prometheus" "${opt}" ] '' 191 The prometheus exporters are now configured using `services.prometheus.exporters'. 192 See the 18.03 release notes for more information. 193 '' )); 194 195 options.services.prometheus.exporters = mkOption { 196 type = types.submodule { 197 options = (mkSubModules); 198 }; 199 description = "Prometheus exporter configuration"; 200 default = {}; 201 example = literalExample '' 202 { 203 node = { 204 enable = true; 205 enabledCollectors = [ "systemd" ]; 206 }; 207 varnish.enable = true; 208 } 209 ''; 210 }; 211 212 config = mkMerge ([{ 213 assertions = [ { 214 assertion = cfg.snmp.enable -> ( 215 (cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null) 216 ); 217 message = '' 218 Please ensure you have either `services.prometheus.exporters.snmp.configuration' 219 or `services.prometheus.exporters.snmp.configurationPath' set! 220 ''; 221 } { 222 assertion = cfg.mikrotik.enable -> ( 223 (cfg.mikrotik.configFile == null) != (cfg.mikrotik.configuration == null) 224 ); 225 message = '' 226 Please specify either `services.prometheus.exporters.mikrotik.configuration' 227 or `services.prometheus.exporters.mikrotik.configFile'. 228 ''; 229 } { 230 assertion = cfg.mail.enable -> ( 231 (cfg.mail.configFile == null) != (cfg.mail.configuration == null) 232 ); 233 message = '' 234 Please specify either 'services.prometheus.exporters.mail.configuration' 235 or 'services.prometheus.exporters.mail.configFile'. 236 ''; 237 } { 238 assertion = cfg.sql.enable -> ( 239 (cfg.sql.configFile == null) != (cfg.sql.configuration == null) 240 ); 241 message = '' 242 Please specify either 'services.prometheus.exporters.sql.configuration' or 243 'services.prometheus.exporters.sql.configFile' 244 ''; 245 } ] ++ (flip map (attrNames cfg) (exporter: { 246 assertion = cfg.${exporter}.firewallFilter != null -> cfg.${exporter}.openFirewall; 247 message = '' 248 The `firewallFilter'-option of exporter ${exporter} doesn't have any effect unless 249 `openFirewall' is set to `true'! 250 ''; 251 })); 252 }] ++ [(mkIf config.services.minio.enable { 253 services.prometheus.exporters.minio.minioAddress = mkDefault "http://localhost:9000"; 254 services.prometheus.exporters.minio.minioAccessKey = mkDefault config.services.minio.accessKey; 255 services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey; 256 })] ++ [(mkIf config.services.prometheus.exporters.rtl_433.enable { 257 hardware.rtl-sdr.enable = mkDefault true; 258 })] ++ [(mkIf config.services.postfix.enable { 259 services.prometheus.exporters.postfix.group = mkDefault config.services.postfix.setgidGroup; 260 })] ++ (mapAttrsToList (name: conf: 261 mkExporterConf { 262 inherit name; 263 inherit (conf) serviceOpts; 264 conf = cfg.${name}; 265 }) exporterOpts) 266 ); 267 268 meta = { 269 doc = ./exporters.xml; 270 maintainers = [ maintainers.willibutz ]; 271 }; 272}