uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead

https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948
this can do it nicely.

Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
Anton Arapov 2021-04-03 12:58:10 +02:00 committed by Alan Daniels
commit 56de2bcd43
30691 changed files with 3076956 additions and 0 deletions

View file

@ -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 = ''
Address of the apcupsd Network Information Server (NIS).
'';
};
apcupsdNetwork = mkOption {
type = types.enum ["tcp" "tcp4" "tcp6"];
default = "tcp";
description = ''
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}
'';
};
};
}

View file

@ -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 = ''
URI on which to scrape JFrog Artifactory.
'';
};
artiUsername = mkOption {
type = types.str;
description = ''
Username for authentication against JFrog Artifactory API.
'';
};
artiPassword = mkOption {
type = types.str;
default = "";
description = ''
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 = ''
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}"
];
};
};
}

View file

@ -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 = ''
HTTP XML API address of an Bind server.
'';
};
bindTimeout = mkOption {
type = types.str;
default = "10s";
description = ''
Timeout for trying to get stats from Bind.
'';
};
bindVersion = mkOption {
type = types.enum [ "xml.v2" "xml.v3" "auto" ];
default = "auto";
description = ''
BIND statistics version. Can be detected automatically.
'';
};
bindGroups = mkOption {
type = types.listOf (types.enum [ "server" "view" "tasks" ]);
default = [ "server" "view" ];
description = ''
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}
'';
};
};
}

View file

@ -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 = ''
Specifies whether BIRD1 or BIRD2 is in use.
'';
};
birdSocket = mkOption {
type = types.path;
default = "/run/bird/bird.ctl";
description = ''
Path to BIRD2 (or BIRD1 v4) socket.
'';
};
newMetricFormat = mkOption {
type = types.bool;
default = true;
description = ''
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"
];
};
};
}

View file

@ -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 = ''
RPC user name.
'';
};
rpcPasswordFile = mkOption {
type = types.path;
description = ''
File containing RPC password.
'';
};
rpcScheme = mkOption {
type = types.enum [ "http" "https" ];
default = "http";
description = ''
Whether to connect to bitcoind over http or https.
'';
};
rpcHost = mkOption {
type = types.str;
default = "localhost";
description = ''
RPC host.
'';
};
rpcPort = mkOption {
type = types.port;
default = 8332;
description = ''
RPC port number.
'';
};
refreshSeconds = mkOption {
type = types.ints.unsigned;
default = 300;
description = ''
How often to ask bitcoind for metrics.
'';
};
extraEnv = mkOption {
type = types.attrsOf types.str;
default = {};
description = ''
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;
};
}

View file

@ -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
true;
checkConfig = file:
pkgs.runCommand "checked-blackbox-exporter.conf" {
preferLocalBuild = true;
buildInputs = [ 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 = ''
Path to configuration file.
'';
};
enableConfigCheck = mkOption {
type = types.bool;
default = true;
description = ''
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";
};
};
}

View file

@ -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 = ''
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 = ''
How often to update metrics.
'';
};
endpoint = mkOption {
type = types.str;
default = "https://agent.buildkite.com/v3";
description = ''
The Buildkite Agent API endpoint.
'';
};
queues = mkOption {
type = with types; nullOr (listOf str);
default = null;
example = literalExpression ''[ "my-queue1" "my-queue2" ]'';
description = ''
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";
};
};
}

View file

@ -0,0 +1,77 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.collectd;
in
{
port = 9103;
extraOpts = {
collectdBinary = {
enable = mkEnableOption "collectd binary protocol receiver";
authFile = mkOption {
default = null;
type = types.nullOr types.path;
description = "File mapping user names to pre-shared keys (passwords).";
};
port = mkOption {
type = types.int;
default = 25826;
description = "Network address on which to accept collectd binary network packets.";
};
listenAddress = mkOption {
type = types.str;
default = "0.0.0.0";
description = ''
Address to listen on for binary network packets.
'';
};
securityLevel = mkOption {
type = types.enum ["None" "Sign" "Encrypt"];
default = "None";
description = ''
Minimum required security level for accepted packets.
'';
};
};
logFormat = mkOption {
type = types.enum [ "logfmt" "json" ];
default = "logfmt";
example = "json";
description = ''
Set the log format.
'';
};
logLevel = mkOption {
type = types.enum ["debug" "info" "warn" "error" "fatal"];
default = "info";
description = ''
Only log messages with the given severity or above.
'';
};
};
serviceOpts = let
collectSettingsArgs = if (cfg.collectdBinary.enable) then ''
--collectd.listen-address ${cfg.collectdBinary.listenAddress}:${toString cfg.collectdBinary.port} \
--collectd.security-level ${cfg.collectdBinary.securityLevel} \
'' else "";
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}
'';
};
};
}

