nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/restic.nix

142 lines
4.3 KiB
Nix

{ config, lib, pkgs, options, ... }:
let
cfg = config.services.prometheus.exporters.restic;
inherit (lib)
mkOption
types
concatStringsSep
mkIf
mapAttrs'
splitString
toUpper
optionalAttrs
nameValuePair
;
in
{
port = 9753;
extraOpts = {
repository = mkOption {
type = types.str;
description = ''
URI pointing to the repository to monitor.
'';
example = "sftp:backup@192.168.1.100:/backups/example";
};
passwordFile = mkOption {
type = types.path;
description = ''
File containing the password to the repository.
'';
example = "/etc/nixos/restic-password";
};
environmentFile = mkOption {
type = with types; nullOr path;
default = null;
description = ''
File containing the credentials to access the repository, in the
format of an EnvironmentFile as described by systemd.exec(5)
'';
};
refreshInterval = mkOption {
type = types.ints.unsigned;
default = 60;
description = ''
Refresh interval for the metrics in seconds.
Computing the metrics is an expensive task, keep this value as high as possible.
'';
};
rcloneOptions = mkOption {
type = with types; attrsOf (oneOf [ str bool ]);
default = { };
description = ''
Options to pass to rclone to control its behavior.
See <https://rclone.org/docs/#options> for
available options. When specifying option names, strip the
leading `--`. To set a flag such as
`--drive-use-trash`, which does not take a value,
set the value to the Boolean `true`.
'';
};
rcloneConfig = mkOption {
type = with types; attrsOf (oneOf [ str bool ]);
default = { };
description = ''
Configuration for the rclone remote being used for backup.
See the remote's specific options under rclone's docs at
<https://rclone.org/docs/>. When specifying
option names, use the "config" name specified in the docs.
For example, to set `--b2-hard-delete` for a B2
remote, use `hard_delete = true` in the
attribute set.
::: {.warning}
Secrets set in here will be world-readable in the Nix
store! Consider using the {option}`rcloneConfigFile`
option instead to specify secret values separately. Note that
options set here will override those set in the config file.
:::
'';
};
rcloneConfigFile = mkOption {
type = with types; nullOr path;
default = null;
description = ''
Path to the file containing rclone configuration. This file
must contain configuration for the remote specified in this backup
set and also must be readable by root.
::: {.caution}
Options set in `rcloneConfig` will override those set in this
file.
:::
'';
};
};
serviceOpts = {
script = ''
export RESTIC_PASSWORD_FILE=$CREDENTIALS_DIRECTORY/RESTIC_PASSWORD_FILE
${pkgs.prometheus-restic-exporter}/bin/restic-exporter.py \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
serviceConfig = {
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
LoadCredential = [ "RESTIC_PASSWORD_FILE:${cfg.passwordFile}" ];
};
environment =
let
rcloneRemoteName = builtins.elemAt (splitString ":" cfg.repository) 1;
rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v);
rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v);
toRcloneVal = v: if lib.isBool v then lib.boolToString v else v;
in
{
RESTIC_REPOSITORY = cfg.repository;
LISTEN_ADDRESS = cfg.listenAddress;
LISTEN_PORT = toString cfg.port;
REFRESH_INTERVAL = toString cfg.refreshInterval;
}
// (mapAttrs'
(name: value:
nameValuePair (rcloneAttrToOpt name) (toRcloneVal value)
)
cfg.rcloneOptions)
// optionalAttrs (cfg.rcloneConfigFile != null) {
RCLONE_CONFIG = cfg.rcloneConfigFile;
}
// (mapAttrs'
(name: value:
nameValuePair (rcloneAttrToConf name) (toRcloneVal value)
)
cfg.rcloneConfig);
};
}