diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services/monitoring/prometheus/exporters')
71 files changed, 4314 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/apcupsd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/apcupsd.nix new file mode 100644 index 000000000000..a8a9f84ea8ea --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/apcupsd.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.apcupsd; +in +{ + port = 9162; + extraOpts = { + apcupsdAddress = mkOption { + type = types.str; + default = ":3551"; + description = lib.mdDoc '' + Address of the apcupsd Network Information Server (NIS). + ''; + }; + + apcupsdNetwork = mkOption { + type = types.enum ["tcp" "tcp4" "tcp6"]; + default = "tcp"; + description = lib.mdDoc '' + Network of the apcupsd Network Information Server (NIS): one of "tcp", "tcp4", or "tcp6". + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-apcupsd-exporter}/bin/apcupsd_exporter \ + -telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \ + -apcupsd.addr ${cfg.apcupsdAddress} \ + -apcupsd.network ${cfg.apcupsdNetwork} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/artifactory.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/artifactory.nix new file mode 100644 index 000000000000..bc67fe59b3b8 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/artifactory.nix @@ -0,0 +1,59 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.artifactory; +in +{ + port = 9531; + extraOpts = { + scrapeUri = mkOption { + type = types.str; + default = "http://localhost:8081/artifactory"; + description = lib.mdDoc '' + URI on which to scrape JFrog Artifactory. + ''; + }; + + artiUsername = mkOption { + type = types.str; + description = lib.mdDoc '' + Username for authentication against JFrog Artifactory API. + ''; + }; + + artiPassword = mkOption { + type = types.str; + default = ""; + description = lib.mdDoc '' + Password for authentication against JFrog Artifactory API. + One of the password or access token needs to be set. + ''; + }; + + artiAccessToken = mkOption { + type = types.str; + default = ""; + description = lib.mdDoc '' + Access token for authentication against JFrog Artifactory API. + One of the password or access token needs to be set. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-artifactory-exporter}/bin/artifactory_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --artifactory.scrape-uri ${cfg.scrapeUri} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + Environment = [ + "ARTI_USERNAME=${cfg.artiUsername}" + "ARTI_PASSWORD=${cfg.artiPassword}" + "ARTI_ACCESS_TOKEN=${cfg.artiAccessToken}" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix new file mode 100644 index 000000000000..bd2003f06504 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix @@ -0,0 +1,54 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.bind; +in +{ + port = 9119; + extraOpts = { + bindURI = mkOption { + type = types.str; + default = "http://localhost:8053/"; + description = lib.mdDoc '' + HTTP XML API address of an Bind server. + ''; + }; + bindTimeout = mkOption { + type = types.str; + default = "10s"; + description = lib.mdDoc '' + Timeout for trying to get stats from Bind. + ''; + }; + bindVersion = mkOption { + type = types.enum [ "xml.v2" "xml.v3" "auto" ]; + default = "auto"; + description = lib.mdDoc '' + BIND statistics version. Can be detected automatically. + ''; + }; + bindGroups = mkOption { + type = types.listOf (types.enum [ "server" "view" "tasks" ]); + default = [ "server" "view" ]; + description = lib.mdDoc '' + List of statistics to collect. Available: [server, view, tasks] + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-bind-exporter}/bin/bind_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --bind.pid-file /var/run/named/named.pid \ + --bind.timeout ${toString cfg.bindTimeout} \ + --bind.stats-url ${cfg.bindURI} \ + --bind.stats-version ${cfg.bindVersion} \ + --bind.stats-groups ${concatStringsSep "," cfg.bindGroups} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix new file mode 100644 index 000000000000..5f6c36f4c567 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bird.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.bird; +in +{ + port = 9324; + extraOpts = { + birdVersion = mkOption { + type = types.enum [ 1 2 ]; + default = 2; + description = lib.mdDoc '' + Specifies whether BIRD1 or BIRD2 is in use. + ''; + }; + birdSocket = mkOption { + type = types.path; + default = "/run/bird/bird.ctl"; + description = lib.mdDoc '' + Path to BIRD2 (or BIRD1 v4) socket. + ''; + }; + newMetricFormat = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Enable the new more-generic metric format. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + SupplementaryGroups = singleton (if cfg.birdVersion == 1 then "bird" else "bird2"); + ExecStart = '' + ${pkgs.prometheus-bird-exporter}/bin/bird_exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -bird.socket ${cfg.birdSocket} \ + -bird.v2=${if cfg.birdVersion == 2 then "true" else "false"} \ + -format.new=${if cfg.newMetricFormat then "true" else "false"} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix new file mode 100644 index 000000000000..330d54126448 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bitcoin.nix @@ -0,0 +1,82 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.bitcoin; +in +{ + port = 9332; + extraOpts = { + rpcUser = mkOption { + type = types.str; + default = "bitcoinrpc"; + description = lib.mdDoc '' + RPC user name. + ''; + }; + + rpcPasswordFile = mkOption { + type = types.path; + description = lib.mdDoc '' + File containing RPC password. + ''; + }; + + rpcScheme = mkOption { + type = types.enum [ "http" "https" ]; + default = "http"; + description = lib.mdDoc '' + Whether to connect to bitcoind over http or https. + ''; + }; + + rpcHost = mkOption { + type = types.str; + default = "localhost"; + description = lib.mdDoc '' + RPC host. + ''; + }; + + rpcPort = mkOption { + type = types.port; + default = 8332; + description = lib.mdDoc '' + RPC port number. + ''; + }; + + refreshSeconds = mkOption { + type = types.ints.unsigned; + default = 300; + description = lib.mdDoc '' + How often to ask bitcoind for metrics. + ''; + }; + + extraEnv = mkOption { + type = types.attrsOf types.str; + default = {}; + description = lib.mdDoc '' + Extra environment variables for the exporter. + ''; + }; + }; + serviceOpts = { + script = '' + export BITCOIN_RPC_PASSWORD=$(cat ${cfg.rpcPasswordFile}) + exec ${pkgs.prometheus-bitcoin-exporter}/bin/bitcoind-monitor.py + ''; + + environment = { + BITCOIN_RPC_USER = cfg.rpcUser; + BITCOIN_RPC_SCHEME = cfg.rpcScheme; + BITCOIN_RPC_HOST = cfg.rpcHost; + BITCOIN_RPC_PORT = toString cfg.rpcPort; + METRICS_ADDR = cfg.listenAddress; + METRICS_PORT = toString cfg.port; + REFRESH_SECONDS = toString cfg.refreshSeconds; + } // cfg.extraEnv; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix new file mode 100644 index 000000000000..ce2c391de523 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix @@ -0,0 +1,70 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + logPrefix = "services.prometheus.exporter.blackbox"; + cfg = config.services.prometheus.exporters.blackbox; + + # This ensures that we can deal with string paths, path types and + # store-path strings with context. + coerceConfigFile = file: + if (builtins.isPath file) || (lib.isStorePath file) then + file + else + (lib.warn '' + ${logPrefix}: configuration file "${file}" is being copied to the nix-store. + If you would like to avoid that, please set enableConfigCheck to false. + '' /. + file); + checkConfigLocation = file: + if lib.hasPrefix "/tmp/" file then + throw + "${logPrefix}: configuration file must not reside within /tmp - it won't be visible to the systemd service." + else + file; + checkConfig = file: + pkgs.runCommand "checked-blackbox-exporter.conf" { + preferLocalBuild = true; + nativeBuildInputs = [ pkgs.buildPackages.prometheus-blackbox-exporter ]; + } '' + ln -s ${coerceConfigFile file} $out + blackbox_exporter --config.check --config.file $out + ''; +in { + port = 9115; + extraOpts = { + configFile = mkOption { + type = types.path; + description = lib.mdDoc '' + Path to configuration file. + ''; + }; + enableConfigCheck = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Whether to run a correctness check for the configuration file. This depends + on the configuration file residing in the nix-store. Paths passed as string will + be copied to the store. + ''; + }; + }; + + serviceOpts = let + adjustedConfigFile = if cfg.enableConfigCheck then + checkConfig cfg.configFile + else + checkConfigLocation cfg.configFile; + in { + serviceConfig = { + AmbientCapabilities = [ "CAP_NET_RAW" ]; # for ping probes + ExecStart = '' + ${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --config.file ${escapeShellArg adjustedConfigFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/buildkite-agent.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/buildkite-agent.nix new file mode 100644 index 000000000000..0515b72b13f9 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/buildkite-agent.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.buildkite-agent; +in +{ + port = 9876; + extraOpts = { + tokenPath = mkOption { + type = types.nullOr types.path; + apply = final: if final == null then null else toString final; + description = lib.mdDoc '' + The token from your Buildkite "Agents" page. + + A run-time path to the token file, which is supposed to be provisioned + outside of Nix store. + ''; + }; + interval = mkOption { + type = types.str; + default = "30s"; + example = "1min"; + description = lib.mdDoc '' + How often to update metrics. + ''; + }; + endpoint = mkOption { + type = types.str; + default = "https://agent.buildkite.com/v3"; + description = lib.mdDoc '' + The Buildkite Agent API endpoint. + ''; + }; + queues = mkOption { + type = with types; nullOr (listOf str); + default = null; + example = literalExpression ''[ "my-queue1" "my-queue2" ]''; + description = lib.mdDoc '' + Which specific queues to process. + ''; + }; + }; + serviceOpts = { + script = + let + queues = concatStringsSep " " (map (q: "-queue ${q}") cfg.queues); + in + '' + export BUILDKITE_AGENT_TOKEN="$(cat ${toString cfg.tokenPath})" + exec ${pkgs.buildkite-agent-metrics}/bin/buildkite-agent-metrics \ + -backend prometheus \ + -interval ${cfg.interval} \ + -endpoint ${cfg.endpoint} \ + ${optionalString (cfg.queues != null) queues} \ + -prometheus-addr "${cfg.listenAddress}:${toString cfg.port}" ${concatStringsSep " " cfg.extraFlags} + ''; + serviceConfig = { + DynamicUser = false; + RuntimeDirectory = "buildkite-agent-metrics"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix new file mode 100644 index 000000000000..f67596f05a3a --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix @@ -0,0 +1,77 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.collectd; +in +{ + port = 9103; + extraOpts = { + collectdBinary = { + enable = mkEnableOption (lib.mdDoc "collectd binary protocol receiver"); + + authFile = mkOption { + default = null; + type = types.nullOr types.path; + description = lib.mdDoc "File mapping user names to pre-shared keys (passwords)."; + }; + + port = mkOption { + type = types.port; + default = 25826; + description = lib.mdDoc "Network address on which to accept collectd binary network packets."; + }; + + listenAddress = mkOption { + type = types.str; + default = "0.0.0.0"; + description = lib.mdDoc '' + Address to listen on for binary network packets. + ''; + }; + + securityLevel = mkOption { + type = types.enum ["None" "Sign" "Encrypt"]; + default = "None"; + description = lib.mdDoc '' + Minimum required security level for accepted packets. + ''; + }; + }; + + logFormat = mkOption { + type = types.enum [ "logfmt" "json" ]; + default = "logfmt"; + example = "json"; + description = lib.mdDoc '' + Set the log format. + ''; + }; + + logLevel = mkOption { + type = types.enum ["debug" "info" "warn" "error" "fatal"]; + default = "info"; + description = lib.mdDoc '' + Only log messages with the given severity or above. + ''; + }; + }; + serviceOpts = let + collectSettingsArgs = optionalString (cfg.collectdBinary.enable) '' + --collectd.listen-address ${cfg.collectdBinary.listenAddress}:${toString cfg.collectdBinary.port} \ + --collectd.security-level ${cfg.collectdBinary.securityLevel} \ + ''; + in { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \ + --log.format ${escapeShellArg cfg.logFormat} \ + --log.level ${cfg.logLevel} \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${collectSettingsArgs} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix new file mode 100644 index 000000000000..437cece588a7 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix @@ -0,0 +1,117 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.dmarc; + + json = builtins.toJSON { + inherit (cfg) folders port; + listen_addr = cfg.listenAddress; + storage_path = "$STATE_DIRECTORY"; + imap = (builtins.removeAttrs cfg.imap [ "passwordFile" ]) // { password = "$IMAP_PASSWORD"; use_ssl = true; }; + poll_interval_seconds = cfg.pollIntervalSeconds; + deduplication_max_seconds = cfg.deduplicationMaxSeconds; + logging = { + version = 1; + disable_existing_loggers = false; + }; + }; +in { + port = 9797; + extraOpts = { + imap = { + host = mkOption { + type = types.str; + default = "localhost"; + description = lib.mdDoc '' + Hostname of IMAP server to connect to. + ''; + }; + port = mkOption { + type = types.port; + default = 993; + description = lib.mdDoc '' + Port of the IMAP server to connect to. + ''; + }; + username = mkOption { + type = types.str; + example = "postmaster@example.org"; + description = lib.mdDoc '' + Login username for the IMAP connection. + ''; + }; + passwordFile = mkOption { + type = types.str; + example = "/run/secrets/dovecot_pw"; + description = lib.mdDoc '' + File containing the login password for the IMAP connection. + ''; + }; + }; + folders = { + inbox = mkOption { + type = types.str; + default = "INBOX"; + description = lib.mdDoc '' + IMAP mailbox that is checked for incoming DMARC aggregate reports + ''; + }; + done = mkOption { + type = types.str; + default = "Archive"; + description = lib.mdDoc '' + IMAP mailbox that successfully processed reports are moved to. + ''; + }; + error = mkOption { + type = types.str; + default = "Invalid"; + description = lib.mdDoc '' + IMAP mailbox that emails are moved to that could not be processed. + ''; + }; + }; + pollIntervalSeconds = mkOption { + type = types.ints.unsigned; + default = 60; + description = lib.mdDoc '' + How often to poll the IMAP server in seconds. + ''; + }; + deduplicationMaxSeconds = mkOption { + type = types.ints.unsigned; + default = 604800; + defaultText = "7 days (in seconds)"; + description = lib.mdDoc '' + How long individual report IDs will be remembered to avoid + counting double delivered reports twice. + ''; + }; + debug = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Whether to declare enable `--debug`. + ''; + }; + }; + serviceOpts = { + path = with pkgs; [ envsubst coreutils ]; + serviceConfig = { + StateDirectory = "prometheus-dmarc-exporter"; + WorkingDirectory = "/var/lib/prometheus-dmarc-exporter"; + ExecStart = "${pkgs.writeShellScript "setup-cfg" '' + export IMAP_PASSWORD="$(<${cfg.imap.passwordFile})" + envsubst \ + -i ${pkgs.writeText "dmarc-exporter.json.template" json} \ + -o ''${STATE_DIRECTORY}/dmarc-exporter.json + + exec ${pkgs.dmarc-metrics-exporter}/bin/dmarc-metrics-exporter \ + --configuration /var/lib/prometheus-dmarc-exporter/dmarc-exporter.json \ + ${optionalString cfg.debug "--debug"} + ''}"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix new file mode 100644 index 000000000000..ece42a34cb06 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.dnsmasq; +in +{ + port = 9153; + extraOpts = { + dnsmasqListenAddress = mkOption { + type = types.str; + default = "localhost:53"; + description = lib.mdDoc '' + Address on which dnsmasq listens. + ''; + }; + leasesPath = mkOption { + type = types.path; + default = "/var/lib/misc/dnsmasq.leases"; + example = "/var/lib/dnsmasq/dnsmasq.leases"; + description = lib.mdDoc '' + Path to the `dnsmasq.leases` file. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-dnsmasq-exporter}/bin/dnsmasq_exporter \ + --listen ${cfg.listenAddress}:${toString cfg.port} \ + --dnsmasq ${cfg.dnsmasqListenAddress} \ + --leases_path ${escapeShellArg cfg.leasesPath} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/domain.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/domain.nix new file mode 100644 index 000000000000..61e2fc80afde --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/domain.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.domain; +in +{ + port = 9222; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-domain-exporter}/bin/domain_exporter \ + --bind ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix new file mode 100644 index 000000000000..6fb438353a4c --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix @@ -0,0 +1,92 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.dovecot; +in +{ + port = 9166; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + socketPath = mkOption { + type = types.path; + default = "/var/run/dovecot/stats"; + example = "/var/run/dovecot2/old-stats"; + description = lib.mdDoc '' + Path under which the stats socket is placed. + The user/group under which the exporter runs, + should be able to access the socket in order + to scrape the metrics successfully. + + Please keep in mind that the stats module has changed in + [Dovecot 2.3+](https://wiki2.dovecot.org/Upgrading/2.3) which + is not [compatible with this exporter](https://github.com/kumina/dovecot_exporter/issues/8). + + The following extra config has to be passed to Dovecot to ensure that recent versions + work with this exporter: + ``` + { + services.prometheus.exporters.dovecot.enable = true; + services.prometheus.exporters.dovecot.socketPath = "/var/run/dovecot2/old-stats"; + services.dovecot2.mailPlugins.globally.enable = [ "old_stats" ]; + services.dovecot2.extraConfig = ''' + service old-stats { + unix_listener old-stats { + user = dovecot-exporter + group = dovecot-exporter + mode = 0660 + } + fifo_listener old-stats-mail { + mode = 0660 + user = dovecot + group = dovecot + } + fifo_listener old-stats-user { + mode = 0660 + user = dovecot + group = dovecot + } + } + plugin { + old_stats_refresh = 30 secs + old_stats_track_cmds = yes + } + '''; + } + ``` + ''; + }; + scopes = mkOption { + type = types.listOf types.str; + default = [ "user" ]; + example = [ "user" "global" ]; + description = lib.mdDoc '' + Stats scopes to query. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + ExecStart = '' + ${pkgs.prometheus-dovecot-exporter}/bin/dovecot_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + --dovecot.socket-path ${escapeShellArg cfg.socketPath} \ + --dovecot.scopes ${concatStringsSep "," cfg.scopes} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/exportarr.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/exportarr.nix new file mode 100644 index 000000000000..8511abbee1bd --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/exportarr.nix @@ -0,0 +1,55 @@ +{ config, lib, pkgs, options, type }: + +let + cfg = config.services.prometheus.exporters."exportarr-${type}"; + exportarrEnvironment = ( + lib.mapAttrs (_: toString) cfg.environment + ) // { + PORT = toString cfg.port; + URL = cfg.url; + API_KEY_FILE = lib.mkIf (cfg.apiKeyFile != null) "%d/api-key"; + }; +in +{ + port = 9708; + extraOpts = { + url = lib.mkOption { + type = lib.types.str; + default = "http://127.0.0.1"; + description = lib.mdDoc '' + The full URL to Sonarr, Radarr, or Lidarr. + ''; + }; + + apiKeyFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = lib.mdDoc '' + File containing the api-key. + ''; + }; + + package = lib.mkPackageOption pkgs "exportarr" { }; + + environment = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + description = lib.mdDoc '' + See [the configuration guide](https://github.com/onedr0p/exportarr#configuration) for available options. + ''; + example = { + PROWLARR__BACKFILL = true; + }; + }; + }; + serviceOpts = { + serviceConfig = { + LoadCredential = lib.optionalString (cfg.apiKeyFile != null) "api-key:${cfg.apiKeyFile}"; + ExecStart = ''${cfg.package}/bin/exportarr ${type} "$@"''; + ProcSubset = "pid"; + ProtectProc = "invisible"; + SystemCallFilter = ["@system-service" "~@privileged"]; + }; + environment = exportarrEnvironment; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix new file mode 100644 index 000000000000..36409caccf2e --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fastly.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, options }: + +with lib; + +let cfg = config.services.prometheus.exporters.fastly; +in +{ + port = 9118; + extraOpts = { + debug = mkEnableOption (lib.mdDoc "Debug logging mode for fastly-exporter"); + + configFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to a fastly-exporter configuration file. + Example one can be generated with `fastly-exporter --config-file-example`. + ''; + example = "./fastly-exporter-config.txt"; + }; + + tokenPath = mkOption { + type = types.nullOr types.path; + apply = final: if final == null then null else toString final; + description = lib.mdDoc '' + A run-time path to the token file, which is supposed to be provisioned + outside of Nix store. + ''; + }; + }; + serviceOpts = { + script = '' + ${optionalString (cfg.tokenPath != null) + "export FASTLY_API_TOKEN=$(cat ${toString cfg.tokenPath})"} + ${pkgs.prometheus-fastly-exporter}/bin/fastly-exporter \ + -listen http://${cfg.listenAddress}:${toString cfg.port} + ${optionalString cfg.debug "-debug true"} \ + ${optionalString (cfg.configFile != null) "-config-file ${cfg.configFile}"} + ''; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/flow.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/flow.nix new file mode 100644 index 000000000000..81099aaf1704 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/flow.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.flow; +in { + port = 9590; + extraOpts = { + brokers = mkOption { + type = types.listOf types.str; + example = literalExpression ''[ "kafka.example.org:19092" ]''; + description = lib.mdDoc "List of Kafka brokers to connect to."; + }; + + asn = mkOption { + type = types.ints.positive; + example = 65542; + description = lib.mdDoc "The ASN being monitored."; + }; + + partitions = mkOption { + type = types.listOf types.int; + default = []; + description = lib.mdDoc '' + The number of the partitions to consume, none means all. + ''; + }; + + topic = mkOption { + type = types.str; + example = "pmacct.acct"; + description = lib.mdDoc "The Kafka topic to consume from."; + }; + }; + + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-flow-exporter}/bin/flow-exporter \ + -asn ${toString cfg.asn} \ + -topic ${cfg.topic} \ + -brokers ${concatStringsSep "," cfg.brokers} \ + ${optionalString (cfg.partitions != []) "-partitions ${concatStringsSep "," cfg.partitions}"} \ + -addr ${cfg.listenAddress}:${toString cfg.port} ${concatStringsSep " " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix new file mode 100644 index 000000000000..dc53d21406ff --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.fritzbox; +in +{ + port = 9133; + extraOpts = { + gatewayAddress = mkOption { + type = types.str; + default = "fritz.box"; + description = lib.mdDoc '' + The hostname or IP of the FRITZ!Box. + ''; + }; + + gatewayPort = mkOption { + type = types.int; + default = 49000; + description = lib.mdDoc '' + The port of the FRITZ!Box UPnP service. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-fritzbox-exporter}/bin/exporter \ + -listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -gateway-address ${cfg.gatewayAddress} \ + -gateway-port ${toString cfg.gatewayPort} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/graphite.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/graphite.nix new file mode 100644 index 000000000000..34a887104212 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/graphite.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, options }: + +let + cfg = config.services.prometheus.exporters.graphite; + format = pkgs.formats.yaml { }; +in +{ + port = 9108; + extraOpts = { + graphitePort = lib.mkOption { + type = lib.types.port; + default = 9109; + description = lib.mdDoc '' + Port to use for the graphite server. + ''; + }; + mappingSettings = lib.mkOption { + type = lib.types.submodule { + freeformType = format.type; + options = { }; + }; + default = { }; + description = lib.mdDoc '' + Mapping configuration for the exporter, see + <https://github.com/prometheus/graphite_exporter#yaml-config> for + available options. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-graphite-exporter}/bin/graphite_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --graphite.listen-address ${cfg.listenAddress}:${toString cfg.graphitePort} \ + --graphite.mapping-config ${format.generate "mapping.yml" cfg.mappingSettings} \ + ${lib.concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/idrac.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/idrac.nix new file mode 100644 index 000000000000..f5604bc00ee0 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/idrac.nix @@ -0,0 +1,69 @@ +{ config, lib, pkgs, options }: + +with lib; +let + cfg = config.services.prometheus.exporters.idrac; + + configFile = if cfg.configurationPath != null + then cfg.configurationPath + else pkgs.writeText "idrac.yml" (builtins.toJSON cfg.configuration); +in +{ + port = 9348; + extraOpts = { + configurationPath = mkOption { + type = with types; nullOr path; + default = null; + example = "/etc/prometheus-idrac-exporter/idrac.yml"; + description = lib.mdDoc '' + Path to the service's config file. This path can either be a computed path in /nix/store or a path in the local filesystem. + + The config file should NOT be stored in /nix/store as it will contain passwords and/or keys in plain text. + + Mutually exclusive with `configuration` option. + + Configuration reference: https://github.com/mrlhansen/idrac_exporter/#configuration + ''; + }; + configuration = mkOption { + type = types.nullOr types.attrs; + description = lib.mdDoc '' + Configuration for iDRAC exporter, as a nix attribute set. + + Configuration reference: https://github.com/mrlhansen/idrac_exporter/#configuration + + Mutually exclusive with `configurationPath` option. + ''; + default = null; + example = { + timeout = 10; + retries = 1; + hosts = { + default = { + username = "username"; + password = "password"; + }; + }; + metrics = { + system = true; + sensors = true; + power = true; + sel = true; + storage = true; + memory = true; + }; + }; + }; + }; + + serviceOpts = { + serviceConfig = { + LoadCredential = "configFile:${configFile}"; + ExecStart = "${pkgs.prometheus-idrac-exporter}/bin/idrac_exporter -config %d/configFile"; + Environment = [ + "IDRAC_EXPORTER_LISTEN_ADDRESS=${cfg.listenAddress}" + "IDRAC_EXPORTER_LISTEN_PORT=${toString cfg.port}" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/imap-mailstat.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/imap-mailstat.nix new file mode 100644 index 000000000000..c5024a258e71 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/imap-mailstat.nix @@ -0,0 +1,71 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.imap-mailstat; + valueToString = value: + if (builtins.typeOf value == "string") then "\"${value}\"" + else ( + if (builtins.typeOf value == "int") then "${toString value}" + else ( + if (builtins.typeOf value == "bool") then (if value then "true" else "false") + else "XXX ${toString value}" + ) + ); + createConfigFile = accounts: + # unfortunately on toTOML yet + # https://github.com/NixOS/nix/issues/3929 + pkgs.writeText "imap-mailstat-exporter.conf" '' + ${concatStrings (attrValues (mapAttrs (name: config: "[[Accounts]]\nname = \"${name}\"\n${concatStrings (attrValues (mapAttrs (k: v: "${k} = ${valueToString v}\n") config))}") accounts))} + ''; + mkOpt = type: description: mkOption { + type = types.nullOr type; + default = null; + description = lib.mdDoc description; + }; + accountOptions.options = { + mailaddress = mkOpt types.str "Your email address (at the moment used as login name)"; + username = mkOpt types.str "If empty string mailaddress value is used"; + password = mkOpt types.str ""; + serveraddress = mkOpt types.str "mailserver name or address"; + serverport = mkOpt types.int "imap port number (at the moment only tls connection is supported)"; + starttls = mkOpt types.bool "set to true for using STARTTLS to start a TLS connection"; + }; +in +{ + port = 8081; + extraOpts = { + oldestUnseenDate = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Enable metric with timestamp of oldest unseen mail + ''; + }; + accounts = mkOption { + type = types.attrsOf (types.submodule accountOptions); + default = {}; + description = lib.mdDoc '' + Accounts to monitor + ''; + }; + configurationFile = mkOption { + type = types.path; + example = "/path/to/config-file"; + description = lib.mdDoc '' + File containing the configuration + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-imap-mailstat-exporter}/bin/imap-mailstat-exporter \ + -config ${createConfigFile cfg.accounts} \ + ${optionalString cfg.oldestUnseenDate "-oldestunseendate"} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/influxdb.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/influxdb.nix new file mode 100644 index 000000000000..61c0c08d2250 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/influxdb.nix @@ -0,0 +1,34 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.influxdb; +in +{ + port = 9122; + extraOpts = { + sampleExpiry = mkOption { + type = types.str; + default = "5m"; + example = "10m"; + description = lib.mdDoc "How long a sample is valid for"; + }; + udpBindAddress = mkOption { + type = types.str; + default = ":9122"; + example = "192.0.2.1:9122"; + description = lib.mdDoc "Address on which to listen for udp packets"; + }; + }; + serviceOpts = { + serviceConfig = { + RuntimeDirectory = "prometheus-influxdb-exporter"; + ExecStart = '' + ${pkgs.prometheus-influxdb-exporter}/bin/influxdb_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --influxdb.sample-expiry ${cfg.sampleExpiry} ${concatStringsSep " " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/ipmi.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/ipmi.nix new file mode 100644 index 000000000000..9adbe31d84d6 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/ipmi.nix @@ -0,0 +1,42 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + logPrefix = "services.prometheus.exporter.ipmi"; + cfg = config.services.prometheus.exporters.ipmi; +in { + port = 9290; + + extraOpts = { + configFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to configuration file. + ''; + }; + + webConfigFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to configuration file that can enable TLS or authentication. + ''; + }; + }; + + serviceOpts.serviceConfig = { + ExecStart = with cfg; concatStringsSep " " ([ + "${pkgs.prometheus-ipmi-exporter}/bin/ipmi_exporter" + "--web.listen-address ${listenAddress}:${toString port}" + ] ++ optionals (cfg.webConfigFile != null) [ + "--web.config.file ${escapeShellArg cfg.webConfigFile}" + ] ++ optionals (cfg.configFile != null) [ + "--config.file ${escapeShellArg cfg.configFile}" + ] ++ extraFlags); + + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/jitsi.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/jitsi.nix new file mode 100644 index 000000000000..024602718602 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/jitsi.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.jitsi; +in +{ + port = 9700; + extraOpts = { + url = mkOption { + type = types.str; + default = "http://localhost:8080/colibri/stats"; + description = lib.mdDoc '' + Jitsi Videobridge metrics URL to monitor. + This is usually /colibri/stats on port 8080 of the jitsi videobridge host. + ''; + }; + interval = mkOption { + type = types.str; + default = "30s"; + example = "1min"; + description = lib.mdDoc '' + How often to scrape new data + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-jitsi-exporter}/bin/jitsiexporter \ + -url ${escapeShellArg cfg.url} \ + -host ${cfg.listenAddress} \ + -port ${toString cfg.port} \ + -interval ${toString cfg.interval} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix new file mode 100644 index 000000000000..473f3a7e47e3 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix @@ -0,0 +1,43 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.json; +in +{ + port = 7979; + extraOpts = { + configFile = mkOption { + type = types.path; + description = lib.mdDoc '' + Path to configuration file. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-json-exporter}/bin/json_exporter \ + --config.file ${escapeShellArg cfg.configFile} \ + --web.listen-address="${cfg.listenAddress}:${toString cfg.port}" \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; + imports = [ + (mkRemovedOptionModule [ "url" ] '' + This option was removed. The URL of the endpoint serving JSON + must now be provided to the exporter by prometheus via the url + parameter `target'. + + In prometheus a scrape URL would look like this: + + http://some.json-exporter.host:7979/probe?target=https://example.com/some/json/endpoint + + For more information, take a look at the official documentation + (https://github.com/prometheus-community/json_exporter) of the json_exporter. + '') + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/junos-czerwonk.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/junos-czerwonk.nix new file mode 100644 index 000000000000..15e0c9ecb177 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/junos-czerwonk.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.junos-czerwonk; + + configFile = if cfg.configuration != null then configurationFile else (escapeShellArg cfg.configurationFile); + + configurationFile = pkgs.writeText "prometheus-junos-czerwonk-exporter.conf" (builtins.toJSON (cfg.configuration)); +in +{ + port = 9326; + extraOpts = { + environmentFile = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc '' + File containing env-vars to be substituted into the exporter's config. + ''; + }; + configurationFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Specify the JunOS exporter configuration file to use. + ''; + }; + configuration = mkOption { + type = types.nullOr types.attrs; + default = null; + description = lib.mdDoc '' + JunOS exporter configuration as nix attribute set. Mutually exclusive with the `configurationFile` option. + ''; + example = { + devices = [ + { + host = "router1"; + key_file = "/path/to/key"; + } + ]; + }; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + RuntimeDirectory = "prometheus-junos-czerwonk-exporter"; + ExecStartPre = [ + "${pkgs.writeShellScript "subst-secrets-junos-czerwonk-exporter" '' + umask 0077 + ${pkgs.envsubst}/bin/envsubst -i ${configFile} -o ''${RUNTIME_DIRECTORY}/junos-exporter.json + ''}" + ]; + ExecStart = '' + ${pkgs.prometheus-junos-czerwonk-exporter}/bin/junos_exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -web.telemetry-path ${cfg.telemetryPath} \ + -config.file ''${RUNTIME_DIRECTORY}/junos-exporter.json \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix new file mode 100644 index 000000000000..8b1cd47d0a40 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/kea.nix @@ -0,0 +1,47 @@ +{ config +, lib +, pkgs +, options +}: + +with lib; + +let + cfg = config.services.prometheus.exporters.kea; +in { + port = 9547; + extraOpts = { + controlSocketPaths = mkOption { + type = types.listOf types.str; + example = literalExpression '' + [ + "/run/kea-dhcp4/kea-dhcp4.socket" + "/run/kea-dhcp6/kea-dhcp6.socket" + ] + ''; + description = lib.mdDoc '' + Paths to kea control sockets + ''; + }; + }; + serviceOpts = { + after = [ + "kea-dhcp4-server.service" + "kea-dhcp6-server.service" + ]; + serviceConfig = { + User = "kea"; + ExecStart = '' + ${pkgs.prometheus-kea-exporter}/bin/kea-exporter \ + --address ${cfg.listenAddress} \ + --port ${toString cfg.port} \ + ${concatStringsSep " " cfg.controlSocketPaths} + ''; + SupplementaryGroups = [ "kea" ]; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/keylight.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/keylight.nix new file mode 100644 index 000000000000..dfa56343b871 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/keylight.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.keylight; +in +{ + port = 9288; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-keylight-exporter}/bin/keylight_exporter \ + -metrics.addr ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix new file mode 100644 index 000000000000..775848750803 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/knot.nix @@ -0,0 +1,58 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.knot; +in { + port = 9433; + extraOpts = { + knotLibraryPath = mkOption { + type = types.nullOr types.str; + default = null; + example = literalExpression ''"''${pkgs.knot-dns.out}/lib/libknot.so"''; + description = lib.mdDoc '' + Path to the library of `knot-dns`. + ''; + }; + + knotSocketPath = mkOption { + type = types.str; + default = "/run/knot/knot.sock"; + description = lib.mdDoc '' + Socket path of {manpage}`knotd(8)`. + ''; + }; + + knotSocketTimeout = mkOption { + type = types.ints.positive; + default = 2000; + description = lib.mdDoc '' + Timeout in seconds. + ''; + }; + }; + serviceOpts = { + path = with pkgs; [ + procps + ]; + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-knot-exporter}/bin/knot-exporter \ + --web-listen-addr ${cfg.listenAddress} \ + --web-listen-port ${toString cfg.port} \ + --knot-socket-path ${cfg.knotSocketPath} \ + --knot-socket-timeout ${toString cfg.knotSocketTimeout} \ + ${lib.optionalString (cfg.knotLibraryPath != null) "--knot-library-path ${cfg.knotLibraryPath}"} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + SupplementaryGroups = [ + "knot" + ]; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/lnd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/lnd.nix new file mode 100644 index 000000000000..9f914b1dc146 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/lnd.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.lnd; +in +{ + port = 9092; + extraOpts = { + lndHost = mkOption { + type = types.str; + default = "localhost:10009"; + description = lib.mdDoc '' + lnd instance gRPC address:port. + ''; + }; + + lndTlsPath = mkOption { + type = types.path; + description = lib.mdDoc '' + Path to lnd TLS certificate. + ''; + }; + + lndMacaroonDir = mkOption { + type = types.path; + description = lib.mdDoc '' + Path to lnd macaroons. + ''; + }; + }; + serviceOpts.serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-lnd-exporter}/bin/lndmon \ + --prometheus.listenaddr=${cfg.listenAddress}:${toString cfg.port} \ + --prometheus.logdir=/var/log/prometheus-lnd-exporter \ + --lnd.host=${cfg.lndHost} \ + --lnd.tlspath=${cfg.lndTlsPath} \ + --lnd.macaroondir=${cfg.lndMacaroonDir} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + LogsDirectory = "prometheus-lnd-exporter"; + ReadOnlyPaths = [ cfg.lndTlsPath cfg.lndMacaroonDir ]; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix new file mode 100644 index 000000000000..15079f5841f4 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix @@ -0,0 +1,190 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.mail; + + configFile = if cfg.configuration != null then configurationFile else (escapeShellArg cfg.configFile); + + configurationFile = pkgs.writeText "prometheus-mail-exporter.conf" (builtins.toJSON ( + # removes the _module attribute, null values and converts attrNames to lowercase + mapAttrs' (name: value: + if name == "servers" + then nameValuePair (toLower name) + ((map (srv: (mapAttrs' (n: v: nameValuePair (toLower n) v) + (filterAttrs (n: v: !(n == "_module" || v == null)) srv) + ))) value) + else nameValuePair (toLower name) value + ) (filterAttrs (n: _: !(n == "_module")) cfg.configuration) + )); + + serverOptions.options = { + name = mkOption { + type = types.str; + description = lib.mdDoc '' + Value for label 'configname' which will be added to all metrics. + ''; + }; + server = mkOption { + type = types.str; + description = lib.mdDoc '' + Hostname of the server that should be probed. + ''; + }; + port = mkOption { + type = types.port; + example = 587; + description = lib.mdDoc '' + Port to use for SMTP. + ''; + }; + from = mkOption { + type = types.str; + example = "exporteruser@domain.tld"; + description = lib.mdDoc '' + Content of 'From' Header for probing mails. + ''; + }; + to = mkOption { + type = types.str; + example = "exporteruser@domain.tld"; + description = lib.mdDoc '' + Content of 'To' Header for probing mails. + ''; + }; + detectionDir = mkOption { + type = types.path; + example = "/var/spool/mail/exporteruser/new"; + description = lib.mdDoc '' + Directory in which new mails for the exporter user are placed. + Note that this needs to exist when the exporter starts. + ''; + }; + login = mkOption { + type = types.nullOr types.str; + default = null; + example = "exporteruser@domain.tld"; + description = lib.mdDoc '' + Username to use for SMTP authentication. + ''; + }; + passphrase = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc '' + Password to use for SMTP authentication. + ''; + }; + }; + + exporterOptions.options = { + monitoringInterval = mkOption { + type = types.str; + example = "10s"; + description = lib.mdDoc '' + Time interval between two probe attempts. + ''; + }; + mailCheckTimeout = mkOption { + type = types.str; + description = lib.mdDoc '' + Timeout until mails are considered "didn't make it". + ''; + }; + disableFileDeletion = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Disables the exporter's function to delete probing mails. + ''; + }; + servers = mkOption { + type = types.listOf (types.submodule serverOptions); + default = []; + example = literalExpression '' + [ { + name = "testserver"; + server = "smtp.domain.tld"; + port = 587; + from = "exporteruser@domain.tld"; + to = "exporteruser@domain.tld"; + detectionDir = "/path/to/Maildir/new"; + } ] + ''; + description = lib.mdDoc '' + List of servers that should be probed. + + *Note:* if your mailserver has {manpage}`rspamd(8)` configured, + it can happen that emails from this exporter are marked as spam. + + It's possible to work around the issue with a config like this: + ``` + { + services.rspamd.locals."multimap.conf".text = ''' + ALLOWLIST_PROMETHEUS { + filter = "email:domain:tld"; + type = "from"; + map = "''${pkgs.writeText "allowmap" "domain.tld"}"; + score = -100.0; + } + '''; + } + ``` + ''; + }; + }; +in +{ + port = 9225; + extraOpts = { + environmentFile = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc '' + File containing env-vars to be substituted into the exporter's config. + ''; + }; + configFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Specify the mailexporter configuration file to use. + ''; + }; + configuration = mkOption { + type = types.nullOr (types.submodule exporterOptions); + default = null; + description = lib.mdDoc '' + Specify the mailexporter configuration file to use. + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + RuntimeDirectory = "prometheus-mail-exporter"; + ExecStartPre = [ + "${pkgs.writeShellScript "subst-secrets-mail-exporter" '' + umask 0077 + ${pkgs.envsubst}/bin/envsubst -i ${configFile} -o ''${RUNTIME_DIRECTORY}/mail-exporter.json + ''}" + ]; + ExecStart = '' + ${pkgs.prometheus-mail-exporter}/bin/mailexporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + --config.file ''${RUNTIME_DIRECTORY}/mail-exporter.json \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix new file mode 100644 index 000000000000..54dab4b5581a --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix @@ -0,0 +1,66 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.mikrotik; +in +{ + port = 9436; + extraOpts = { + configFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to a mikrotik exporter configuration file. Mutually exclusive with + {option}`configuration` option. + ''; + example = literalExpression "./mikrotik.yml"; + }; + + configuration = mkOption { + type = types.nullOr types.attrs; + default = null; + description = lib.mdDoc '' + Mikrotik exporter configuration as nix attribute set. Mutually exclusive with + {option}`configFile` option. + + See <https://github.com/nshttpd/mikrotik-exporter/blob/master/README.md> + for the description of the configuration file format. + ''; + example = literalExpression '' + { + devices = [ + { + name = "my_router"; + address = "10.10.0.1"; + user = "prometheus"; + password = "changeme"; + } + ]; + features = { + bgp = true; + dhcp = true; + routes = true; + optics = true; + }; + } + ''; + }; + }; + serviceOpts = let + configFile = if cfg.configFile != null + then cfg.configFile + else "${pkgs.writeText "mikrotik-exporter.yml" (builtins.toJSON cfg.configuration)}"; + in { + serviceConfig = { + # -port is misleading name, it actually accepts address too + ExecStart = '' + ${pkgs.prometheus-mikrotik-exporter}/bin/mikrotik-exporter \ + -config-file=${escapeShellArg configFile} \ + -port=${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix new file mode 100644 index 000000000000..82cc3fc314f2 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.minio; +in +{ + port = 9290; + extraOpts = { + minioAddress = mkOption { + type = types.str; + example = "https://10.0.0.1:9000"; + description = lib.mdDoc '' + The URL of the minio server. + Use HTTPS if Minio accepts secure connections only. + By default this connects to the local minio server if enabled. + ''; + }; + + minioAccessKey = mkOption { + type = types.str; + example = "yourMinioAccessKey"; + description = lib.mdDoc '' + The value of the Minio access key. + It is required in order to connect to the server. + By default this uses the one from the local minio server if enabled + and `config.services.minio.accessKey`. + ''; + }; + + minioAccessSecret = mkOption { + type = types.str; + description = lib.mdDoc '' + The value of the Minio access secret. + It is required in order to connect to the server. + By default this uses the one from the local minio server if enabled + and `config.services.minio.secretKey`. + ''; + }; + + minioBucketStats = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Collect statistics about the buckets and files in buckets. + It requires more computation, use it carefully in case of large buckets.. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -minio.server ${cfg.minioAddress} \ + -minio.access-key ${escapeShellArg cfg.minioAccessKey} \ + -minio.access-secret ${escapeShellArg cfg.minioAccessSecret} \ + ${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/modemmanager.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/modemmanager.nix new file mode 100644 index 000000000000..222ea3e5384f --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/modemmanager.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.modemmanager; +in +{ + port = 9539; + extraOpts = { + refreshRate = mkOption { + type = types.str; + default = "5s"; + description = lib.mdDoc '' + How frequently ModemManager will refresh the extended signal quality + information for each modem. The duration should be specified in seconds + ("5s"), minutes ("1m"), or hours ("1h"). + ''; + }; + }; + serviceOpts = { + serviceConfig = { + # Required in order to authenticate with ModemManager via D-Bus. + SupplementaryGroups = "networkmanager"; + ExecStart = '' + ${pkgs.prometheus-modemmanager-exporter}/bin/modemmanager_exporter \ + -addr ${cfg.listenAddress}:${toString cfg.port} \ + -rate ${cfg.refreshRate} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mongodb.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mongodb.nix new file mode 100644 index 000000000000..db5c4d15be66 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mongodb.nix @@ -0,0 +1,68 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.mongodb; +in +{ + port = 9216; + extraOpts = { + uri = mkOption { + type = types.str; + default = "mongodb://localhost:27017/test"; + example = "mongodb://localhost:27017/test"; + description = lib.mdDoc "MongoDB URI to connect to."; + }; + collStats = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "db1.coll1" "db2" ]; + description = lib.mdDoc '' + List of comma separared databases.collections to get $collStats + ''; + }; + indexStats = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "db1.coll1" "db2" ]; + description = lib.mdDoc '' + List of comma separared databases.collections to get $indexStats + ''; + }; + collector = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "diagnosticdata" "replicasetstatus" "dbstats" "topmetrics" "currentopmetrics" "indexstats" "dbstats" "profile" ]; + description = lib.mdDoc "Enabled collectors"; + }; + collectAll = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Enable all collectors. Same as specifying all --collector.<name> + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + example = "/metrics"; + description = lib.mdDoc "Metrics expose path"; + }; + }; + serviceOpts = { + serviceConfig = { + RuntimeDirectory = "prometheus-mongodb-exporter"; + ExecStart = '' + ${getExe pkgs.prometheus-mongodb-exporter} \ + --mongodb.uri=${cfg.uri} + ${if cfg.collectAll then "--collect-all" else concatMapStringsSep " " (x: "--collect.${x}") cfg.collector} \ + --collector.collstats=${concatStringsSep "," cfg.collStats} \ + --collector.indexstats=${concatStringsSep "," cfg.indexStats} \ + --web.listen-address=${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path=${cfg.telemetryPath} \ + ${escapeShellArgs cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mysqld.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mysqld.nix new file mode 100644 index 000000000000..849c514de681 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mysqld.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, options }: +let + cfg = config.services.prometheus.exporters.mysqld; + inherit (lib) types mkOption mdDoc mkIf mkForce cli concatStringsSep optionalString escapeShellArgs; +in { + port = 9104; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = mdDoc '' + Path under which to expose metrics. + ''; + }; + + runAsLocalSuperUser = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to run the exporter as {option}`services.mysql.user`. + ''; + }; + + configFile = mkOption { + type = types.path; + example = "/var/lib/prometheus-mysqld-exporter.cnf"; + description = mdDoc '' + Path to the services config file. + + See <https://github.com/prometheus/mysqld_exporter#running> for more information about + the available options. + + ::: {.warn} + Please do not store this file in the nix store if you choose to include any credentials here, + as it would be world-readable. + ::: + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + DynamicUser = !cfg.runAsLocalSuperUser; + User = mkIf cfg.runAsLocalSuperUser (mkForce config.services.mysql.user); + LoadCredential = mkIf (cfg.configFile != null) (mkForce ("config:" + cfg.configFile)); + ExecStart = concatStringsSep " " [ + "${pkgs.prometheus-mysqld-exporter}/bin/mysqld_exporter" + "--web.listen-address=${cfg.listenAddress}:${toString cfg.port}" + "--web.telemetry-path=${cfg.telemetryPath}" + (optionalString (cfg.configFile != null) ''--config.my-cnf=''${CREDENTIALS_DIRECTORY}/config'') + (escapeShellArgs cfg.extraFlags) + ]; + RestrictAddressFamilies = [ + # The exporter can be configured to talk to a local mysql server via a unix socket. + "AF_UNIX" + ]; + }; + }; +} + diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix new file mode 100644 index 000000000000..28a3eb6a134c --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.nextcloud; +in +{ + port = 9205; + extraOpts = { + url = mkOption { + type = types.str; + example = "https://domain.tld"; + description = lib.mdDoc '' + URL to the Nextcloud serverinfo page. + Adding the path to the serverinfo API is optional, it defaults + to `/ocs/v2.php/apps/serverinfo/api/v1/info`. + ''; + }; + username = mkOption { + type = types.str; + default = "nextcloud-exporter"; + description = lib.mdDoc '' + Username for connecting to Nextcloud. + Note that this account needs to have admin privileges in Nextcloud. + Unused when using token authentication. + ''; + }; + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/path/to/password-file"; + description = lib.mdDoc '' + File containing the password for connecting to Nextcloud. + Make sure that this file is readable by the exporter user. + ''; + }; + tokenFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/path/to/token-file"; + description = lib.mdDoc '' + File containing the token for connecting to Nextcloud. + Make sure that this file is readable by the exporter user. + ''; + }; + timeout = mkOption { + type = types.str; + default = "5s"; + description = lib.mdDoc '' + Timeout for getting server info document. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + ExecStart = '' + ${pkgs.prometheus-nextcloud-exporter}/bin/nextcloud-exporter \ + --addr ${cfg.listenAddress}:${toString cfg.port} \ + --timeout ${cfg.timeout} \ + --server ${cfg.url} \ + ${if cfg.passwordFile != null then '' + --username ${cfg.username} \ + --password ${escapeShellArg "@${cfg.passwordFile}"} \ + '' else '' + --auth-token ${escapeShellArg "@${cfg.tokenFile}"} \ + ''} \ + ${concatStringsSep " \\\n " cfg.extraFlags}''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix new file mode 100644 index 000000000000..3158e71f0468 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix @@ -0,0 +1,68 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.nginx; +in +{ + port = 9113; + extraOpts = { + scrapeUri = mkOption { + type = types.str; + default = "http://localhost/nginx_status"; + description = lib.mdDoc '' + Address to access the nginx status page. + Can be enabled with services.nginx.statusPage = true. + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + sslVerify = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Whether to perform certificate verification for https. + ''; + }; + constLabels = mkOption { + type = types.listOf types.str; + default = []; + example = [ + "label1=value1" + "label2=value2" + ]; + description = lib.mdDoc '' + A list of constant labels that will be used in every metric. + ''; + }; + }; + serviceOpts = mkMerge ([{ + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-nginx-exporter}/bin/nginx-prometheus-exporter \ + --nginx.scrape-uri='${cfg.scrapeUri}' \ + --nginx.ssl-verify=${boolToString cfg.sslVerify} \ + --web.listen-address=${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path=${cfg.telemetryPath} \ + --prometheus.const-labels=${concatStringsSep "," cfg.constLabels} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }] ++ [(mkIf config.services.nginx.enable { + after = [ "nginx.service" ]; + requires = [ "nginx.service" ]; + })]); + imports = [ + (mkRenamedOptionModule [ "telemetryEndpoint" ] [ "telemetryPath" ]) + (mkRemovedOptionModule [ "insecure" ] '' + This option was replaced by 'prometheus.exporters.nginx.sslVerify'. + '') + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix new file mode 100644 index 000000000000..674dc9dd4158 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginxlog.nix @@ -0,0 +1,51 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.nginxlog; +in { + port = 9117; + extraOpts = { + settings = mkOption { + type = types.attrs; + default = {}; + description = lib.mdDoc '' + All settings of nginxlog expressed as an Nix attrset. + + Check the official documentation for the corresponding YAML + settings that can all be used here: https://github.com/martin-helmich/prometheus-nginxlog-exporter + + The `listen` object is already generated by `port`, `listenAddress` and `metricsEndpoint` and + will be merged with the value of `settings` before writing it as JSON. + ''; + }; + + metricsEndpoint = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + }; + + serviceOpts = let + listenConfig = { + listen = { + port = cfg.port; + address = cfg.listenAddress; + metrics_endpoint = cfg.metricsEndpoint; + }; + }; + completeConfig = pkgs.writeText "nginxlog-exporter.yaml" (builtins.toJSON (lib.recursiveUpdate listenConfig cfg.settings)); + in { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-nginxlog-exporter}/bin/prometheus-nginxlog-exporter -config-file ${completeConfig} + ''; + Restart="always"; + ProtectSystem="full"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix new file mode 100644 index 000000000000..dd8602e2c63d --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.node; + collectorIsEnabled = final: any (collector: (final == collector)) cfg.enabledCollectors; + collectorIsDisabled = final: any (collector: (final == collector)) cfg.disabledCollectors; +in +{ + port = 9100; + extraOpts = { + enabledCollectors = mkOption { + type = types.listOf types.str; + default = []; + example = [ "systemd" ]; + description = lib.mdDoc '' + Collectors to enable. The collectors listed here are enabled in addition to the default ones. + ''; + }; + disabledCollectors = mkOption { + type = types.listOf types.str; + default = []; + example = [ "timex" ]; + description = lib.mdDoc '' + Collectors to disable which are enabled by default. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + RuntimeDirectory = "prometheus-node-exporter"; + ExecStart = '' + ${pkgs.prometheus-node-exporter}/bin/node_exporter \ + ${concatMapStringsSep " " (x: "--collector." + x) cfg.enabledCollectors} \ + ${concatMapStringsSep " " (x: "--no-collector." + x) cfg.disabledCollectors} \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} ${concatStringsSep " " cfg.extraFlags} + ''; + RestrictAddressFamilies = optionals (collectorIsEnabled "logind" || collectorIsEnabled "systemd") [ + # needs access to dbus via unix sockets (logind/systemd) + "AF_UNIX" + ] ++ optionals (collectorIsEnabled "network_route" || collectorIsEnabled "wifi" || ! collectorIsDisabled "netdev") [ + # needs netlink sockets for wireless collector + "AF_NETLINK" + ]; + # The timex collector needs to access clock APIs + ProtectClock = collectorIsDisabled "timex"; + # Allow space monitoring under /home + ProtectHome = true; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nut.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nut.nix new file mode 100644 index 000000000000..1c86b48b4509 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nut.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.nut; +in +{ + port = 9199; + extraOpts = { + nutServer = mkOption { + type = types.str; + default = "127.0.0.1"; + description = lib.mdDoc '' + Hostname or address of the NUT server + ''; + }; + nutUser = mkOption { + type = types.str; + default = ""; + example = "nut"; + description = lib.mdDoc '' + The user to log in into NUT server. If set, passwordPath should + also be set. + + Default NUT configs usually permit reading variables without + authentication. + ''; + }; + passwordPath = mkOption { + type = types.nullOr types.path; + default = null; + apply = final: if final == null then null else toString final; + description = lib.mdDoc '' + A run-time path to the nutUser password file, which should be + provisioned outside of Nix store. + ''; + }; + }; + serviceOpts = { + script = '' + ${optionalString (cfg.passwordPath != null) + "export NUT_EXPORTER_PASSWORD=$(cat ${toString cfg.passwordPath})"} + ${pkgs.prometheus-nut-exporter}/bin/nut_exporter \ + --nut.server=${cfg.nutServer} \ + --web.listen-address="${cfg.listenAddress}:${toString cfg.port}" \ + ${optionalString (cfg.nutUser != "") "--nut.username=${cfg.nutUser}"} + ''; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openldap.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openldap.nix new file mode 100644 index 000000000000..aee3ae5bb2d4 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openldap.nix @@ -0,0 +1,67 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.prometheus.exporters.openldap; +in { + port = 9330; + extraOpts = { + ldapCredentialFile = mkOption { + type = types.path; + example = "/run/keys/ldap_pass"; + description = lib.mdDoc '' + Environment file to contain the credentials to authenticate against + `openldap`. + + The file should look like this: + ``` + --- + ldapUser: "cn=monitoring,cn=Monitor" + ldapPass: "secret" + ``` + ''; + }; + protocol = mkOption { + default = "tcp"; + example = "udp"; + type = types.str; + description = lib.mdDoc '' + Which protocol to use to connect against `openldap`. + ''; + }; + ldapAddr = mkOption { + default = "localhost:389"; + type = types.str; + description = lib.mdDoc '' + Address of the `openldap`-instance. + ''; + }; + metricsPath = mkOption { + default = "/metrics"; + type = types.str; + description = lib.mdDoc '' + URL path where metrics should be exposed. + ''; + }; + interval = mkOption { + default = "30s"; + type = types.str; + example = "1m"; + description = lib.mdDoc '' + Scrape interval of the exporter. + ''; + }; + }; + serviceOpts.serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-openldap-exporter}/bin/openldap_exporter \ + --promAddr ${cfg.listenAddress}:${toString cfg.port} \ + --metrPath ${cfg.metricsPath} \ + --ldapNet ${cfg.protocol} \ + --interval ${cfg.interval} \ + --config ${cfg.ldapCredentialFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix new file mode 100644 index 000000000000..5b54dad99805 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/openvpn.nix @@ -0,0 +1,39 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.prometheus.exporters.openvpn; +in { + port = 9176; + extraOpts = { + statusPaths = mkOption { + type = types.listOf types.str; + description = lib.mdDoc '' + Paths to OpenVPN status files. Please configure the OpenVPN option + `status` accordingly. + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + PrivateDevices = true; + ProtectKernelModules = true; + NoNewPrivileges = true; + ExecStart = '' + ${pkgs.prometheus-openvpn-exporter}/bin/openvpn_exporter \ + -openvpn.status_paths "${concatStringsSep "," cfg.statusPaths}" \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -web.telemetry-path ${cfg.telemetryPath} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix new file mode 100644 index 000000000000..9e55cadae523 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix @@ -0,0 +1,145 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.pgbouncer; +in +{ + port = 9127; + extraOpts = { + + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + + connectionString = mkOption { + type = types.str; + default = ""; + example = "postgres://admin:@localhost:6432/pgbouncer?sslmode=require"; + description = lib.mdDoc '' + Connection string for accessing pgBouncer. + + NOTE: You MUST keep pgbouncer as database name (special internal db)!!! + + NOTE: Admin user (with password or passwordless) MUST exist + in the services.pgbouncer.authFile if authType other than any is used. + + WARNING: this secret is stored in the world-readable Nix store! + Use {option}`connectionStringFile` instead. + ''; + }; + + connectionStringFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/pgBouncer-connection-string"; + description = lib.mdDoc '' + File that contains pgBouncer connection string in format: + postgres://admin:@localhost:6432/pgbouncer?sslmode=require + + NOTE: You MUST keep pgbouncer as database name (special internal db)!!! + + NOTE: Admin user (with password or passwordless) MUST exist + in the services.pgbouncer.authFile if authType other than any is used. + + {option}`connectionStringFile` takes precedence over {option}`connectionString` + ''; + }; + + pidFile = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc '' + Path to PgBouncer pid file. + + If provided, the standard process metrics get exported for the PgBouncer + process, prefixed with 'pgbouncer_process_...'. The pgbouncer_process exporter + needs to have read access to files owned by the PgBouncer process. Depends on + the availability of /proc. + + https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics. + + ''; + }; + + webSystemdSocket = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Use systemd socket activation listeners instead of port listeners (Linux only). + ''; + }; + + logLevel = mkOption { + type = types.enum ["debug" "info" "warn" "error" ]; + default = "info"; + description = lib.mdDoc '' + Only log messages with the given severity or above. + ''; + }; + + logFormat = mkOption { + type = types.enum ["logfmt" "json"]; + default = "logfmt"; + description = lib.mdDoc '' + Output format of log messages. One of: [logfmt, json] + ''; + }; + + webConfigFile = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to configuration file that can enable TLS or authentication. + ''; + }; + + extraFlags = mkOption { + type = types.listOf types.str; + default = [ ]; + description = lib.mdDoc '' + Extra commandline options when launching Prometheus. + ''; + }; + + }; + + serviceOpts = { + after = [ "pgbouncer.service" ]; + serviceConfig = let + startScript = pkgs.writeShellScriptBin "pgbouncer-start" "${concatStringsSep " " ([ + "${pkgs.prometheus-pgbouncer-exporter}/bin/pgbouncer_exporter" + "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" + "--pgBouncer.connectionString ${if cfg.connectionStringFile != null then + "$(head -n1 ${cfg.connectionStringFile})" else "${escapeShellArg cfg.connectionString}"}" + ] + ++ optionals (cfg.telemetryPath != null) [ + "--web.telemetry-path ${escapeShellArg cfg.telemetryPath}" + ] + ++ optionals (cfg.pidFile != null) [ + "--pgBouncer.pid-file= ${escapeShellArg cfg.pidFile}" + ] + ++ optionals (cfg.logLevel != null) [ + "--log.level ${escapeShellArg cfg.logLevel}" + ] + ++ optionals (cfg.logFormat != null) [ + "--log.format ${escapeShellArg cfg.logFormat}" + ] + ++ optionals (cfg.webSystemdSocket != false) [ + "--web.systemd-socket ${escapeShellArg cfg.webSystemdSocket}" + ] + ++ optionals (cfg.webConfigFile != null) [ + "--web.config.file ${escapeShellArg cfg.webConfigFile}" + ] + ++ cfg.extraFlags)}"; + in + { + ExecStart = "${startScript}/bin/pgbouncer-start"; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix new file mode 100644 index 000000000000..8238f1ac1856 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/php-fpm.nix @@ -0,0 +1,65 @@ +{ config +, lib +, pkgs +, options +}: + +let + logPrefix = "services.prometheus.exporter.php-fpm"; + cfg = config.services.prometheus.exporters.php-fpm; +in { + port = 9253; + extraOpts = { + package = lib.mkPackageOption pkgs "prometheus-php-fpm-exporter" {}; + + telemetryPath = lib.mkOption { + type = lib.types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/root/prometheus-php-fpm-exporter.env"; + description = lib.mdDoc '' + Environment file as defined in {manpage}`systemd.exec(5)`. + + Secrets may be passed to the service without adding them to the + world-readable Nix store, by specifying placeholder variables as + the option value in Nix and setting these variables accordingly in the + environment file. + + Environment variables from this file will be interpolated into the + config file using envsubst with this syntax: + `$ENVIRONMENT ''${VARIABLE}` + + For variables to use see [options and defaults](https://github.com/hipages/php-fpm_exporter#options-and-defaults). + + The main use is to set the PHP_FPM_SCRAPE_URI that indicate how to connect to PHP-FPM process. + + ``` + # Content of the environment file + PHP_FPM_SCRAPE_URI="unix:///tmp/php.sock;/status" + ``` + + Note that this file needs to be available on the host on which + this exporter is running. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + ExecStart = '' + ${lib.getExe cfg.package} server \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${lib.concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pihole.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pihole.nix new file mode 100644 index 000000000000..6f403b3e58c8 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pihole.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.pihole; +in +{ + imports = [ + (mkRemovedOptionModule [ "interval"] "This option has been removed.") + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; + + port = 9617; + extraOpts = { + apiToken = mkOption { + type = types.str; + default = ""; + example = "580a770cb40511eb85290242ac130003580a770cb40511eb85290242ac130003"; + description = lib.mdDoc '' + Pi-Hole API token which can be used instead of a password + ''; + }; + password = mkOption { + type = types.str; + default = ""; + example = "password"; + description = lib.mdDoc '' + The password to login into Pi-Hole. An api token can be used instead. + ''; + }; + piholeHostname = mkOption { + type = types.str; + default = "pihole"; + example = "127.0.0.1"; + description = lib.mdDoc '' + Hostname or address where to find the Pi-Hole webinterface + ''; + }; + piholePort = mkOption { + type = types.port; + default = 80; + example = 443; + description = lib.mdDoc '' + The port Pi-Hole webinterface is reachable on + ''; + }; + protocol = mkOption { + type = types.enum [ "http" "https" ]; + default = "http"; + example = "https"; + description = lib.mdDoc '' + The protocol which is used to connect to Pi-Hole + ''; + }; + timeout = mkOption { + type = types.str; + default = "5s"; + description = lib.mdDoc '' + Controls the timeout to connect to a Pi-Hole instance + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-pihole-exporter}/bin/pihole-exporter \ + ${optionalString (cfg.apiToken != "") "-pihole_api_token ${cfg.apiToken}"} \ + -pihole_hostname ${cfg.piholeHostname} \ + ${optionalString (cfg.password != "") "-pihole_password ${cfg.password}"} \ + -pihole_port ${toString cfg.piholePort} \ + -pihole_protocol ${cfg.protocol} \ + -port ${toString cfg.port} \ + -timeout ${cfg.timeout} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix new file mode 100644 index 000000000000..9f402b123110 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix @@ -0,0 +1,100 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.postfix; +in +{ + port = 9154; + extraOpts = { + group = mkOption { + type = types.str; + description = lib.mdDoc '' + Group under which the postfix exporter shall be run. + It should match the group that is allowed to access the + `showq` socket in the `queue/public/` directory. + Defaults to `services.postfix.setgidGroup` when postfix is enabled. + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + logfilePath = mkOption { + type = types.path; + default = "/var/log/postfix_exporter_input.log"; + example = "/var/log/mail.log"; + description = lib.mdDoc '' + Path where Postfix writes log entries. + This file will be truncated by this exporter! + ''; + }; + showqPath = mkOption { + type = types.path; + default = "/var/lib/postfix/queue/public/showq"; + example = "/var/spool/postfix/public/showq"; + description = lib.mdDoc '' + Path where Postfix places its showq socket. + ''; + }; + systemd = { + enable = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Whether to enable reading metrics from the systemd journal instead of from a logfile + ''; + }; + unit = mkOption { + type = types.str; + default = "postfix.service"; + description = lib.mdDoc '' + Name of the postfix systemd unit. + ''; + }; + slice = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc '' + Name of the postfix systemd slice. + This overrides the {option}`systemd.unit`. + ''; + }; + journalPath = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to the systemd journal. + ''; + }; + }; + }; + serviceOpts = { + after = mkIf cfg.systemd.enable [ cfg.systemd.unit ]; + serviceConfig = { + DynamicUser = false; + # By default, each prometheus exporter only gets AF_INET & AF_INET6, + # but AF_UNIX is needed to read from the `showq`-socket. + RestrictAddressFamilies = [ "AF_UNIX" ]; + SupplementaryGroups = mkIf cfg.systemd.enable [ "systemd-journal" ]; + ExecStart = '' + ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + --postfix.showq_path ${escapeShellArg cfg.showqPath} \ + ${concatStringsSep " \\\n " (cfg.extraFlags + ++ optional cfg.systemd.enable "--systemd.enable" + ++ optional cfg.systemd.enable (if cfg.systemd.slice != null + then "--systemd.slice ${cfg.systemd.slice}" + else "--systemd.unit ${cfg.systemd.unit}") + ++ optional (cfg.systemd.enable && (cfg.systemd.journalPath != null)) + "--systemd.journal_path ${escapeShellArg cfg.systemd.journalPath}" + ++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${escapeShellArg cfg.logfilePath}")} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postgres.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postgres.nix new file mode 100644 index 000000000000..755d771ecdff --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postgres.nix @@ -0,0 +1,86 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.postgres; +in +{ + port = 9187; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + dataSourceName = mkOption { + type = types.str; + default = "user=postgres database=postgres host=/run/postgresql sslmode=disable"; + example = "postgresql://username:password@localhost:5432/postgres?sslmode=disable"; + description = lib.mdDoc '' + Accepts PostgreSQL URI form and key=value form arguments. + ''; + }; + runAsLocalSuperUser = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Whether to run the exporter as the local 'postgres' super user. + ''; + }; + + # TODO perhaps LoadCredential would be more appropriate + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/root/prometheus-postgres-exporter.env"; + description = lib.mdDoc '' + Environment file as defined in {manpage}`systemd.exec(5)`. + + Secrets may be passed to the service without adding them to the + world-readable Nix store, by specifying placeholder variables as + the option value in Nix and setting these variables accordingly in the + environment file. + + Environment variables from this file will be interpolated into the + config file using envsubst with this syntax: + `$ENVIRONMENT ''${VARIABLE}` + + The main use is to set the DATA_SOURCE_NAME that contains the + postgres password + + note that contents from this file will override dataSourceName + if you have set it from nix. + + ``` + # Content of the environment file + DATA_SOURCE_NAME=postgresql://username:password@localhost:5432/postgres?sslmode=disable + ``` + + Note that this file needs to be available on the host on which + this exporter is running. + ''; + }; + + }; + serviceOpts = { + environment.DATA_SOURCE_NAME = cfg.dataSourceName; + serviceConfig = { + DynamicUser = false; + User = mkIf cfg.runAsLocalSuperUser (mkForce "postgres"); + EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + ExecStart = '' + ${pkgs.prometheus-postgres-exporter}/bin/postgres_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/process.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/process.nix new file mode 100644 index 000000000000..278d6cd78074 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/process.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.process; + configFile = pkgs.writeText "process-exporter.yaml" (builtins.toJSON cfg.settings); +in +{ + port = 9256; + extraOpts = { + settings.process_names = mkOption { + type = types.listOf types.anything; + default = []; + example = literalExpression '' + [ + # Remove nix store path from process name + { name = "{{.Matches.Wrapped}} {{ .Matches.Args }}"; cmdline = [ "^/nix/store[^ ]*/(?P<Wrapped>[^ /]*) (?P<Args>.*)" ]; } + ] + ''; + description = lib.mdDoc '' + All settings expressed as an Nix attrset. + + Check the official documentation for the corresponding YAML + settings that can all be used here: <https://github.com/ncabatoff/process-exporter> + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + ExecStart = '' + ${pkgs.prometheus-process-exporter}/bin/process-exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --config.path ${configFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + NoNewPrivileges = true; + ProtectHome = true; + ProtectSystem = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix new file mode 100644 index 000000000000..20ee2e4b3238 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pve.nix @@ -0,0 +1,112 @@ +{ config, lib, pkgs, options }: + +with lib; +let + cfg = config.services.prometheus.exporters.pve; + + # pve exporter requires a config file so create an empty one if configFile is not provided + emptyConfigFile = pkgs.writeTextFile { + name = "pve.yml"; + text = "default:"; + }; + + computedConfigFile = if cfg.configFile == null then emptyConfigFile else cfg.configFile; +in +{ + port = 9221; + extraOpts = { + package = mkPackageOption pkgs "prometheus-pve-exporter" { }; + + environmentFile = mkOption { + type = with types; nullOr path; + default = null; + example = "/etc/prometheus-pve-exporter/pve.env"; + description = lib.mdDoc '' + Path to the service's environment file. This path can either be a computed path in /nix/store or a path in the local filesystem. + + The environment file should NOT be stored in /nix/store as it contains passwords and/or keys in plain text. + + Environment reference: https://github.com/prometheus-pve/prometheus-pve-exporter#authentication + ''; + }; + + configFile = mkOption { + type = with types; nullOr path; + default = null; + example = "/etc/prometheus-pve-exporter/pve.yml"; + description = lib.mdDoc '' + Path to the service's config file. This path can either be a computed path in /nix/store or a path in the local filesystem. + + The config file should NOT be stored in /nix/store as it will contain passwords and/or keys in plain text. + + If both configFile and environmentFile are provided, the configFile option will be ignored. + + Configuration reference: https://github.com/prometheus-pve/prometheus-pve-exporter/#authentication + ''; + }; + + collectors = { + status = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Collect Node/VM/CT status + ''; + }; + version = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Collect PVE version info + ''; + }; + node = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Collect PVE node info + ''; + }; + cluster = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Collect PVE cluster info + ''; + }; + resources = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Collect PVE resources info + ''; + }; + config = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Collect PVE onboot status + ''; + }; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = cfg.environmentFile == null; + LoadCredential = "configFile:${computedConfigFile}"; + ExecStart = '' + ${cfg.package}/bin/pve_exporter \ + --${optionalString (!cfg.collectors.status) "no-"}collector.status \ + --${optionalString (!cfg.collectors.version) "no-"}collector.version \ + --${optionalString (!cfg.collectors.node) "no-"}collector.node \ + --${optionalString (!cfg.collectors.cluster) "no-"}collector.cluster \ + --${optionalString (!cfg.collectors.resources) "no-"}collector.resources \ + --${optionalString (!cfg.collectors.config) "no-"}collector.config \ + %d/configFile \ + ${toString cfg.port} ${cfg.listenAddress} + ''; + } // optionalAttrs (cfg.environmentFile != null) { + EnvironmentFile = cfg.environmentFile; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix new file mode 100644 index 000000000000..f03b3c4df916 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/py-air-control.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.py-air-control; + + workingDir = "/var/lib/${cfg.stateDir}"; + +in +{ + port = 9896; + extraOpts = { + deviceHostname = mkOption { + type = types.str; + example = "192.168.1.123"; + description = lib.mdDoc '' + The hostname of the air purification device from which to scrape the metrics. + ''; + }; + protocol = mkOption { + type = types.str; + default = "http"; + description = lib.mdDoc '' + The protocol to use when communicating with the air purification device. + Available: [http, coap, plain_coap] + ''; + }; + stateDir = mkOption { + type = types.str; + default = "prometheus-py-air-control-exporter"; + description = lib.mdDoc '' + Directory below `/var/lib` to store runtime data. + This directory will be created automatically using systemd's StateDirectory mechanism. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + StateDirectory = cfg.stateDir; + WorkingDirectory = workingDir; + ExecStart = '' + ${pkgs.python3Packages.py-air-control-exporter}/bin/py-air-control-exporter \ + --host ${cfg.deviceHostname} \ + --protocol ${cfg.protocol} \ + --listen-port ${toString cfg.port} \ + --listen-address ${cfg.listenAddress} + ''; + Environment = [ "HOME=${workingDir}" ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/redis.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/redis.nix new file mode 100644 index 000000000000..befbcb21f766 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/redis.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.redis; +in +{ + port = 9121; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-redis-exporter}/bin/redis_exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix new file mode 100644 index 000000000000..f9dcfad07d30 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rspamd.nix @@ -0,0 +1,97 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.rspamd; + + mkFile = conf: + pkgs.writeText "rspamd-exporter-config.yml" (builtins.toJSON conf); + + generateConfig = extraLabels: { + modules.default.metrics = (map (path: { + name = "rspamd_${replaceStrings [ "[" "." " " "]" "\\" "'" ] [ "_" "_" "_" "" "" "" ] path}"; + path = "{ .${path} }"; + labels = extraLabels; + }) [ + "actions['add\\ header']" + "actions['no\\ action']" + "actions['rewrite\\ subject']" + "actions['soft\\ reject']" + "actions.greylist" + "actions.reject" + "bytes_allocated" + "chunks_allocated" + "chunks_freed" + "chunks_oversized" + "connections" + "control_connections" + "ham_count" + "learned" + "pools_allocated" + "pools_freed" + "read_only" + "scanned" + "shared_chunks_allocated" + "spam_count" + "total_learns" + ]) ++ [{ + name = "rspamd_statfiles"; + type = "object"; + path = "{.statfiles[*]}"; + labels = recursiveUpdate { + symbol = "{.symbol}"; + type = "{.type}"; + } extraLabels; + values = { + revision = "{.revision}"; + size = "{.size}"; + total = "{.total}"; + used = "{.used}"; + languages = "{.languages}"; + users = "{.users}"; + }; + }]; + }; +in +{ + port = 7980; + extraOpts = { + extraLabels = mkOption { + type = types.attrsOf types.str; + default = { + host = config.networking.hostName; + }; + defaultText = literalExpression "{ host = config.networking.hostName; }"; + example = literalExpression '' + { + host = config.networking.hostName; + custom_label = "some_value"; + } + ''; + description = lib.mdDoc "Set of labels added to each metric."; + }; + }; + serviceOpts.serviceConfig.ExecStart = '' + ${pkgs.prometheus-json-exporter}/bin/json_exporter \ + --config.file ${mkFile (generateConfig cfg.extraLabels)} \ + --web.listen-address "${cfg.listenAddress}:${toString cfg.port}" \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + + imports = [ + (mkRemovedOptionModule [ "url" ] '' + This option was removed. The URL of the rspamd metrics endpoint + must now be provided to the exporter by prometheus via the url + parameter `target'. + + In prometheus a scrape URL would look like this: + + http://some.rspamd-exporter.host:7980/probe?target=http://some.rspamd.host:11334/stat + + For more information, take a look at the official documentation + (https://github.com/prometheus-community/json_exporter) of the json_exporter. + '') + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix new file mode 100644 index 000000000000..1f7235cb7830 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, options }: + +let + cfg = config.services.prometheus.exporters.rtl_433; +in +{ + port = 9550; + + extraOpts = let + mkMatcherOptionType = field: description: with lib.types; + listOf (submodule { + options = { + name = lib.mkOption { + type = str; + description = lib.mdDoc "Name to match."; + }; + "${field}" = lib.mkOption { + type = int; + description = lib.mdDoc description; + }; + location = lib.mkOption { + type = str; + description = lib.mdDoc "Location to match."; + }; + }; + }); + in + { + rtl433Flags = lib.mkOption { + type = lib.types.str; + default = "-C si"; + example = "-C si -R 19"; + description = lib.mdDoc '' + Flags passed verbatim to rtl_433 binary. + Having `-C si` (the default) is recommended since only Celsius temperatures are parsed. + ''; + }; + channels = lib.mkOption { + type = mkMatcherOptionType "channel" "Channel to match."; + default = []; + example = [ + { name = "Acurite"; channel = 6543; location = "Kitchen"; } + ]; + description = lib.mdDoc '' + List of channel matchers to export. + ''; + }; + ids = lib.mkOption { + type = mkMatcherOptionType "id" "ID to match."; + default = []; + example = [ + { name = "Nexus"; id = 1; location = "Bedroom"; } + ]; + description = lib.mdDoc '' + List of ID matchers to export. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + # rtl-sdr udev rules make supported USB devices +rw by plugdev. + SupplementaryGroups = "plugdev"; + # rtl_433 needs rw access to the USB radio. + PrivateDevices = lib.mkForce false; + DeviceAllow = lib.mkForce "char-usb_device rw"; + RestrictAddressFamilies = [ "AF_NETLINK" ]; + + ExecStart = let + matchers = (map (m: + "--channel_matcher '${m.name},${toString m.channel},${m.location}'" + ) cfg.channels) ++ (map (m: + "--id_matcher '${m.name},${toString m.id},${m.location}'" + ) cfg.ids); in '' + ${pkgs.prometheus-rtl_433-exporter}/bin/rtl_433_prometheus \ + -listen ${cfg.listenAddress}:${toString cfg.port} \ + -subprocess "${pkgs.rtl_433}/bin/rtl_433 -F json ${cfg.rtl433Flags}" \ + ${lib.concatStringsSep " \\\n " matchers} \ + ${lib.concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix new file mode 100644 index 000000000000..411277494013 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix @@ -0,0 +1,47 @@ +{ config, lib, pkgs, options }: + +let + inherit (lib) mkOption types; + cfg = config.services.prometheus.exporters.sabnzbd; +in +{ + port = 9387; + + extraOpts = { + servers = mkOption { + description = "List of sabnzbd servers to connect to."; + type = types.listOf (types.submodule { + options = { + baseUrl = mkOption { + type = types.str; + description = "Base URL of the sabnzbd server."; + example = "http://localhost:8080/sabnzbd"; + }; + apiKeyFile = mkOption { + type = types.str; + description = "File containing the API key."; + example = "/run/secrets/sabnzbd_apikey"; + }; + }; + }); + }; + }; + + serviceOpts = + let + servers = lib.zipAttrs cfg.servers; + apiKeys = lib.concatStringsSep "," (builtins.map (file: "$(cat ${file})") servers.apiKeyFile); + in + { + environment = { + METRICS_PORT = toString cfg.port; + METRICS_ADDR = cfg.listenAddress; + SABNZBD_BASEURLS = lib.concatStringsSep "," servers.baseUrl; + }; + + script = '' + export SABNZBD_APIKEYS="${apiKeys}" + exec ${lib.getExe pkgs.prometheus-sabnzbd-exporter} + ''; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix new file mode 100644 index 000000000000..3b6ebf65b090 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/scaphandre.nix @@ -0,0 +1,33 @@ +{ config +, lib +, pkgs +, options +}: + +let + logPrefix = "services.prometheus.exporter.scaphandre"; + cfg = config.services.prometheus.exporters.scaphandre; +in { + port = 8080; + extraOpts = { + telemetryPath = lib.mkOption { + type = lib.types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.scaphandre}/bin/scaphandre prometheus \ + --address ${cfg.listenAddress} \ + --port ${toString cfg.port} \ + --suffix ${cfg.telemetryPath} \ + ${lib.concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/script.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/script.nix new file mode 100644 index 000000000000..eab0e1d8a6b5 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/script.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.script; + configFile = pkgs.writeText "script-exporter.yaml" (builtins.toJSON cfg.settings); +in +{ + port = 9172; + extraOpts = { + settings.scripts = mkOption { + type = with types; listOf (submodule { + options = { + name = mkOption { + type = str; + example = "sleep"; + description = lib.mdDoc "Name of the script."; + }; + script = mkOption { + type = str; + example = "sleep 5"; + description = lib.mdDoc "Shell script to execute when metrics are requested."; + }; + timeout = mkOption { + type = nullOr int; + default = null; + example = 60; + description = lib.mdDoc "Optional timeout for the script in seconds."; + }; + }; + }); + example = literalExpression '' + { + scripts = [ + { name = "sleep"; script = "sleep 5"; } + ]; + } + ''; + description = lib.mdDoc '' + All settings expressed as an Nix attrset. + + Check the official documentation for the corresponding YAML + settings that can all be used here: <https://github.com/adhocteam/script_exporter#sample-configuration> + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-script-exporter}/bin/script_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --config.file ${configFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + NoNewPrivileges = true; + ProtectHome = true; + ProtectSystem = "strict"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/shelly.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/shelly.nix new file mode 100644 index 000000000000..b9cfd1b1e84a --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/shelly.nix @@ -0,0 +1,27 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.shelly; +in +{ + port = 9784; + extraOpts = { + metrics-file = mkOption { + type = types.path; + description = lib.mdDoc '' + Path to the JSON file with the metric definitions + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-shelly-exporter}/bin/shelly_exporter \ + -metrics-file ${cfg.metrics-file} \ + -listen-address ${cfg.listenAddress}:${toString cfg.port} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix new file mode 100644 index 000000000000..50e1321a1e9c --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.smartctl; + args = lib.escapeShellArgs ([ + "--web.listen-address=${cfg.listenAddress}:${toString cfg.port}" + "--smartctl.path=${pkgs.smartmontools}/bin/smartctl" + "--smartctl.interval=${cfg.maxInterval}" + ] ++ map (device: "--smartctl.device=${device}") cfg.devices + ++ cfg.extraFlags); +in { + port = 9633; + + extraOpts = { + devices = mkOption { + type = types.listOf types.str; + default = []; + example = literalExpression '' + [ "/dev/sda", "/dev/nvme0n1" ]; + ''; + description = lib.mdDoc '' + Paths to the disks that will be monitored. Will autodiscover + all disks if none given. + ''; + }; + maxInterval = mkOption { + type = types.str; + default = "60s"; + example = "2m"; + description = lib.mdDoc '' + Interval that limits how often a disk can be queried. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + AmbientCapabilities = [ + "CAP_SYS_RAWIO" + "CAP_SYS_ADMIN" + ]; + CapabilityBoundingSet = [ + "CAP_SYS_RAWIO" + "CAP_SYS_ADMIN" + ]; + DevicePolicy = "closed"; + DeviceAllow = lib.mkOverride 50 [ + "block-blkext rw" + "block-sd rw" + "char-nvme rw" + ]; + ExecStart = '' + ${pkgs.prometheus-smartctl-exporter}/bin/smartctl_exporter ${args} + ''; + PrivateDevices = lib.mkForce false; + ProtectProc = "invisible"; + ProcSubset = "pid"; + SupplementaryGroups = [ "disk" ]; + SystemCallFilter = [ "@system-service" "~@privileged" ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix new file mode 100644 index 000000000000..459f5842f546 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/smokeping.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.smokeping; + goDuration = types.mkOptionType { + name = "goDuration"; + description = "Go duration (https://golang.org/pkg/time/#ParseDuration)"; + check = x: types.str.check x && builtins.match "(-?[0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+" x != null; + inherit (types.str) merge; + }; +in +{ + port = 9374; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + pingInterval = mkOption { + type = goDuration; + default = "1s"; + description = lib.mdDoc '' + Interval between pings. + ''; + }; + buckets = mkOption { + type = types.commas; + default = "5e-05,0.0001,0.0002,0.0004,0.0008,0.0016,0.0032,0.0064,0.0128,0.0256,0.0512,0.1024,0.2048,0.4096,0.8192,1.6384,3.2768,6.5536,13.1072,26.2144"; + description = lib.mdDoc '' + List of buckets to use for the response duration histogram. + ''; + }; + hosts = mkOption { + type = with types; listOf str; + description = lib.mdDoc '' + List of endpoints to probe. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + AmbientCapabilities = [ "CAP_NET_RAW" ]; + CapabilityBoundingSet = [ "CAP_NET_RAW" ]; + ExecStart = '' + ${pkgs.prometheus-smokeping-prober}/bin/smokeping_prober \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + --buckets ${cfg.buckets} \ + --ping.interval ${cfg.pingInterval} \ + --privileged \ + ${concatStringsSep " \\\n " cfg.extraFlags} \ + ${concatStringsSep " " cfg.hosts} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix new file mode 100644 index 000000000000..edc6e4b5022a --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix @@ -0,0 +1,68 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.snmp; +in +{ + port = 9116; + extraOpts = { + configurationPath = mkOption { + type = types.nullOr types.path; + default = null; + description = lib.mdDoc '' + Path to a snmp exporter configuration file. Mutually exclusive with 'configuration' option. + ''; + example = literalExpression "./snmp.yml"; + }; + + configuration = mkOption { + type = types.nullOr types.attrs; + default = null; + description = lib.mdDoc '' + Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option. + ''; + example = { + "default" = { + "version" = 2; + "auth" = { + "community" = "public"; + }; + }; + }; + }; + + logFormat = mkOption { + type = types.enum ["logfmt" "json"]; + default = "logfmt"; + description = lib.mdDoc '' + Output format of log messages. + ''; + }; + + logLevel = mkOption { + type = types.enum ["debug" "info" "warn" "error"]; + default = "info"; + description = lib.mdDoc '' + Only log messages with the given severity or above. + ''; + }; + }; + serviceOpts = let + configFile = if cfg.configurationPath != null + then cfg.configurationPath + else "${pkgs.writeText "snmp-exporter-conf.yml" (builtins.toJSON cfg.configuration)}"; + in { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-snmp-exporter}/bin/snmp_exporter \ + --config.file=${escapeShellArg configFile} \ + --log.format=${escapeShellArg cfg.logFormat} \ + --log.level=${cfg.logLevel} \ + --web.listen-address=${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix new file mode 100644 index 000000000000..678bc348679d --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix @@ -0,0 +1,108 @@ +{ config, lib, pkgs, options }: +with lib; +let + cfg = config.services.prometheus.exporters.sql; + cfgOptions = { + options = with types; { + jobs = mkOption { + type = attrsOf (submodule jobOptions); + default = { }; + description = lib.mdDoc "An attrset of metrics scraping jobs to run."; + }; + }; + }; + jobOptions = { + options = with types; { + interval = mkOption { + type = str; + description = lib.mdDoc '' + How often to run this job, specified in + [Go duration](https://golang.org/pkg/time/#ParseDuration) format. + ''; + }; + connections = mkOption { + type = listOf str; + description = lib.mdDoc "A list of connection strings of the SQL servers to scrape metrics from"; + }; + startupSql = mkOption { + type = listOf str; + default = []; + description = lib.mdDoc "A list of SQL statements to execute once after making a connection."; + }; + queries = mkOption { + type = attrsOf (submodule queryOptions); + description = lib.mdDoc "SQL queries to run."; + }; + }; + }; + queryOptions = { + options = with types; { + help = mkOption { + type = nullOr str; + default = null; + description = lib.mdDoc "A human-readable description of this metric."; + }; + labels = mkOption { + type = listOf str; + default = [ ]; + description = lib.mdDoc "A set of columns that will be used as Prometheus labels."; + }; + query = mkOption { + type = str; + description = lib.mdDoc "The SQL query to run."; + }; + values = mkOption { + type = listOf str; + description = lib.mdDoc "A set of columns that will be used as values of this metric."; + }; + }; + }; + + configFile = + if cfg.configFile != null + then cfg.configFile + else + let + nameInline = mapAttrsToList (k: v: v // { name = k; }); + renameStartupSql = j: removeAttrs (j // { startup_sql = j.startupSql; }) [ "startupSql" ]; + configuration = { + jobs = map renameStartupSql + (nameInline (mapAttrs (k: v: (v // { queries = nameInline v.queries; })) cfg.configuration.jobs)); + }; + in + builtins.toFile "config.yaml" (builtins.toJSON configuration); +in +{ + extraOpts = { + configFile = mkOption { + type = with types; nullOr path; + default = null; + description = lib.mdDoc '' + Path to configuration file. + ''; + }; + configuration = mkOption { + type = with types; nullOr (submodule cfgOptions); + default = null; + description = lib.mdDoc '' + Exporter configuration as nix attribute set. Mutually exclusive with 'configFile' option. + ''; + }; + }; + + port = 9237; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-sql-exporter}/bin/sql_exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -config.file ${configFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/statsd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/statsd.nix new file mode 100644 index 000000000000..d9d732d8c125 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/statsd.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.statsd; +in +{ + port = 9102; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-statsd-exporter}/bin/statsd_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix new file mode 100644 index 000000000000..b1d6760b40b3 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.surfboard; +in +{ + port = 9239; + extraOpts = { + modemAddress = mkOption { + type = types.str; + default = "192.168.100.1"; + description = lib.mdDoc '' + The hostname or IP of the cable modem. + ''; + }; + }; + serviceOpts = { + description = "Prometheus exporter for surfboard cable modem"; + unitConfig.Documentation = "https://github.com/ipstatic/surfboard_exporter"; + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-surfboard-exporter}/bin/surfboard_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --modem-address ${cfg.modemAddress} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix new file mode 100644 index 000000000000..2edd1de83e1b --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix @@ -0,0 +1,22 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let cfg = config.services.prometheus.exporters.systemd; + +in { + port = 9558; + + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-systemd-exporter}/bin/systemd_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} ${concatStringsSep " " cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + # Need AF_UNIX to collect data + "AF_UNIX" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix new file mode 100644 index 000000000000..7a9167110a27 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.tor; +in +{ + port = 9130; + extraOpts = { + torControlAddress = mkOption { + type = types.str; + default = "127.0.0.1"; + description = lib.mdDoc '' + Tor control IP address or hostname. + ''; + }; + + torControlPort = mkOption { + type = types.port; + default = 9051; + description = lib.mdDoc '' + Tor control port. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-tor-exporter}/bin/prometheus-tor-exporter \ + -b ${cfg.listenAddress} \ + -p ${toString cfg.port} \ + -a ${cfg.torControlAddress} \ + -c ${toString cfg.torControlPort} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + + # CPython requires a process to either have $HOME defined or run as a UID + # defined in /etc/passwd. The latter is false with DynamicUser, so define a + # dummy $HOME. https://bugs.python.org/issue10496 + environment = { HOME = "/var/empty"; }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unbound.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unbound.nix new file mode 100644 index 000000000000..f2336429d42f --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unbound.nix @@ -0,0 +1,95 @@ +{ config +, lib +, pkgs +, options +}: + +with lib; + +let + cfg = config.services.prometheus.exporters.unbound; +in +{ + imports = [ + (mkRemovedOptionModule [ "controlInterface" ] "This option was removed, use the `unbound.host` option instead.") + (mkRemovedOptionModule [ "fetchType" ] "This option was removed, use the `unbound.host` option instead.") + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; + + port = 9167; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + + unbound = { + ca = mkOption { + type = types.nullOr types.path; + default = "/var/lib/unbound/unbound_server.pem"; + example = null; + description = '' + Path to the Unbound server certificate authority + ''; + }; + + certificate = mkOption { + type = types.nullOr types.path; + default = "/var/lib/unbound/unbound_control.pem"; + example = null; + description = '' + Path to the Unbound control socket certificate + ''; + }; + + key = mkOption { + type = types.nullOr types.path; + default = "/var/lib/unbound/unbound_control.key"; + example = null; + description = '' + Path to the Unbound control socket key. + ''; + }; + + host = mkOption { + type = types.str; + default = "tcp://127.0.0.1:8953"; + example = "unix:///run/unbound/unbound.socket"; + description = lib.mdDoc '' + Path to the unbound control socket. Supports unix domain sockets, as well as the TCP interface. + ''; + }; + }; + }; + + serviceOpts = mkMerge ([{ + serviceConfig = { + User = "unbound"; # to access the unbound_control.key + ExecStart = '' + ${pkgs.prometheus-unbound-exporter}/bin/unbound_exporter \ + --unbound.host "${cfg.unbound.host}" \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${optionalString (cfg.unbound.ca != null) "--unbound.ca ${cfg.unbound.ca}"} \ + ${optionalString (cfg.unbound.certificate != null) "--unbound.cert ${cfg.unbound.certificate}"} \ + ${optionalString (cfg.unbound.key != null) "--unbound.key ${cfg.unbound.key}"} \ + ${toString cfg.extraFlags} + ''; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + ]; + } // optionalAttrs (!config.services.unbound.enable) { + DynamicUser = true; + }; + }] ++ [ + (mkIf config.services.unbound.enable { + after = [ "unbound.service" ]; + requires = [ "unbound.service" ]; + }) + ]); +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix new file mode 100644 index 000000000000..70f26d9783be --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix @@ -0,0 +1,66 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.unifi; +in +{ + port = 9130; + extraOpts = { + unifiAddress = mkOption { + type = types.str; + example = "https://10.0.0.1:8443"; + description = lib.mdDoc '' + URL of the UniFi Controller API. + ''; + }; + + unifiInsecure = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + If enabled skip the verification of the TLS certificate of the UniFi Controller API. + Use with caution. + ''; + }; + + unifiUsername = mkOption { + type = types.str; + example = "ReadOnlyUser"; + description = lib.mdDoc '' + username for authentication against UniFi Controller API. + ''; + }; + + unifiPassword = mkOption { + type = types.str; + description = lib.mdDoc '' + Password for authentication against UniFi Controller API. + ''; + }; + + unifiTimeout = mkOption { + type = types.str; + default = "5s"; + example = "2m"; + description = lib.mdDoc '' + Timeout including unit for UniFi Controller API requests. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \ + -telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \ + -unifi.addr ${cfg.unifiAddress} \ + -unifi.username ${escapeShellArg cfg.unifiUsername} \ + -unifi.password ${escapeShellArg cfg.unifiPassword} \ + -unifi.timeout ${cfg.unifiTimeout} \ + ${optionalString cfg.unifiInsecure "-unifi.insecure" } \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unpoller.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unpoller.nix new file mode 100644 index 000000000000..3b7f978528cd --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unpoller.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.unpoller; + + configFile = pkgs.writeText "prometheus-unpoller-exporter.json" (generators.toJSON {} { + poller = { inherit (cfg.log) debug quiet; }; + unifi = { inherit (cfg) controllers; }; + influxdb.disable = true; + datadog.disable = true; # workaround for https://github.com/unpoller/unpoller/issues/442 + prometheus = { + http_listen = "${cfg.listenAddress}:${toString cfg.port}"; + report_errors = cfg.log.prometheusErrors; + }; + inherit (cfg) loki; + }); + +in { + port = 9130; + + extraOpts = { + inherit (options.services.unpoller.unifi) controllers; + inherit (options.services.unpoller) loki; + log = { + debug = mkEnableOption (lib.mdDoc "debug logging including line numbers, high resolution timestamps, per-device logs"); + quiet = mkEnableOption (lib.mdDoc "startup and error logs only"); + prometheusErrors = mkEnableOption (lib.mdDoc "emitting errors to prometheus"); + }; + }; + + serviceOpts.serviceConfig = { + ExecStart = "${pkgs.unpoller}/bin/unpoller --config ${configFile}"; + DynamicUser = false; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix new file mode 100644 index 000000000000..a019157c664b --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/v2ray.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.v2ray; +in +{ + port = 9299; + extraOpts = { + v2rayEndpoint = mkOption { + type = types.str; + default = "127.0.0.1:54321"; + description = lib.mdDoc '' + v2ray grpc api endpoint + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-v2ray-exporter}/bin/v2ray-exporter \ + --v2ray-endpoint ${cfg.v2rayEndpoint} \ + --listen ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix new file mode 100644 index 000000000000..a7e5b41dffc6 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix @@ -0,0 +1,89 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.varnish; +in +{ + port = 9131; + extraOpts = { + noExit = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Do not exit server on Varnish scrape errors. + ''; + }; + withGoMetrics = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Export go runtime and http handler metrics. + ''; + }; + verbose = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Enable verbose logging. + ''; + }; + raw = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Enable raw stdout logging without timestamps. + ''; + }; + varnishStatPath = mkOption { + type = types.str; + default = "varnishstat"; + description = lib.mdDoc '' + Path to varnishstat. + ''; + }; + instance = mkOption { + type = types.nullOr types.str; + default = config.services.varnish.stateDir; + defaultText = lib.literalExpression "config.services.varnish.stateDir"; + description = lib.mdDoc '' + varnishstat -n value. + ''; + }; + healthPath = mkOption { + type = types.nullOr types.str; + default = null; + description = lib.mdDoc '' + Path under which to expose healthcheck. Disabled unless configured. + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + }; + serviceOpts = { + path = [ config.services.varnish.package ]; + serviceConfig = { + RestartSec = mkDefault 1; + DynamicUser = false; + ExecStart = '' + ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + --varnishstat-path ${escapeShellArg cfg.varnishStatPath} \ + ${concatStringsSep " \\\n " (cfg.extraFlags + ++ optional (cfg.healthPath != null) "--web.health-path ${cfg.healthPath}" + ++ optional (cfg.instance != null) "-n ${escapeShellArg cfg.instance}" + ++ optional cfg.noExit "--no-exit" + ++ optional cfg.withGoMetrics "--with-go-metrics" + ++ optional cfg.verbose "--verbose" + ++ optional cfg.raw "--raw")} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix new file mode 100644 index 000000000000..9b7590314936 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix @@ -0,0 +1,71 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.wireguard; +in { + port = 9586; + imports = [ + (mkRenamedOptionModule [ "addr" ] [ "listenAddress" ]) + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; + extraOpts = { + verbose = mkEnableOption (lib.mdDoc "verbose logging mode for prometheus-wireguard-exporter"); + + wireguardConfig = mkOption { + type = with types; nullOr (either path str); + default = null; + + description = lib.mdDoc '' + Path to the Wireguard Config to + [add the peer's name to the stats of a peer](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/2.0.0#usage). + + Please note that `networking.wg-quick` is required for this feature + as `networking.wireguard` uses + {manpage}`wg(8)` + to set the peers up. + ''; + }; + + singleSubnetPerField = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + By default, all allowed IPs and subnets are comma-separated in the + `allowed_ips` field. With this option enabled, + a single IP and subnet will be listed in fields like `allowed_ip_0`, + `allowed_ip_1` and so on. + ''; + }; + + withRemoteIp = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Whether or not the remote IP of a WireGuard peer should be exposed via prometheus. + ''; + }; + }; + serviceOpts = { + path = [ pkgs.wireguard-tools ]; + + serviceConfig = { + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; + ExecStart = '' + ${pkgs.prometheus-wireguard-exporter}/bin/prometheus_wireguard_exporter \ + -p ${toString cfg.port} \ + -l ${cfg.listenAddress} \ + ${optionalString cfg.verbose "-v true"} \ + ${optionalString cfg.singleSubnetPerField "-s true"} \ + ${optionalString cfg.withRemoteIp "-r true"} \ + ${optionalString (cfg.wireguardConfig != null) "-n ${escapeShellArg cfg.wireguardConfig}"} + ''; + RestrictAddressFamilies = [ + # Need AF_NETLINK to collect data + "AF_NETLINK" + ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/zfs.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/zfs.nix new file mode 100644 index 000000000000..ff12a52d49a9 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/zfs.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.zfs; +in +{ + port = 9134; + + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = lib.mdDoc '' + Path under which to expose metrics. + ''; + }; + + pools = mkOption { + type = with types; nullOr (listOf str); + default = [ ]; + description = lib.mdDoc '' + Name of the pool(s) to collect, repeat for multiple pools (default: all pools). + ''; + }; + }; + + serviceOpts = { + # needs zpool + path = [ config.boot.zfs.package ]; + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-zfs-exporter}/bin/zfs_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${concatMapStringsSep " " (x: "--pool=${x}") cfg.pools} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + ProtectClock = false; + PrivateDevices = false; + }; + }; +} |