View file

@ -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 = ''
Hostname of IMAP server to connect to.
'';
};
port = mkOption {
type = types.port;
default = 993;
description = ''
Port of the IMAP server to connect to.
'';
};
username = mkOption {
type = types.str;
example = "postmaster@example.org";
description = ''
Login username for the IMAP connection.
'';
};
passwordFile = mkOption {
type = types.str;
example = "/run/secrets/dovecot_pw";
description = ''
File containing the login password for the IMAP connection.
'';
};
};
folders = {
inbox = mkOption {
type = types.str;
default = "INBOX";
description = ''
IMAP mailbox that is checked for incoming DMARC aggregate reports
'';
};
done = mkOption {
type = types.str;
default = "Archive";
description = ''
IMAP mailbox that successfully processed reports are moved to.
'';
};
error = mkOption {
type = types.str;
default = "Invalid";
description = ''
IMAP mailbox that emails are moved to that could not be processed.
'';
};
};
pollIntervalSeconds = mkOption {
type = types.ints.unsigned;
default = 60;
description = ''
How often to poll the IMAP server in seconds.
'';
};
deduplicationMaxSeconds = mkOption {
type = types.ints.unsigned;
default = 604800;
defaultText = "7 days (in seconds)";
description = ''
How long individual report IDs will be remembered to avoid
counting double delivered reports twice.
'';
};
debug = mkOption {
type = types.bool;
default = false;
description = ''
Whether to declare enable <literal>--debug</literal>.
'';
};
};
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"}
''}";
};
};
}

View file

@ -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 = ''
Address on which dnsmasq listens.
'';
};
leasesPath = mkOption {
type = types.path;
default = "/var/lib/misc/dnsmasq.leases";
example = "/var/lib/dnsmasq/dnsmasq.leases";
description = ''
Path to the <literal>dnsmasq.leases</literal> 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}
'';
};
};
}

View file

@ -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}
'';
};
};
}

View file

