2024-05-14 11:18:38 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
let
|
2024-05-14 13:39:41 +00:00
|
|
|
cfg = config.programs.rclone;
|
|
|
|
targetName = "rclone";
|
2024-05-15 19:10:35 +00:00
|
|
|
mkIfNotNull = value: result: lib.mkIf (value != null) result;
|
2024-05-14 13:39:41 +00:00
|
|
|
|
2024-05-15 08:01:13 +00:00
|
|
|
mkSystemdDependencyOption =
|
2024-05-15 16:16:45 +00:00
|
|
|
{ default, global ? false, ... }: lib.mkOption {
|
2024-05-15 08:01:13 +00:00
|
|
|
type = lib.types.attrsOf (lib.types.listOf lib.types.str);
|
2024-05-15 16:16:45 +00:00
|
|
|
description = "The systemd services ${
|
|
|
|
if global then "all" else "this"
|
|
|
|
} sync${
|
|
|
|
if global then "s" else ""
|
|
|
|
} depend${
|
|
|
|
if global then "" else "s"
|
|
|
|
} on.";
|
2024-05-15 08:01:13 +00:00
|
|
|
example = {
|
|
|
|
secrets = [
|
|
|
|
"sops-nix.service"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
inherit default;
|
|
|
|
};
|
|
|
|
|
2024-05-15 21:21:00 +00:00
|
|
|
mkProvider = (
|
|
|
|
{ config, ... }: {
|
2024-05-14 11:18:38 +00:00
|
|
|
options = {
|
2024-05-15 18:51:50 +00:00
|
|
|
path = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "The path to mount the remote file system to.";
|
|
|
|
};
|
|
|
|
|
2024-05-14 11:18:38 +00:00
|
|
|
autoStart = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
|
|
|
description = "Whether to start this sync automatically.";
|
|
|
|
default = true;
|
|
|
|
};
|
|
|
|
|
2024-05-14 13:39:41 +00:00
|
|
|
systemdDependencies = mkSystemdDependencyOption {
|
|
|
|
default = cfg.systemdDependencies;
|
2024-05-14 11:18:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
environment = lib.mkOption {
|
|
|
|
type = lib.types.attrsOf lib.types.envVar;
|
|
|
|
description = "The environment variables to pass to the service.";
|
2024-05-15 21:21:00 +00:00
|
|
|
default = { };
|
2024-05-14 11:18:38 +00:00
|
|
|
};
|
|
|
|
|
2024-05-15 22:13:14 +00:00
|
|
|
secrets = lib.mkOption {
|
|
|
|
type = lib.types.attrsOf (lib.types.either lib.types.path lib.types.str);
|
|
|
|
description = "A set of environment variables to load from files.";
|
|
|
|
default = { };
|
|
|
|
};
|
|
|
|
|
2024-05-14 12:23:30 +00:00
|
|
|
secretsScript = lib.mkOption {
|
2024-05-14 11:18:38 +00:00
|
|
|
type = lib.types.lines;
|
2024-05-14 12:23:30 +00:00
|
|
|
description = "A script for loading secrets before launching the sync.";
|
2024-05-15 22:13:14 +00:00
|
|
|
default = "";
|
2024-05-14 11:18:38 +00:00
|
|
|
};
|
2024-05-15 07:48:02 +00:00
|
|
|
|
|
|
|
config = lib.mkOption {
|
|
|
|
type = lib.types.attrs;
|
|
|
|
description = "The rclone config to use for creating the mount.";
|
|
|
|
visible = false;
|
|
|
|
};
|
2024-05-14 11:18:38 +00:00
|
|
|
};
|
2024-05-15 22:13:14 +00:00
|
|
|
|
|
|
|
config = {
|
2024-05-15 22:20:06 +00:00
|
|
|
secretsScript = lib.strings.concatLines
|
2024-05-15 22:13:14 +00:00
|
|
|
(builtins.attrValues (
|
|
|
|
builtins.mapAttrs
|
|
|
|
(name: path: "${name}=\"$(cat ${lib.escapeShellArg path})\"")
|
|
|
|
config.secrets));
|
|
|
|
};
|
2024-05-15 21:21:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
mkWebdavProvider = (
|
|
|
|
{ displayName, vendor, ... }: (
|
|
|
|
{ config, ... }: {
|
|
|
|
imports = [
|
|
|
|
mkProvider
|
|
|
|
];
|
|
|
|
|
2024-05-15 21:24:54 +00:00
|
|
|
options = {
|
2024-05-15 21:21:00 +00:00
|
|
|
vendor = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "The vendor of the WebDAV share.";
|
|
|
|
default = vendor;
|
|
|
|
};
|
|
|
|
|
|
|
|
url = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "The WebDAV URL of the ${displayName} server.";
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
username = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.str;
|
|
|
|
description = "The user name for logging in to the ${displayName} server.";
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
obscuredPassword = lib.mkOption {
|
|
|
|
type = lib.types.nullOr lib.types.str;
|
|
|
|
description = "The password obscured using the `rclone obscure` command for logging in to the ${displayName} server.";
|
|
|
|
default = null;
|
|
|
|
};
|
2024-05-14 13:24:17 +00:00
|
|
|
|
2024-05-15 21:21:00 +00:00
|
|
|
obscuredPasswordFile = lib.mkOption {
|
|
|
|
type = lib.types.nullOr (lib.types.either lib.types.path lib.types.str);
|
|
|
|
description = "The path to a file containing the password obscured using the `rclone obscure` command for logging in to the ${displayName} server.";
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = {
|
|
|
|
config = lib.mkMerge [
|
|
|
|
{
|
|
|
|
inherit vendor;
|
2024-05-15 21:24:54 +00:00
|
|
|
url = config.url;
|
2024-05-15 21:21:00 +00:00
|
|
|
}
|
2024-05-15 21:24:54 +00:00
|
|
|
(mkIfNotNull config.username { user = config.username; })
|
|
|
|
(mkIfNotNull config.obscuredPassword { pass = config.obscuredPassword; })
|
2024-05-15 21:21:00 +00:00
|
|
|
];
|
2024-05-15 22:13:14 +00:00
|
|
|
|
|
|
|
secrets = lib.optionalAttrs (config.obscuredPasswordFile != null) {
|
|
|
|
RCLONE_WEBDAV_PASS = config.obscuredPasswordFile;
|
|
|
|
};
|
2024-05-15 21:21:00 +00:00
|
|
|
};
|
|
|
|
}));
|
|
|
|
|
2024-05-15 22:32:49 +00:00
|
|
|
mkOwncloudProvider = { displayName ? "Owncloud", vendor ? "owncloud" }: (
|
|
|
|
{ config, ... }: {
|
|
|
|
imports = [
|
|
|
|
(mkWebdavProvider { inherit displayName vendor; })
|
|
|
|
];
|
|
|
|
|
|
|
|
options = {
|
|
|
|
baseUrl = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = "The base url of the ${displayName} server for automatically determining the WebDAV url.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = {
|
|
|
|
url = "${lib.strings.removeSuffix "/" (lib.strings.normalizePath config.baseUrl)}/remote.php/dav/files/${config.username}";
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2024-05-15 21:21:00 +00:00
|
|
|
syncProviders = {
|
|
|
|
nextcloud = rec {
|
|
|
|
displayName = "Nextcloud";
|
|
|
|
|
2024-05-15 22:32:49 +00:00
|
|
|
module = mkOwncloudProvider {
|
2024-05-15 21:21:00 +00:00
|
|
|
inherit displayName;
|
|
|
|
vendor = "nextcloud";
|
2024-05-15 15:22:34 +00:00
|
|
|
};
|
2024-05-15 21:21:00 +00:00
|
|
|
};
|
|
|
|
};
|
2024-05-14 11:18:38 +00:00
|
|
|
in {
|
2024-05-12 23:20:01 +00:00
|
|
|
options = {
|
|
|
|
programs.rclone = {
|
|
|
|
enable = lib.mkEnableOption "rclone";
|
2024-05-14 11:18:38 +00:00
|
|
|
|
2024-05-14 13:39:41 +00:00
|
|
|
systemdDependencies = mkSystemdDependencyOption {
|
|
|
|
default = {};
|
2024-05-15 16:16:45 +00:00
|
|
|
global = true;
|
2024-05-14 13:39:41 +00:00
|
|
|
};
|
|
|
|
|
2024-05-15 13:54:03 +00:00
|
|
|
configs = (builtins.mapAttrs
|
2024-05-15 21:21:00 +00:00
|
|
|
(name: provider: lib.mkOption {
|
|
|
|
type = lib.types.attrsOf (lib.types.submodule provider.module);
|
|
|
|
description = "The ${provider.displayName} synchronizations to set up.";
|
2024-05-15 14:04:34 +00:00
|
|
|
default = { };
|
2024-05-15 13:54:03 +00:00
|
|
|
})
|
|
|
|
syncProviders);
|
2024-05-12 23:20:01 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-05-14 13:39:41 +00:00
|
|
|
config = {
|
|
|
|
home.packages = lib.optional cfg.enable pkgs.rclone;
|
2024-05-12 23:20:01 +00:00
|
|
|
|
2024-05-14 13:39:41 +00:00
|
|
|
systemd.user = lib.optionalAttrs cfg.enable {
|
|
|
|
enable = true;
|
2024-05-12 23:20:01 +00:00
|
|
|
|
2024-05-14 13:39:41 +00:00
|
|
|
services = {
|
|
|
|
rclone = {
|
|
|
|
Unit = {
|
|
|
|
Description = "rclone Starter";
|
|
|
|
Documentation = "man:rclone(1)";
|
|
|
|
};
|
2024-05-12 23:20:01 +00:00
|
|
|
|
2024-05-14 13:39:41 +00:00
|
|
|
Service = {
|
|
|
|
Type = "simple";
|
|
|
|
|
|
|
|
ExecStartPre =
|
|
|
|
let
|
|
|
|
script = pkgs.writeShellScriptBin "rclone-pre" ''
|
|
|
|
sleep 10
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
(lib.getExe script);
|
|
|
|
|
|
|
|
ExecStart =
|
|
|
|
let
|
|
|
|
script = pkgs.writeShellScriptBin "rclone" ''
|
|
|
|
systemctl --user start rclone.target
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
(lib.getExe script);
|
2024-05-12 23:20:01 +00:00
|
|
|
};
|
2024-05-14 13:39:41 +00:00
|
|
|
};
|
|
|
|
} // (
|
|
|
|
lib.attrsets.concatMapAttrs
|
2024-05-15 13:54:03 +00:00
|
|
|
(providerName: configs:
|
|
|
|
lib.attrsets.concatMapAttrs
|
|
|
|
(name: sync:
|
|
|
|
let
|
|
|
|
serviceName = "rclone-${providerName}-sync-${name}";
|
|
|
|
in {
|
|
|
|
${serviceName} = {
|
|
|
|
Unit = {
|
|
|
|
Description = "rclone sync service for ${name} at using ${providerName}";
|
|
|
|
};
|
|
|
|
|
|
|
|
Service = {
|
|
|
|
Environment = lib.mapAttrsToList
|
|
|
|
(key: val: (lib.escapeShellArg "${key}=${val}"))
|
|
|
|
sync.environment;
|
|
|
|
|
|
|
|
ExecStart =
|
|
|
|
let
|
2024-05-15 19:10:35 +00:00
|
|
|
configFile = pkgs.writeText
|
|
|
|
"${serviceName}.conf"
|
|
|
|
(lib.generators.toINI { } { name = sync.config; });
|
2024-05-15 13:54:03 +00:00
|
|
|
script = pkgs.writeShellScriptBin serviceName ''
|
|
|
|
${sync.secretsScript}
|
|
|
|
bash -c echo hello world
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
(lib.getExe script);
|
|
|
|
};
|
|
|
|
|
|
|
|
Install = {
|
|
|
|
WantedBy = lib.optional sync.autoStart "${targetName}.target";
|
2024-05-15 22:32:49 +00:00
|
|
|
After = builtins.concatLists (builtins.attrValues sync.systemdDependencies);
|
2024-05-15 13:54:03 +00:00
|
|
|
};
|
2024-05-14 13:39:41 +00:00
|
|
|
};
|
2024-05-15 13:54:03 +00:00
|
|
|
})
|
|
|
|
configs)
|
2024-05-14 13:39:41 +00:00
|
|
|
cfg.configs);
|
|
|
|
|
|
|
|
targets.${targetName} = {
|
|
|
|
Unit = {
|
|
|
|
Description = "rclone Mounts";
|
|
|
|
Documentation = "man:rclone(1)";
|
2024-05-12 23:20:01 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2024-05-14 13:39:41 +00:00
|
|
|
};
|
2024-05-12 23:20:01 +00:00
|
|
|
}
|