{ pkgs, config, lib, ... }: let inherit (lib) types mkOption mkDefault; yaml = pkgs.formats.yaml {}; in { options = { services.prometheus = { extraExporters = mkOption { type = types.attrsOf (types.submodule { options = { port = mkOption { type = types.int; description = "The port on which this exporter listens."; }; listenAddress = mkOption { type = types.str; default = "127.0.0.1"; description = "Address to listen on."; }; serviceOpts = mkOption { type = types.attrs; description = "An attrset to be merged with the exporter's systemd service."; }; }; }); }; }; services.victoriametrics.scrapeConfigs = mkOption { type = types.attrsOf (types.submodule ({ name, self, ... }: { options = { job_name = mkOption { type = types.str; default = name; }; extraSettings = mkOption { type = types.anything; description = '' Other settings to set for this scrape config. ''; default = {}; }; targets = mkOption { type = types.listOf types.str; description = lib.mdDoc '' Addresses scrape targets for this config listen on. Shortcut for `static_configs = lib.singleton {targets = [];}` ''; default = []; }; static_configs = mkOption { default = []; type = types.listOf (types.submodule { options = { targets = mkOption { type = types.listOf types.str; description = lib.mdDoc '' The addresses scrape targets for this config listen on. Must in `listenAddress:port` format. ''; }; labels = mkOption { type = types.attrsOf types.str; description = lib.mdDoc '' Labels to apply to all targets defined for this static config. ''; default = {}; }; }; }); }; }; })); }; }; config = { systemd.services = lib.mkMerge [ (lib.mapAttrs' (name: exporter: lib.nameValuePair "prometheus-${name}-exporter" (lib.mkMerge [ { # Shamelessly copied from upstream because the upstream # module is an intractable mess wantedBy = ["multi-user.target"]; after = ["network.target"]; serviceConfig.Restart = mkDefault "always"; serviceConfig.PrivateTmp = mkDefault true; serviceConfig.WorkingDirectory = mkDefault /tmp; serviceConfig.DynamicUser = mkDefault true; # Hardening serviceConfig.CapabilityBoundingSet = mkDefault [""]; serviceConfig.DeviceAllow = [""]; serviceConfig.LockPersonality = true; serviceConfig.MemoryDenyWriteExecute = true; serviceConfig.NoNewPrivileges = true; serviceConfig.PrivateDevices = mkDefault true; serviceConfig.ProtectClock = mkDefault true; serviceConfig.ProtectControlGroups = true; serviceConfig.ProtectHome = true; serviceConfig.ProtectHostname = true; serviceConfig.ProtectKernelLogs = true; serviceConfig.ProtectKernelModules = true; serviceConfig.ProtectKernelTunables = true; serviceConfig.ProtectSystem = mkDefault "strict"; serviceConfig.RemoveIPC = true; serviceConfig.RestrictAddressFamilies = ["AF_INET" "AF_INET6"]; serviceConfig.RestrictNamespaces = true; serviceConfig.RestrictRealtime = true; serviceConfig.RestrictSUIDSGID = true; serviceConfig.SystemCallArchitectures = "native"; serviceConfig.UMask = "0077"; } exporter.serviceOpts ])) config.services.prometheus.extraExporters) { vmagent-scrape-exporters = let listenAddress = config.services.victoriametrics.listenAddress; vmAddr = (lib.optionalString (lib.hasPrefix ":" listenAddress) "127.0.0.1") + listenAddress; promscrape = yaml.generate "prometheus.yml" { scrape_configs = lib.mapAttrsToList (_: scrape: lib.recursiveUpdate { inherit (scrape) job_name; static_configs = scrape.static_configs ++ lib.optional (scrape.targets != []) {targets = scrape.targets;}; } scrape.extraSettings) config.services.victoriametrics.scrapeConfigs; }; in { enable = true; path = [pkgs.victoriametrics]; wantedBy = ["multi-user.target"]; after = ["network.target" "victoriametrics.service"]; serviceConfig = { ExecStart = [ (lib.concatStringsSep " " [ "${pkgs.victoriametrics}/bin/vmagent" "-promscrape.config=${promscrape}" "-remoteWrite.url=http://${vmAddr}/api/v1/write" "-remoteWrite.tmpDataPath=%t/vmagent" ]) ]; SupplementaryGroups = "metrics"; DynamicUser = true; RuntimeDirectory = "vmagent"; CapabilityBoundingSet = [""]; DeviceAllow = [""]; LockPersonality = true; MemoryDenyWriteExecute = true; NoNewPrivileges = true; PrivateDevices = true; ProtectClock = true; ProtectControlGroups = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectSystem = "strict"; RemoveIPC = true; RestrictAddressFamilies = ["AF_INET" "AF_INET6"]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; SystemCallArchitectures = "native"; UMask = "0077"; }; }; } ]; users.groups.metrics = {}; services.victoriametrics.scrapeConfigs = let allExporters = lib.mapAttrs (name: exporter: { inherit (exporter) listenAddress port; }) ((lib.filterAttrs (_: exporter: builtins.isAttrs exporter && exporter.enable) config.services.prometheus.exporters) // config.services.prometheus.extraExporters); in lib.mapAttrs (_: exporter: { targets = ["${exporter.listenAddress}:${toString exporter.port}"]; }) allExporters; }; }