@ -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 = ''
Path under which to expose metrics.
'';
};
socketPath = mkOption {
type = types.path;
default = "/var/run/dovecot/stats";
example = "/var/run/dovecot2/old-stats";
description = ''
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
<link xlink:href="https://wiki2.dovecot.org/Upgrading/2.3">Dovecot 2.3+</link> which
is not <link xlink:href="https://github.com/kumina/dovecot_exporter/issues/8">compatible with this exporter</link>.
The following extra config has to be passed to Dovecot to ensure that recent versions
work with this exporter:
<programlisting>
{
<xref linkend="opt-services.prometheus.exporters.dovecot.enable" /> = true;
<xref linkend="opt-services.prometheus.exporters.dovecot.socketPath" /> = "/var/run/dovecot2/old-stats";
<xref linkend="opt-services.dovecot2.mailPlugins.globally.enable" /> = [ "old_stats" ];
<xref linkend="opt-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
}
''';
}
</programlisting>
'';
};
scopes = mkOption {
type = types.listOf types.str;
default = [ "user" ];
example = [ "user" "global" ];
description = ''
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"
];
};
};
}

View file

@ -0,0 +1,41 @@
{ config, lib, pkgs, options }:
with lib;
let cfg = config.services.prometheus.exporters.fastly;
in
{
port = 9118;
extraOpts = {
debug = mkEnableOption "Debug logging mode for fastly-exporter";
configFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to a fastly-exporter configuration file.
Example one can be generated with <literal>fastly-exporter --config-file-example</literal>.
'';
example = "./fastly-exporter-config.txt";
};
tokenPath = mkOption {
type = types.nullOr types.path;
apply = final: if final == null then null else toString final;
description = ''
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}"}
'';
};
}

View file

@ -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 = "List of Kafka brokers to connect to.";
};
asn = mkOption {
type = types.ints.positive;
example = 65542;
description = "The ASN being monitored.";
};
partitions = mkOption {
type = types.listOf types.int;
default = [];
description = ''
The number of the partitions to consume, none means all.
'';
};
topic = mkOption {
type = types.str;
example = "pmacct.acct";
description = "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}
'';
};
};
}

View file

@ -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 = ''
The hostname or IP of the FRITZ!Box.
'';
};
gatewayPort = mkOption {
type = types.int;
default = 49000;
description = ''
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}
'';
};
};
}

View file

@ -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 = "How long a sample is valid for";
};
udpBindAddress = mkOption {
type = types.str;
default = ":9122";
example = "192.0.2.1:9122";
description = "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}
'';
};
};
}

View file

@ -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 = ''
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 = ''
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}
'';
};
};
}

View file

@ -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 = ''
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; })
];
}

View file

@ -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/kea-dhcp4.socket"
"/run/kea/kea-dhcp6.socket"
]
'';
description = ''
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 " \\n" cfg.controlSocketPaths}
'';
SupplementaryGroups = [ "kea" ];
RestrictAddressFamilies = [
# Need AF_UNIX to collect data
"AF_UNIX"
];
};
};
}

View file

@ -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}
'';
};
};
}

View file

@ -0,0 +1,54 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.knot;
in {
port = 9433;
extraOpts = {
knotLibraryPath = mkOption {
type = types.str;
default = "${pkgs.knot-dns.out}/lib/libknot.so";
defaultText = literalExpression ''"''${pkgs.knot-dns.out}/lib/libknot.so"'';
description = ''
Path to the library of <package>knot-dns</package>.
'';
};
knotSocketPath = mkOption {
type = types.str;
default = "/run/knot/knot.sock";
description = ''
Socket path of <citerefentry><refentrytitle>knotd</refentrytitle>
<manvolnum>8</manvolnum></citerefentry>.
'';
};
knotSocketTimeout = mkOption {
type = types.int;
default = 2000;
description = ''
Timeout in seconds.
'';
};
};
serviceOpts = {
serviceConfig = {
ExecStart = ''
${pkgs.prometheus-knot-exporter}/bin/knot_exporter \
--web-listen-addr ${cfg.listenAddress} \
--web-listen-port ${toString cfg.port} \
--knot-library-path ${cfg.knotLibraryPath} \
--knot-socket-path ${cfg.knotSocketPath} \
--knot-socket-timeout ${toString cfg.knotSocketTimeout} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
SupplementaryGroups = [ "knot" ];
RestrictAddressFamilies = [
# Need AF_UNIX to collect data
"AF_UNIX"
];
};
};
}

View file

@ -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 = ''
lnd instance gRPC address:port.
'';
};
lndTlsPath = mkOption {
type = types.path;
description = ''
Path to lnd TLS certificate.
'';
};
lndMacaroonDir = mkOption {
type = types.path;
description = ''
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 ];
};
}

View file

@ -0,0 +1,176 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.mail;
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 = ''
Value for label 'configname' which will be added to all metrics.
'';
};
server = mkOption {
type = types.str;
description = ''
Hostname of the server that should be probed.
'';
};
port = mkOption {
type = types.int;
example = 587;
description = ''
Port to use for SMTP.
'';
};
from = mkOption {
type = types.str;
example = "exporteruser@domain.tld";
description = ''
Content of 'From' Header for probing mails.
'';
};
to = mkOption {
type = types.str;
example = "exporteruser@domain.tld";
description = ''
Content of 'To' Header for probing mails.
'';
};
detectionDir = mkOption {
type = types.path;
example = "/var/spool/mail/exporteruser/new";
description = ''
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 = ''
Username to use for SMTP authentication.
'';
};
passphrase = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Password to use for SMTP authentication.
'';
};
};
exporterOptions.options = {
monitoringInterval = mkOption {
type = types.str;
example = "10s";
description = ''
Time interval between two probe attempts.
'';
};
mailCheckTimeout = mkOption {
type = types.str;
description = ''
Timeout until mails are considered "didn't make it".
'';
};
disableFileDeletion = mkOption {
type = types.bool;
default = false;
description = ''
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 = ''
List of servers that should be probed.
<emphasis>Note:</emphasis> if your mailserver has <citerefentry>
<refentrytitle>rspamd</refentrytitle><manvolnum>8</manvolnum></citerefentry> 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:
<programlisting>
{
<link linkend="opt-services.rspamd.locals._name_.text">services.rspamd.locals."multimap.conf".text</link> = '''
ALLOWLIST_PROMETHEUS {
filter = "email:domain:tld";
type = "from";
map = "''${pkgs.writeText "allowmap" "domain.tld"}";
score = -100.0;
}
''';
}
</programlisting>
'';
};
};
in
{
port = 9225;
extraOpts = {
configFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Specify the mailexporter configuration file to use.
'';
};
configuration = mkOption {
type = types.nullOr (types.submodule exporterOptions);
default = null;
description = ''
Specify the mailexporter configuration file to use.
'';
};
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
};
serviceOpts = {
serviceConfig = {
DynamicUser = false;
ExecStart = ''
${pkgs.prometheus-mail-exporter}/bin/mailexporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
--config.file ${
if cfg.configuration != null then configurationFile else (escapeShellArg cfg.configFile)
} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
};
}

View file

@ -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 = ''
Path to a mikrotik exporter configuration file. Mutually exclusive with
<option>configuration</option> option.
'';
example = literalExpression "./mikrotik.yml";
};
configuration = mkOption {
type = types.nullOr types.attrs;
default = null;
description = ''
Mikrotik exporter configuration as nix attribute set. Mutually exclusive with
<option>configFile</option> option.
See <link xlink:href="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}
'';
};
};
}

View file

@ -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 = ''
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 = ''
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 <literal>config.services.minio.accessKey</literal>.
'';
};
minioAccessSecret = mkOption {
type = types.str;
description = ''
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 <literal>config.services.minio.secretKey</literal>.
'';
};
minioBucketStats = mkOption {
type = types.bool;
default = false;
description = ''
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}
'';
};
};
}

View file

@ -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 = ''
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"
];
};
};
}

View file

@ -0,0 +1,58 @@
{ 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 = ''
URL to the Nextcloud serverinfo page.
Adding the path to the serverinfo API is optional, it defaults
to <literal>/ocs/v2.php/apps/serverinfo/api/v1/info</literal>.
'';
};
username = mkOption {
type = types.str;
default = "nextcloud-exporter";
description = ''
Username for connecting to Nextcloud.
Note that this account needs to have admin privileges in Nextcloud.
'';
};
passwordFile = mkOption {
type = types.path;
example = "/path/to/password-file";
description = ''
File containing the password for connecting to Nextcloud.
Make sure that this file is readable by the exporter user.
'';
};
timeout = mkOption {
type = types.str;
default = "5s";
description = ''
Timeout for getting server info document.
'';
};
};
serviceOpts = {
serviceConfig = {
DynamicUser = false;
ExecStart = ''
${pkgs.prometheus-nextcloud-exporter}/bin/nextcloud-exporter \
--addr ${cfg.listenAddress}:${toString cfg.port} \
--username ${cfg.username} \
--timeout ${cfg.timeout} \
--server ${cfg.url} \
--password ${escapeShellArg "@${cfg.passwordFile}"} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
};
}

View file

@ -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 = ''
Address to access the nginx status page.
Can be enabled with services.nginx.statusPage = true.
'';
};
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
sslVerify = mkOption {
type = types.bool;
default = true;
description = ''
Whether to perform certificate verification for https.
'';
};
constLabels = mkOption {
type = types.listOf types.str;
default = [];
example = [
"label1=value1"
"label2=value2"
];
description = ''
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; })
];
}

View file

@ -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 = ''
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 writting it as JSON.
'';
};
metricsEndpoint = mkOption {
type = types.str;
default = "/metrics";
description = ''
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";
};
};
}

View file

@ -0,0 +1,49 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.node;
in
{
port = 9100;
extraOpts = {
enabledCollectors = mkOption {
type = types.listOf types.str;
default = [];
example = [ "systemd" ];
description = ''
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 = ''
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 (any (collector: (collector == "logind" || collector == "systemd")) cfg.enabledCollectors) [
# needs access to dbus via unix sockets (logind/systemd)
"AF_UNIX"
] ++ optionals (any (collector: (collector == "network_route" || collector == "wifi")) cfg.enabledCollectors) [
# needs netlink sockets for wireless collector
"AF_NETLINK"
];
# The timex collector needs to access clock APIs
ProtectClock = any (collector: collector == "timex") cfg.disabledCollectors;
};
};
}

View file

@ -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 = ''
Environment file to contain the credentials to authenticate against
<package>openldap</package>.
The file should look like this:
<programlisting>
---
ldapUser: "cn=monitoring,cn=Monitor"
ldapPass: "secret"
</programlisting>
'';
};
protocol = mkOption {
default = "tcp";
example = "udp";
type = types.str;
description = ''
Which protocol to use to connect against <package>openldap</package>.
'';
};
ldapAddr = mkOption {
default = "localhost:389";
type = types.str;
description = ''
Address of the <package>openldap</package>-instance.
'';
};
metricsPath = mkOption {
default = "/metrics";
type = types.str;
description = ''
URL path where metrics should be exposed.
'';
};
interval = mkOption {
default = "30s";
type = types.str;
example = "1m";
description = ''
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}
'';
};
}

View file

@ -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 = ''
Paths to OpenVPN status files. Please configure the OpenVPN option
<literal>status</literal> accordingly.
'';
};
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
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}
'';
};
};
}

View file

@ -0,0 +1,74 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.pihole;
in
{
port = 9617;
extraOpts = {
apiToken = mkOption {
type = types.str;
default = "";
example = "580a770cb40511eb85290242ac130003580a770cb40511eb85290242ac130003";
description = ''
pi-hole API token which can be used instead of a password
'';
};
interval = mkOption {
type = types.str;
default = "10s";
example = "30s";
description = ''
How often to scrape new data
'';
};
password = mkOption {
type = types.str;
default = "";
example = "password";
description = ''
The password to login into pihole. An api token can be used instead.
'';
};
piholeHostname = mkOption {
type = types.str;
default = "pihole";
example = "127.0.0.1";
description = ''
Hostname or address where to find the pihole webinterface
'';
};
piholePort = mkOption {
type = types.port;
default = 80;
example = 443;
description = ''
The port pihole webinterface is reachable on
'';
};
protocol = mkOption {
type = types.enum [ "http" "https" ];
default = "http";
example = "https";
description = ''
The protocol which is used to connect to pihole
'';
};
};
serviceOpts = {
serviceConfig = {
ExecStart = ''
${pkgs.bash}/bin/bash -c "${pkgs.prometheus-pihole-exporter}/bin/pihole-exporter \
-interval ${cfg.interval} \
${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}"
'';
};
};
}

View file

@ -0,0 +1,98 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.postfix;
in
{
port = 9154;
extraOpts = {
group = mkOption {
type = types.str;
description = ''
Group under which the postfix exporter shall be run.
It should match the group that is allowed to access the
<literal>showq</literal> socket in the <literal>queue/public/</literal> directory.
Defaults to <literal>services.postfix.setgidGroup</literal> when postfix is enabled.
'';
};
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
logfilePath = mkOption {
type = types.path;
default = "/var/log/postfix_exporter_input.log";
example = "/var/log/mail.log";
description = ''
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 = ''
Path where Postfix places its showq socket.
'';
};
systemd = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable reading metrics from the systemd journal instead of from a logfile
'';
};
unit = mkOption {
type = types.str;
default = "postfix.service";
description = ''
Name of the postfix systemd unit.
'';
};
slice = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Name of the postfix systemd slice.
This overrides the <option>systemd.unit</option>.
'';
};
journalPath = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to the systemd journal.
'';
};
};
};
serviceOpts = {
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" ];
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}")}
'';
};
};
}

View file

@ -0,0 +1,88 @@
{ 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 = ''
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 = ''
Accepts PostgreSQL URI form and key=value form arguments.
'';
};
runAsLocalSuperUser = mkOption {
type = types.bool;
default = false;
description = ''
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 = ''
Environment file as defined in <citerefentry>
<refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
</citerefentry>.
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:
<literal>$ENVIRONMENT ''${VARIABLE}</literal>
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.
<programlisting>
# Content of the environment file
DATA_SOURCE_NAME=postgresql://username:password@localhost:5432/postgres?sslmode=disable
</programlisting>
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"
];
};
};
}

View file

@ -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 = ''
All settings expressed as an Nix attrset.
Check the official documentation for the corresponding YAML
settings that can all be used here: <link xlink:href="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;
};
};
}

View file

@ -0,0 +1,118 @@
{ 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 = mkOption {
type = types.package;
default = pkgs.prometheus-pve-exporter;
defaultText = literalExpression "pkgs.prometheus-pve-exporter";
example = literalExpression "pkgs.prometheus-pve-exporter";
description = ''
The package to use for prometheus-pve-exporter
'';
};
environmentFile = mkOption {
type = with types; nullOr path;
default = null;
example = "/etc/prometheus-pve-exporter/pve.env";
description = ''
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 = ''
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 = ''
Collect Node/VM/CT status
'';
};
version = mkOption {
type = types.bool;
default = true;
description = ''
Collect PVE version info
'';
};
node = mkOption {
type = types.bool;
default = true;
description = ''
Collect PVE node info
'';
};
cluster = mkOption {
type = types.bool;
default = true;
description = ''
Collect PVE cluster info
'';
};
resources = mkOption {
type = types.bool;
default = true;
description = ''
Collect PVE resources info
'';
};
config = mkOption {
type = types.bool;
default = true;
description = ''
Collect PVE onboot status
'';
};
};
};
serviceOpts = {
serviceConfig = {
ExecStart = ''
${cfg.package}/bin/pve_exporter \
--${if cfg.collectors.status == true then "" else "no-"}collector.status \
--${if cfg.collectors.version == true then "" else "no-"}collector.version \
--${if cfg.collectors.node == true then "" else "no-"}collector.node \
--${if cfg.collectors.cluster == true then "" else "no-"}collector.cluster \
--${if cfg.collectors.resources == true then "" else "no-"}collector.resources \
--${if cfg.collectors.config == true then "" else "no-"}collector.config \
${computedConfigFile} \
${toString cfg.port} ${cfg.listenAddress}
'';
} // optionalAttrs (cfg.environmentFile != null) {
EnvironmentFile = cfg.environmentFile;
};
};
}

View file

@ -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 = ''
The hostname of the air purification device from which to scrape the metrics.
'';
};
protocol = mkOption {
type = types.str;
default = "http";
description = ''
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 = ''
Directory below <literal>/var/lib</literal> 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}" ];
};
};
}

View file

@ -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}
'';
};
};
}

View file

@ -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: {
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 = "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; })
];
}

View file

@ -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 = "Name to match.";
};
"${field}" = lib.mkOption {
type = int;
inherit description;
};
location = lib.mkOption {
type = str;
description = "Location to match.";
};
};
});
in
{
rtl433Flags = lib.mkOption {
type = lib.types.str;
default = "-C si";
example = "-C si -R 19";
description = ''
Flags passed verbatim to rtl_433 binary.
Having <literal>-C si</literal> (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 = ''
List of channel matchers to export.
'';
};
ids = lib.mkOption {
type = mkMatcherOptionType "id" "ID to match.";
default = [];
example = [
{ name = "Nexus"; id = 1; location = "Bedroom"; }
];
description = ''
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}
'';
};
};
}

View file

@ -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 = "Name of the script.";
};
script = mkOption {
type = str;
example = "sleep 5";
description = "Shell script to execute when metrics are requested.";
};
timeout = mkOption {
type = nullOr int;
default = null;
example = 60;
description = "Optional timeout for the script in seconds.";
};
};
});
example = literalExpression ''
{
scripts = [
{ name = "sleep"; script = "sleep 5"; }
];
}
'';
description = ''
All settings expressed as an Nix attrset.
Check the official documentation for the corresponding YAML
settings that can all be used here: <link xlink:href="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;
};
};
}

View file

@ -0,0 +1,75 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.smartctl;
format = pkgs.formats.yaml {};
configFile = format.generate "smartctl-exporter.yml" {
smartctl_exporter = {
bind_to = "${cfg.listenAddress}:${toString cfg.port}";
url_path = "/metrics";
smartctl_location = "${pkgs.smartmontools}/bin/smartctl";
collect_not_more_than_period = cfg.maxInterval;
devices = cfg.devices;
};
};
in {
port = 9633;
extraOpts = {
devices = mkOption {
type = types.listOf types.str;
default = [];
example = literalExpression ''
[ "/dev/sda", "/dev/nvme0n1" ];
'';
description = ''
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 = ''
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 100 (
if cfg.devices != [] then
cfg.devices
else [
"block-blkext rw"
"block-sd rw"
"char-nvme rw"
]
);
ExecStart = ''
${pkgs.prometheus-smartctl-exporter}/bin/smartctl_exporter -config ${configFile}
'';
PrivateDevices = lib.mkForce false;
ProtectProc = "invisible";
ProcSubset = "pid";
SupplementaryGroups = [ "disk" ];
SystemCallFilter = [
"@system-service"
"~@privileged @resources"
];
};
};
}

View file

@ -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 = ''
Path under which to expose metrics.
'';
};
pingInterval = mkOption {
type = goDuration;
default = "1s";
description = ''
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 = ''
List of buckets to use for the response duration histogram.
'';
};
hosts = mkOption {
type = with types; listOf str;
description = ''
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}
'';
};
};
}

View file

@ -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 = ''
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 = ''
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 = ''
Output format of log messages.
'';
};
logLevel = mkOption {
type = types.enum ["debug" "info" "warn" "error"];
default = "info";
description = ''
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}
'';
};
};
}

View file

@ -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 = "An attrset of metrics scraping jobs to run.";
};
};
};
jobOptions = {
options = with types; {
interval = mkOption {
type = str;
description = ''
How often to run this job, specified in
<link xlink:href="https://golang.org/pkg/time/#ParseDuration">Go duration</link> format.
'';
};
connections = mkOption {
type = listOf str;
description = "A list of connection strings of the SQL servers to scrape metrics from";
};
startupSql = mkOption {
type = listOf str;
default = [];
description = "A list of SQL statements to execute once after making a connection.";
};
queries = mkOption {
type = attrsOf (submodule queryOptions);
description = "SQL queries to run.";
};
};
};
queryOptions = {
options = with types; {
help = mkOption {
type = nullOr str;
default = null;
description = "A human-readable description of this metric.";
};
labels = mkOption {
type = listOf str;
default = [ ];
description = "A set of columns that will be used as Prometheus labels.";
};
query = mkOption {
type = str;
description = "The SQL query to run.";
};
values = mkOption {
type = listOf str;
description = "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 = ''
Path to configuration file.
'';
};
configuration = mkOption {
type = with types; nullOr (submodule cfgOptions);
default = null;
description = ''
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"
];
};
};
}

View file

@ -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 = ''
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}
'';
};
};
}

View file

@ -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"
];
};
};
}

View file

@ -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 = ''
Tor control IP address or hostname.
'';
};
torControlPort = mkOption {
type = types.int;
default = 9051;
description = ''
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"; };
};
}

View file

@ -0,0 +1,63 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.unbound;
in
{
port = 9167;
extraOpts = {
fetchType = mkOption {
# TODO: add shm when upstream implemented it
type = types.enum [ "tcp" "uds" ];
default = "uds";
description = ''
Which methods the exporter uses to get the information from unbound.
'';
};
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
controlInterface = mkOption {
type = types.nullOr types.str;
default = null;
example = "/run/unbound/unbound.socket";
description = ''
Path to the unbound socket for uds mode or the control interface port for tcp mode.
Example:
uds-mode: /run/unbound/unbound.socket
tcp-mode: 127.0.0.1:8953
'';
};
};
serviceOpts = mkMerge ([{
serviceConfig = {
ExecStart = ''
${pkgs.prometheus-unbound-exporter}/bin/unbound-telemetry \
${cfg.fetchType} \
--bind ${cfg.listenAddress}:${toString cfg.port} \
--path ${cfg.telemetryPath} \
${optionalString (cfg.controlInterface != null) "--control-interface ${cfg.controlInterface}"} \
${toString cfg.extraFlags}
'';
RestrictAddressFamilies = [
# Need AF_UNIX to collect data
"AF_UNIX"
];
};
}] ++ [
(mkIf config.services.unbound.enable {
after = [ "unbound.service" ];
requires = [ "unbound.service" ];
})
]);
}

View file

@ -0,0 +1,34 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.unifi-poller;
configFile = pkgs.writeText "prometheus-unifi-poller-exporter.json" (generators.toJSON {} {
poller = { inherit (cfg.log) debug quiet; };
unifi = { inherit (cfg) controllers; };
influxdb.disable = true;
prometheus = {
http_listen = "${cfg.listenAddress}:${toString cfg.port}";
report_errors = cfg.log.prometheusErrors;
};
});
in {
port = 9130;
extraOpts = {
inherit (options.services.unifi-poller.unifi) controllers;
log = {
debug = mkEnableOption "debug logging including line numbers, high resolution timestamps, per-device logs.";
quiet = mkEnableOption "startup and error logs only.";
prometheusErrors = mkEnableOption "emitting errors to prometheus.";
};
};
serviceOpts.serviceConfig = {
ExecStart = "${pkgs.unifi-poller}/bin/unifi-poller --config ${configFile}";
DynamicUser = false;
};
}

View file

@ -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 = ''
URL of the UniFi Controller API.
'';
};
unifiInsecure = mkOption {
type = types.bool;
default = false;
description = ''
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 = ''
username for authentication against UniFi Controller API.
'';
};
unifiPassword = mkOption {
type = types.str;
description = ''
Password for authentication against UniFi Controller API.
'';
};
unifiTimeout = mkOption {
type = types.str;
default = "5s";
example = "2m";
description = ''
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}
'';
};
};
}

View file

@ -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 = ''
Do not exit server on Varnish scrape errors.
'';
};
withGoMetrics = mkOption {
type = types.bool;
default = false;
description = ''
Export go runtime and http handler metrics.
'';
};
verbose = mkOption {
type = types.bool;
default = false;
description = ''
Enable verbose logging.
'';
};
raw = mkOption {
type = types.bool;
default = false;
description = ''
Enable raw stdout logging without timestamps.
'';
};
varnishStatPath = mkOption {
type = types.str;
default = "varnishstat";
description = ''
Path to varnishstat.
'';
};
instance = mkOption {
type = types.nullOr types.str;
default = config.services.varnish.stateDir;
defaultText = lib.literalExpression "config.services.varnish.stateDir";
description = ''
varnishstat -n value.
'';
};
healthPath = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Path under which to expose healthcheck. Disabled unless configured.
'';
};
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
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")}
'';
};
};
}

View file

@ -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 "Verbose logging mode for prometheus-wireguard-exporter";
wireguardConfig = mkOption {
type = with types; nullOr (either path str);
default = null;
description = ''
Path to the Wireguard Config to
<link xlink:href="https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/2.0.0#usage">add the peer's name to the stats of a peer</link>.
Please note that <literal>networking.wg-quick</literal> is required for this feature
as <literal>networking.wireguard</literal> uses
<citerefentry><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry>
to set the peers up.
'';
};
singleSubnetPerField = mkOption {
type = types.bool;
default = false;
description = ''
By default, all allowed IPs and subnets are comma-separated in the
<literal>allowed_ips</literal> field. With this option enabled,
a single IP and subnet will be listed in fields like <literal>allowed_ip_0</literal>,
<literal>allowed_ip_1</literal> and so on.
'';
};
withRemoteIp = mkOption {
type = types.bool;
default = false;
description = ''
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"} \
${optionalString cfg.singleSubnetPerField "-s"} \
${optionalString cfg.withRemoteIp "-r"} \
${optionalString (cfg.wireguardConfig != null) "-n ${escapeShellArg cfg.wireguardConfig}"}
'';
RestrictAddressFamilies = [
# Need AF_NETLINK to collect data
"AF_NETLINK"
];
};
};
}