nixos/syncthing: use rfc42 style settings

This commit is contained in:
Xyz00777 2023-04-14 00:20:18 +02:00 committed by lassulus
parent 6c4023fb1a
commit 32866f8d58
2 changed files with 275 additions and 279 deletions

View file

@ -7,25 +7,20 @@ let
opt = options.services.syncthing;
defaultUser = "syncthing";
defaultGroup = defaultUser;
settingsFormat = pkgs.formats.json { };
devices = mapAttrsToList (name: device: {
devices = mapAttrsToList (_: device: device // {
deviceID = device.id;
inherit (device) name addresses introducer autoAcceptFolders;
}) cfg.devices;
}) cfg.settings.devices;
folders = mapAttrsToList ( _: folder: {
inherit (folder) path id label type;
devices = map (device: { deviceId = cfg.devices.${device}.id; }) folder.devices;
rescanIntervalS = folder.rescanInterval;
fsWatcherEnabled = folder.watch;
fsWatcherDelayS = folder.watchDelay;
ignorePerms = folder.ignorePerms;
ignoreDelete = folder.ignoreDelete;
versioning = folder.versioning;
}) (filterAttrs (
_: folder:
folder.enable
) cfg.folders);
folders = mapAttrsToList (_: folder: folder // {
devices = map (device:
if builtins.isString device then
{ deviceId = cfg.settings.devices.${device}.id; }
else
device
) folder.devices;
}) cfg.settings.folders;
updateConfig = pkgs.writers.writeDash "merge-syncthing-config" ''
set -efu
@ -54,10 +49,10 @@ let
old_cfg=$(curl ${cfg.guiAddress}/rest/config)
# generate the new config by merging with the NixOS config options
new_cfg=$(printf '%s\n' "$old_cfg" | ${pkgs.jq}/bin/jq -c '. * {
"devices": (${builtins.toJSON devices}${optionalString (cfg.devices == {} || ! cfg.overrideDevices) " + .devices"}),
"folders": (${builtins.toJSON folders}${optionalString (cfg.folders == {} || ! cfg.overrideFolders) " + .folders"})
} * ${builtins.toJSON cfg.extraOptions}')
new_cfg=$(printf '%s\n' "$old_cfg" | ${pkgs.jq}/bin/jq -c ${escapeShellArg ''. * ${builtins.toJSON cfg.settings} * {
"devices": (${builtins.toJSON devices}${optionalString (cfg.settings.devices == {} || ! cfg.overrideDevices) " + .devices"}),
"folders": (${builtins.toJSON folders}${optionalString (cfg.settings.folders == {} || ! cfg.overrideFolders) " + .folders"})
}''})
# send the new config
curl -X PUT -d "$new_cfg" ${cfg.guiAddress}/rest/config
@ -99,12 +94,92 @@ in {
default = true;
description = mdDoc ''
Whether to delete the devices which are not configured via the
[devices](#opt-services.syncthing.devices) option.
[devices](#opt-services.syncthing.settings.devices) option.
If set to `false`, devices added via the web
interface will persist and will have to be deleted manually.
'';
};
overrideFolders = mkOption {
type = types.bool;
default = true;
description = mdDoc ''
Whether to delete the folders which are not configured via the
[folders](#opt-services.syncthing.settings.folders) option.
If set to `false`, folders added via the web
interface will persist and will have to be deleted manually.
'';
};
settings = mkOption {
type = types.submodule {
freeformType = settingsFormat.type;
options = {
# global options
options = mkOption {
default = {};
description = mdDoc ''
The options element contains all other global configuration options
'';
type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type;
options = {
localAnnounceEnabled = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether to send announcements to the local LAN, also use such announcements to find other devices.
'';
};
localAnnouncePort = mkOption {
type = types.int;
default = 21027;
description = lib.mdDoc ''
The port on which to listen and send IPv4 broadcast announcements to.
'';
};
relaysEnabled = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
When true, relays will be connected to and potentially used for device to device connections.
'';
};
urAccepted = mkOption {
type = types.int;
default = 0;
description = lib.mdDoc ''
Whether the user has accepted to submit anonymous usage data.
The default, 0, mean the user has not made a choice, and Syncthing will ask at some point in the future.
"-1" means no, a number above zero means that that version of usage reporting has been accepted.
'';
};
limitBandwidthInLan = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Whether to apply bandwidth limits to devices in the same broadcast domain as the local device.
'';
};
maxFolderConcurrency = mkOption {
type = types.int;
default = 0;
description = lib.mdDoc ''
This option controls how many folders may concurrently be in I/O-intensive operations such as syncing or scanning.
The mechanism is described in detail in a [separate chapter](https://docs.syncthing.net/advanced/option-max-concurrency.html).
'';
};
};
}));
};
# device settings
devices = mkOption {
default = {};
description = mdDoc ''
@ -121,6 +196,7 @@ in {
};
};
type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type;
options = {
name = mkOption {
@ -131,15 +207,6 @@ in {
'';
};
addresses = mkOption {
type = types.listOf types.str;
default = [];
description = lib.mdDoc ''
The addresses used to connect to the device.
If this is left empty, dynamic configuration is attempted.
'';
};
id = mkOption {
type = types.str;
description = mdDoc ''
@ -147,16 +214,6 @@ in {
'';
};
introducer = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Whether the device should act as an introducer and be allowed
to add folders on this computer.
See <https://docs.syncthing.net/users/introducer.html>.
'';
};
autoAcceptFolders = mkOption {
type = types.bool;
default = false;
@ -170,17 +227,7 @@ in {
}));
};
overrideFolders = mkOption {
type = types.bool;
default = true;
description = mdDoc ''
Whether to delete the folders which are not configured via the
[folders](#opt-services.syncthing.folders) option.
If set to `false`, folders added via the web
interface will persist and will have to be deleted manually.
'';
};
# folder settings
folders = mkOption {
default = {};
description = mdDoc ''
@ -199,6 +246,7 @@ in {
}
'';
type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type;
options = {
enable = mkOption {
@ -248,7 +296,7 @@ in {
default = [];
description = mdDoc ''
The devices this folder should be shared with. Each device must
be defined in the [devices](#opt-services.syncthing.devices) option.
be defined in the [devices](#opt-services.syncthing.settings.devices) option.
'';
};
@ -304,82 +352,24 @@ in {
See <https://docs.syncthing.net/users/versioning.html>.
'';
};
fsPath = mkOption {
default = "";
type = either str path;
description = mdDoc ''
Path to the versioning folder.
See <https://docs.syncthing.net/users/versioning.html>.
'';
};
params = mkOption {
type = attrsOf (either str path);
description = mdDoc ''
The parameters for versioning. Structure depends on
[versioning.type](#opt-services.syncthing.folders._name_.versioning.type).
See <https://docs.syncthing.net/users/versioning.html>.
'';
};
};
});
};
rescanInterval = mkOption {
type = types.int;
default = 3600;
description = lib.mdDoc ''
How often the folder should be rescanned for changes.
'';
};
type = mkOption {
type = types.enum [ "sendreceive" "sendonly" "receiveonly" "receiveencrypted" ];
default = "sendreceive";
description = lib.mdDoc ''
Whether to only send changes for this folder, only receive them
or both. `receiveencrypted` can be used for untrusted devices. See
<https://docs.syncthing.net/users/untrusted.html> for reference.
'';
};
watch = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether the folder should be watched for changes by inotify.
'';
};
watchDelay = mkOption {
type = types.int;
default = 10;
description = lib.mdDoc ''
The delay after an inotify event is triggered.
'';
};
ignorePerms = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether to ignore permission changes.
'';
};
ignoreDelete = mkOption {
copyOwnershipFromParent = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Whether to skip deleting files that are deleted by peers.
See <https://docs.syncthing.net/advanced/folder-ignoredelete.html>.
On Unix systems, tries to copy file/folder ownership from the parent directory (the directory its located in).
Requires running Syncthing as a privileged user, or granting it additional capabilities (e.g. CAP_CHOWN on Linux).
'';
};
};
}));
};
extraOptions = mkOption {
type = types.addCheck (pkgs.formats.json {}).type isAttrs;
};
};
default = {};
description = mdDoc ''
Extra configuration options for Syncthing.
@ -530,6 +520,10 @@ in {
This option was removed because Syncthing now has the inotify functionality included under the name "fswatcher".
It can be enabled on a per-folder basis through the web interface.
'')
(mkRenamedOptionModule [ "services" "syncthing" "extraOptions" ] [ "services" "syncthing" "settings" ])
(mkRenamedOptionModule [ "services" "syncthing" "folders" ] [ "services" "syncthing" "settings" "folders" ])
(mkRenamedOptionModule [ "services" "syncthing" "devices" ] [ "services" "syncthing" "settings" "devices" ])
(mkRenamedOptionModule [ "services" "syncthing" "options" ] [ "services" "syncthing" "settings" "options" ])
] ++ map (o:
mkRenamedOptionModule [ "services" "syncthing" "declarative" o ] [ "services" "syncthing" o ]
) [ "cert" "key" "devices" "folders" "overrideDevices" "overrideFolders" "extraOptions"];
@ -616,7 +610,7 @@ in {
};
};
syncthing-init = mkIf (
cfg.devices != {} || cfg.folders != {} || cfg.extraOptions != {}
cfg.settings.devices != {} || cfg.folders != {} || cfg.extraOptions != {}
) {
description = "Syncthing configuration updater";
requisite = [ "syncthing.service" ];

View file

@ -9,6 +9,7 @@ in {
nodes.machine = {
services.syncthing = {
enable = true;
settings = {
devices.testDevice = {
id = testId;
};
@ -16,7 +17,8 @@ in {
path = "/tmp/test";
devices = [ "testDevice" ];
};
extraOptions.gui.user = "guiUser";
gui.user = "guiUser";
};
};
};