diff options
author | Xyz00777 <52142054+Xyz00777@users.noreply.github.com> | 2023-04-14 00:20:18 +0200 |
---|---|---|
committer | lassulus <git@lassul.us> | 2023-05-15 14:38:56 +0200 |
commit | 32866f8d58979e8dbdf92bfaa72d2883eee861f7 (patch) | |
tree | 0200aa651aa1de3f5819426b8b8cc1206bf5413e /nixos | |
parent | 6c4023fb1ad258c53c2b82a068aa4197542cd0c4 (diff) |
nixos/syncthing: use rfc42 style settings
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/modules/services/networking/syncthing.nix | 508 | ||||
-rw-r--r-- | nixos/tests/syncthing-init.nix | 16 |
2 files changed, 260 insertions, 264 deletions
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index 3d41fe4013ea9..b5ebda6da045f 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -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; - - 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); + }) cfg.settings.devices; + + 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,287 +94,282 @@ 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. ''; }; - devices = mkOption { - default = {}; - description = mdDoc '' - Peers/devices which Syncthing should communicate with. - - Note that you can still add devices manually, but those changes - will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices) - is enabled. - ''; - example = { - bigbox = { - id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU"; - addresses = [ "tcp://192.168.0.10:51820" ]; - }; - }; - type = types.attrsOf (types.submodule ({ name, ... }: { - options = { - - name = mkOption { - type = types.str; - default = name; - description = lib.mdDoc '' - The name of the device. - ''; - }; - - 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 '' - The device ID. See <https://docs.syncthing.net/dev/device-ids.html>. - ''; - }; - - 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; - description = mdDoc '' - Automatically create or share folders that this device advertises at the default path. - See <https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format>. - ''; - }; - - }; - })); - }; - 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. + [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. ''; }; - folders = mkOption { - default = {}; - description = mdDoc '' - Folders which should be shared by Syncthing. - - Note that you can still add folders manually, but those changes - will be reverted on restart if [overrideFolders](#opt-services.syncthing.overrideFolders) - is enabled. - ''; - example = literalExpression '' - { - "/home/user/sync" = { - id = "syncme"; - devices = [ "bigbox" ]; - }; - } - ''; - type = types.attrsOf (types.submodule ({ name, ... }: { + settings = mkOption { + type = types.submodule { + freeformType = settingsFormat.type; options = { - - enable = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to share this folder. - This option is useful when you want to define all folders - in one place, but not every machine should share all folders. + # 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 = { - path = mkOption { - # TODO for release 23.05: allow relative paths again and set - # working directory to cfg.dataDir - type = types.str // { - check = x: types.str.check x && (substring 0 1 x == "/" || substring 0 2 x == "~/"); - description = types.str.description + " starting with / or ~/"; - }; - default = name; - description = lib.mdDoc '' - The path to the folder which should be shared. - Only absolute paths (starting with `/`) and paths relative to - the [user](#opt-services.syncthing.user)'s home directory - (starting with `~/`) are allowed. - ''; - }; + 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. + ''; + }; - id = mkOption { - type = types.str; - default = name; - description = lib.mdDoc '' - The ID of the folder. Must be the same on all devices. - ''; - }; + localAnnouncePort = mkOption { + type = types.int; + default = 21027; + description = lib.mdDoc '' + The port on which to listen and send IPv4 broadcast announcements to. + ''; + }; - label = mkOption { - type = types.str; - default = name; - description = lib.mdDoc '' - The label of the folder. - ''; + 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 { - type = types.listOf types.str; - default = []; + default = {}; description = mdDoc '' - The devices this folder should be shared with. Each device must - be defined in the [devices](#opt-services.syncthing.devices) option. - ''; - }; + Peers/devices which Syncthing should communicate with. - versioning = mkOption { - default = null; - description = mdDoc '' - How to keep changed/deleted files with Syncthing. - There are 4 different types of versioning with different parameters. - See <https://docs.syncthing.net/users/versioning.html>. + Note that you can still add devices manually, but those changes + will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices) + is enabled. ''; - example = literalExpression '' - [ - { - versioning = { - type = "simple"; - params.keep = "10"; - }; - } - { - versioning = { - type = "trashcan"; - params.cleanoutDays = "1000"; - }; - } - { - versioning = { - type = "staggered"; - fsPath = "/syncthing/backup"; - params = { - cleanInterval = "3600"; - maxAge = "31536000"; - }; - }; - } - { - versioning = { - type = "external"; - params.versionsPath = pkgs.writers.writeBash "backup" ''' - folderpath="$1" - filepath="$2" - rm -rf "$folderpath/$filepath" - '''; - }; - } - ] - ''; - type = with types; nullOr (submodule { + example = { + bigbox = { + id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU"; + addresses = [ "tcp://192.168.0.10:51820" ]; + }; + }; + type = types.attrsOf (types.submodule ({ name, ... }: { + freeformType = settingsFormat.type; options = { - type = mkOption { - type = enum [ "external" "simple" "staggered" "trashcan" ]; - description = mdDoc '' - The type of versioning. - See <https://docs.syncthing.net/users/versioning.html>. + + name = mkOption { + type = types.str; + default = name; + description = lib.mdDoc '' + The name of the device. ''; }; - fsPath = mkOption { - default = ""; - type = either str path; + + id = mkOption { + type = types.str; description = mdDoc '' - Path to the versioning folder. - See <https://docs.syncthing.net/users/versioning.html>. + The device ID. See <https://docs.syncthing.net/dev/device-ids.html>. ''; }; - params = mkOption { - type = attrsOf (either str path); + + autoAcceptFolders = mkOption { + type = types.bool; + default = false; 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>. + Automatically create or share folders that this device advertises at the default path. + See <https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format>. ''; }; + }; - }); + })); }; - rescanInterval = mkOption { - type = types.int; - default = 3600; - description = lib.mdDoc '' - How often the folder should be rescanned for changes. - ''; - }; + # folder settings + folders = mkOption { + default = {}; + description = mdDoc '' + Folders which should be shared by Syncthing. - 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. + Note that you can still add folders manually, but those changes + will be reverted on restart if [overrideFolders](#opt-services.syncthing.overrideFolders) + is enabled. ''; - }; - - watch = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether the folder should be watched for changes by inotify. + example = literalExpression '' + { + "/home/user/sync" = { + id = "syncme"; + devices = [ "bigbox" ]; + }; + } ''; - }; + type = types.attrsOf (types.submodule ({ name, ... }: { + freeformType = settingsFormat.type; + options = { - watchDelay = mkOption { - type = types.int; - default = 10; - description = lib.mdDoc '' - The delay after an inotify event is triggered. - ''; - }; + enable = mkOption { + type = types.bool; + default = true; + description = lib.mdDoc '' + Whether to share this folder. + This option is useful when you want to define all folders + in one place, but not every machine should share all folders. + ''; + }; - ignorePerms = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to ignore permission changes. - ''; - }; + path = mkOption { + # TODO for release 23.05: allow relative paths again and set + # working directory to cfg.dataDir + type = types.str // { + check = x: types.str.check x && (substring 0 1 x == "/" || substring 0 2 x == "~/"); + description = types.str.description + " starting with / or ~/"; + }; + default = name; + description = lib.mdDoc '' + The path to the folder which should be shared. + Only absolute paths (starting with `/`) and paths relative to + the [user](#opt-services.syncthing.user)'s home directory + (starting with `~/`) are allowed. + ''; + }; - ignoreDelete = 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>. - ''; + id = mkOption { + type = types.str; + default = name; + description = lib.mdDoc '' + The ID of the folder. Must be the same on all devices. + ''; + }; + + label = mkOption { + type = types.str; + default = name; + description = lib.mdDoc '' + The label of the folder. + ''; + }; + + devices = mkOption { + type = types.listOf types.str; + default = []; + description = mdDoc '' + The devices this folder should be shared with. Each device must + be defined in the [devices](#opt-services.syncthing.settings.devices) option. + ''; + }; + + versioning = mkOption { + default = null; + description = mdDoc '' + How to keep changed/deleted files with Syncthing. + There are 4 different types of versioning with different parameters. + See <https://docs.syncthing.net/users/versioning.html>. + ''; + example = literalExpression '' + [ + { + versioning = { + type = "simple"; + params.keep = "10"; + }; + } + { + versioning = { + type = "trashcan"; + params.cleanoutDays = "1000"; + }; + } + { + versioning = { + type = "staggered"; + fsPath = "/syncthing/backup"; + params = { + cleanInterval = "3600"; + maxAge = "31536000"; + }; + }; + } + { + versioning = { + type = "external"; + params.versionsPath = pkgs.writers.writeBash "backup" ''' + folderpath="$1" + filepath="$2" + rm -rf "$folderpath/$filepath" + '''; + }; + } + ] + ''; + type = with types; nullOr (submodule { + options = { + type = mkOption { + type = enum [ "external" "simple" "staggered" "trashcan" ]; + description = mdDoc '' + The type of versioning. + See <https://docs.syncthing.net/users/versioning.html>. + ''; + }; + }; + }); + }; + + copyOwnershipFromParent = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + On Unix systems, tries to copy file/folder ownership from the parent directory (the directory it’s 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" ]; diff --git a/nixos/tests/syncthing-init.nix b/nixos/tests/syncthing-init.nix index fcd90739e6a55..435813e58066f 100644 --- a/nixos/tests/syncthing-init.nix +++ b/nixos/tests/syncthing-init.nix @@ -9,14 +9,16 @@ in { nodes.machine = { services.syncthing = { enable = true; - devices.testDevice = { - id = testId; + settings = { + devices.testDevice = { + id = testId; + }; + folders.testFolder = { + path = "/tmp/test"; + devices = [ "testDevice" ]; + }; + gui.user = "guiUser"; }; - folders.testFolder = { - path = "/tmp/test"; - devices = [ "testDevice" ]; - }; - extraOptions.gui.user = "guiUser"; }; }; |