diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/release-notes/rl-1909.xml | 12 | ||||
-rw-r--r-- | nixos/modules/misc/ids.nix | 4 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/audio/jack.nix | 275 | ||||
-rw-r--r-- | nixos/modules/services/desktops/geoclue2.nix | 13 | ||||
-rw-r--r-- | nixos/modules/services/networking/btsync.nix | 324 | ||||
-rw-r--r-- | nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix | 50 | ||||
-rw-r--r-- | nixos/modules/services/system/localtime.nix | 8 | ||||
-rw-r--r-- | nixos/modules/services/torrent/deluge.nix | 152 | ||||
-rw-r--r-- | nixos/modules/services/x11/compton.nix | 36 | ||||
-rw-r--r-- | nixos/modules/services/x11/redshift.nix | 8 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/grub/grub.nix | 1 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py | 2 | ||||
-rw-r--r-- | nixos/tests/deluge.nix | 49 |
14 files changed, 575 insertions, 361 deletions
diff --git a/nixos/doc/manual/release-notes/rl-1909.xml b/nixos/doc/manual/release-notes/rl-1909.xml index 665345d6f358..922239998ad6 100644 --- a/nixos/doc/manual/release-notes/rl-1909.xml +++ b/nixos/doc/manual/release-notes/rl-1909.xml @@ -114,6 +114,18 @@ </listitem> <listitem> <para> + Since Bittorrent Sync was superseded by Resilio Sync in 2016, the + <literal>bittorrentSync</literal>, <literal>bittorrentSync14</literal>, + and <literal>bittorrentSync16</literal> packages have been removed in + favor of <literal>resilio-sync</literal>. + </para> + <para> + The corresponding module, <option>services.btsync</option> has been + replaced by the <option>services.resilio</option> module. + </para> + </listitem> + <listitem> + <para> The limesurvey apache subservice was replaced with a full NixOS module. One can configure it using the <option>services.limesurvey.enable</option> and <option>services.limesurvey.virtualHost</option> options. diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 5b7fa5d2b98f..f1118f472e44 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -145,7 +145,7 @@ #notbit = 111; # unused aerospike = 111; ngircd = 112; - btsync = 113; + #btsync = 113; # unused minecraft = 114; vault = 115; rippled = 116; @@ -457,7 +457,7 @@ #notbit = 111; # unused aerospike = 111; #ngircd = 112; # unused - btsync = 113; + #btsync = 113; # unused #minecraft = 114; # unused vault = 115; #ripped = 116; # unused diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 5042470802f0..1017d25bf285 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -184,6 +184,7 @@ ./services/amqp/activemq/default.nix ./services/amqp/rabbitmq.nix ./services/audio/alsa.nix + ./services/audio/jack.nix ./services/audio/icecast.nix ./services/audio/liquidsoap.nix ./services/audio/mpd.nix @@ -542,7 +543,6 @@ ./services/networking/autossh.nix ./services/networking/bird.nix ./services/networking/bitlbee.nix - ./services/networking/btsync.nix ./services/networking/charybdis.nix ./services/networking/chrony.nix ./services/networking/cjdns.nix diff --git a/nixos/modules/services/audio/jack.nix b/nixos/modules/services/audio/jack.nix new file mode 100644 index 000000000000..1364abd40447 --- /dev/null +++ b/nixos/modules/services/audio/jack.nix @@ -0,0 +1,275 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.jack; + + pcmPlugin = cfg.jackd.enable && cfg.alsa.enable; + loopback = cfg.jackd.enable && cfg.loopback.enable; + + enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.isx86_64 && pkgs.pkgsi686Linux.alsaLib != null; + + umaskNeeded = versionOlder cfg.jackd.package.version "1.9.12"; + bridgeNeeded = versionAtLeast cfg.jackd.package.version "1.9.12"; +in { + options = { + services.jack = { + jackd = { + enable = mkEnableOption '' + JACK Audio Connection Kit. You need to add yourself to the "jackaudio" group + ''; + + package = mkOption { + # until jack1 promiscuous mode is fixed + internal = true; + type = types.package; + default = pkgs.jack2; + defaultText = "pkgs.jack2"; + example = literalExample "pkgs.jack1"; + description = '' + The JACK package to use. + ''; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = [ + "-dalsa" + ]; + example = literalExample '' + [ "-dalsa" "--device" "hw:1" ]; + ''; + description = '' + Specifies startup command line arguments to pass to JACK server. + ''; + }; + + session = mkOption { + type = types.lines; + description = '' + Commands to run after JACK is started. + ''; + }; + + }; + + alsa = { + enable = mkOption { + type = types.bool; + default = true; + description = '' + Route audio to/from generic ALSA-using applications using ALSA JACK PCM plugin. + ''; + }; + + support32Bit = mkOption { + type = types.bool; + default = false; + description = '' + Whether to support sound for 32-bit ALSA applications on 64-bit system. + ''; + }; + }; + + loopback = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Create ALSA loopback device, instead of using PCM plugin. Has broader + application support (things like Steam will work), but may need fine-tuning + for concrete hardware. + ''; + }; + + index = mkOption { + type = types.int; + default = 10; + description = '' + Index of an ALSA loopback device. + ''; + }; + + config = mkOption { + type = types.lines; + description = '' + ALSA config for loopback device. + ''; + }; + + session = mkOption { + type = types.lines; + description = '' + Additional commands to run to setup loopback device. + ''; + }; + }; + + }; + + }; + + config = mkMerge [ + + (mkIf pcmPlugin { + sound.extraConfig = '' + pcm_type.jack { + libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_jack.so ; + ${lib.optionalString enable32BitAlsaPlugins + "libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;"} + } + pcm.!default { + @func getenv + vars [ PCM ] + default "plug:jack" + } + ''; + }) + + (mkIf loopback { + boot.kernelModules = [ "snd-aloop" ]; + boot.kernelParams = [ "snd-aloop.index=${toString cfg.loopback.index}" ]; + sound.extraConfig = cfg.loopback.config; + }) + + (mkIf cfg.jackd.enable { + services.jack.jackd.session = '' + ${lib.optionalString bridgeNeeded "${pkgs.a2jmidid}/bin/a2jmidid -e &"} + ''; + # https://alsa.opensrc.org/Jack_and_Loopback_device_as_Alsa-to-Jack_bridge#id06 + services.jack.loopback.config = '' + pcm.loophw00 { + type hw + card ${toString cfg.loopback.index} + device 0 + subdevice 0 + } + pcm.amix { + type dmix + ipc_key 219345 + slave { + pcm loophw00 + } + } + pcm.asoftvol { + type softvol + slave.pcm "amix" + control { name Master } + } + pcm.cloop { + type hw + card ${toString cfg.loopback.index} + device 1 + subdevice 0 + format S32_LE + } + pcm.loophw01 { + type hw + card ${toString cfg.loopback.index} + device 0 + subdevice 1 + } + pcm.ploop { + type hw + card ${toString cfg.loopback.index} + device 1 + subdevice 1 + format S32_LE + } + pcm.aduplex { + type asym + playback.pcm "asoftvol" + capture.pcm "loophw01" + } + pcm.!default { + type plug + slave.pcm aduplex + } + ''; + services.jack.loopback.session = '' + alsa_in -j cloop -dcloop & + alsa_out -j ploop -dploop & + while [ "$(jack_lsp cloop)" == "" ] || [ "$(jack_lsp ploop)" == "" ]; do sleep 1; done + jack_connect cloop:capture_1 system:playback_1 + jack_connect cloop:capture_2 system:playback_2 + jack_connect system:capture_1 ploop:playback_1 + jack_connect system:capture_2 ploop:playback_2 + ''; + + assertions = [ + { + assertion = !(cfg.alsa.enable && cfg.loopback.enable); + message = "For JACK both alsa and loopback options shouldn't be used at the same time."; + } + ]; + + users.users.jackaudio = { + group = "jackaudio"; + extraGroups = [ "audio" ]; + description = "JACK Audio system service user"; + }; + # http://jackaudio.org/faq/linux_rt_config.html + security.pam.loginLimits = [ + { domain = "@jackaudio"; type = "-"; item = "rtprio"; value = "99"; } + { domain = "@jackaudio"; type = "-"; item = "memlock"; value = "unlimited"; } + ]; + users.groups.jackaudio = {}; + + environment = { + systemPackages = [ cfg.jackd.package ]; + etc."alsa/conf.d/50-jack.conf".source = "${pkgs.alsaPlugins}/etc/alsa/conf.d/50-jack.conf"; + variables.JACK_PROMISCUOUS_SERVER = "jackaudio"; + }; + + services.udev.extraRules = '' + ACTION=="add", SUBSYSTEM=="sound", ATTRS{id}!="Loopback", TAG+="systemd", ENV{SYSTEMD_WANTS}="jack.service" + ''; + + systemd.services.jack = { + description = "JACK Audio Connection Kit"; + serviceConfig = { + User = "jackaudio"; + ExecStart = "${cfg.jackd.package}/bin/jackd ${lib.escapeShellArgs cfg.jackd.extraOptions}"; + LimitRTPRIO = 99; + LimitMEMLOCK = "infinity"; + } // optionalAttrs umaskNeeded { + UMask = "007"; + }; + path = [ cfg.jackd.package ]; + environment = { + JACK_PROMISCUOUS_SERVER = "jackaudio"; + JACK_NO_AUDIO_RESERVATION = "1"; + }; + restartIfChanged = false; + }; + systemd.services.jack-session = { + description = "JACK session"; + script = '' + jack_wait -w + ${cfg.jackd.session} + ${lib.optionalString cfg.loopback.enable cfg.loopback.session} + ''; + serviceConfig = { + RemainAfterExit = true; + User = "jackaudio"; + StateDirectory = "jack"; + LimitRTPRIO = 99; + LimitMEMLOCK = "infinity"; + }; + path = [ cfg.jackd.package ]; + environment = { + JACK_PROMISCUOUS_SERVER = "jackaudio"; + HOME = "/var/lib/jack"; + }; + wantedBy = [ "jack.service" ]; + partOf = [ "jack.service" ]; + after = [ "jack.service" ]; + restartIfChanged = false; + }; + }) + + ]; + + meta.maintainers = [ maintainers.gnidorah ]; +} diff --git a/nixos/modules/services/desktops/geoclue2.nix b/nixos/modules/services/desktops/geoclue2.nix index a16dbc04a5f7..040fe157d52d 100644 --- a/nixos/modules/services/desktops/geoclue2.nix +++ b/nixos/modules/services/desktops/geoclue2.nix @@ -188,6 +188,19 @@ in systemd.packages = [ package ]; + users.users.geoclue = { + isSystemUser = true; + home = "/var/lib/geoclue"; + group = "geoclue"; + description = "Geoinformation service"; + }; + + users.groups.geoclue = {}; + + systemd.tmpfiles.rules = [ + "d /var/lib/geoclue 0755 geoclue geoclue" + ]; + # restart geoclue service when the configuration changes systemd.services."geoclue".restartTriggers = [ config.environment.etc."geoclue/geoclue.conf".source diff --git a/nixos/modules/services/networking/btsync.nix b/nixos/modules/services/networking/btsync.nix deleted file mode 100644 index 33e85ef58e6e..000000000000 --- a/nixos/modules/services/networking/btsync.nix +++ /dev/null @@ -1,324 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.btsync; - - bittorrentSync = cfg.package; - - listenAddr = cfg.httpListenAddr + ":" + (toString cfg.httpListenPort); - - optionalEmptyStr = b: v: optionalString (b != "") v; - - webUIConfig = optionalString cfg.enableWebUI - '' - "webui": - { - ${optionalEmptyStr cfg.httpLogin "\"login\": \"${cfg.httpLogin}\","} - ${optionalEmptyStr cfg.httpPass "\"password\": \"${cfg.httpPass}\","} - ${optionalEmptyStr cfg.apiKey "\"api_key\": \"${cfg.apiKey}\","} - ${optionalEmptyStr cfg.directoryRoot "\"directory_root\": \"${cfg.directoryRoot}\","} - "listen": "${listenAddr}" - } - ''; - - knownHosts = e: - optionalString (e ? "knownHosts") - (concatStringsSep "," (map (v: "\"${v}\"") e."knownHosts")); - - sharedFoldersRecord = - concatStringsSep "," (map (entry: - let helper = attr: v: - if (entry ? attr) then boolToString entry.attr else boolToString v; - in - '' - { - "secret": "${entry.secret}", - "dir": "${entry.directory}", - - "use_relay_server": ${helper "useRelayServer" true}, - "use_tracker": ${helper "useTracker" true}, - "use_dht": ${helper "useDHT" false}, - - "search_lan": ${helper "searchLAN" true}, - "use_sync_trash": ${helper "useSyncTrash" true}, - - "known_hosts": [${knownHosts entry}] - } - '') cfg.sharedFolders); - - sharedFoldersConfig = optionalString (cfg.sharedFolders != []) - '' - "shared_folders": - [ - ${sharedFoldersRecord} - ] - ''; - - configFile = pkgs.writeText "btsync.config" - '' - { - "device_name": "${cfg.deviceName}", - "storage_path": "${cfg.storagePath}", - "listening_port": ${toString cfg.listeningPort}, - "use_gui": false, - - "check_for_updates": ${boolToString cfg.checkForUpdates}, - "use_upnp": ${boolToString cfg.useUpnp}, - "download_limit": ${toString cfg.downloadLimit}, - "upload_limit": ${toString cfg.uploadLimit}, - "lan_encrypt_data": ${boolToString cfg.encryptLAN}, - - ${webUIConfig} - ${sharedFoldersConfig} - } - ''; -in -{ - options = { - services.btsync = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - If enabled, start the Bittorrent Sync daemon. Once enabled, you can - interact with the service through the Web UI, or configure it in your - NixOS configuration. Enabling the <literal>btsync</literal> service - also installs a systemd user unit which can be used to start - user-specific copies of the daemon. Once installed, you can use - <literal>systemctl --user start btsync</literal> as your user to start - the daemon using the configuration file located at - <literal>$HOME/.config/btsync.conf</literal>. - ''; - }; - - deviceName = mkOption { - type = types.str; - example = "Voltron"; - description = '' - Name of the Bittorrent Sync device. - ''; - }; - - listeningPort = mkOption { - type = types.int; - default = 0; - example = 44444; - description = '' - Listening port. Defaults to 0 which randomizes the port. - ''; - }; - - checkForUpdates = mkOption { - type = types.bool; - default = true; - description = '' - Determines whether to check for updates and alert the user - about them in the UI. - ''; - }; - - useUpnp = mkOption { - type = types.bool; - default = true; - description = '' - Use Universal Plug-n-Play (UPnP) - ''; - }; - - downloadLimit = mkOption { - type = types.int; - default = 0; - example = 1024; - description = '' - Download speed limit. 0 is unlimited (default). - ''; - }; - - uploadLimit = mkOption { - type = types.int; - default = 0; - example = 1024; - description = '' - Upload speed limit. 0 is unlimited (default). - ''; - }; - - httpListenAddr = mkOption { - type = types.str; - default = "0.0.0.0"; - example = "1.2.3.4"; - description = '' - HTTP address to bind to. - ''; - }; - - httpListenPort = mkOption { - type = types.int; - default = 9000; - description = '' - HTTP port to bind on. - ''; - }; - - httpLogin = mkOption { - type = types.str; - example = "allyourbase"; - default = ""; - description = '' - HTTP web login username. - ''; - }; - - httpPass = mkOption { - type = types.str; - example = "arebelongtous"; - default = ""; - description = '' - HTTP web login password. - ''; - }; - - encryptLAN = mkOption { - type = types.bool; - default = true; - description = "Encrypt LAN data."; - }; - - enableWebUI = mkOption { - type = types.bool; - default = false; - description = '' - Enable Web UI for administration. Bound to the specified - <literal>httpListenAddress</literal> and - <literal>httpListenPort</literal>. - ''; - }; - - package = mkOption { - type = types.package; - example = literalExample "pkgs.bittorrentSync20"; - description = '' - Branch of bittorrent sync to use. - ''; - }; - - storagePath = mkOption { - type = types.path; - default = "/var/lib/btsync/"; - description = '' - Where BitTorrent Sync will store it's database files (containing - things like username info and licenses). Generally, you should not - need to ever change this. - ''; - }; - - apiKey = mkOption { - type = types.str; - default = ""; - description = "API key, which enables the developer API."; - }; - - directoryRoot = mkOption { - type = types.str; - default = ""; - example = "/media"; - description = "Default directory to add folders in the web UI."; - }; - - sharedFolders = mkOption { - default = []; - example = - [ { secret = "AHMYFPCQAHBM7LQPFXQ7WV6Y42IGUXJ5Y"; - directory = "/home/user/sync_test"; - useRelayServer = true; - useTracker = true; - useDHT = false; - searchLAN = true; - useSyncTrash = true; - knownHosts = - [ "192.168.1.2:4444" - "192.168.1.3:4444" - ]; - } - ]; - description = '' - Shared folder list. If enabled, web UI must be - disabled. Secrets can be generated using <literal>btsync - --generate-secret</literal>. Note that this secret will be - put inside the Nix store, so it is realistically not very - secret. - - If you would like to be able to modify the contents of this - directories, it is recommended that you make your user a - member of the <literal>btsync</literal> group. - - Directories in this list should be in the - <literal>btsync</literal> group, and that group must have - write access to the directory. It is also recommended that - <literal>chmod g+s</literal> is applied to the directory - so that any sub directories created will also belong to - the <literal>btsync</literal> group. Also, - <literal>setfacl -d -m group:btsync:rwx</literal> and - <literal>setfacl -m group:btsync:rwx</literal> should also - be applied so that the sub directories are writable by - the group. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - assertions = - [ { assertion = cfg.deviceName != ""; - message = "Device name cannot be empty."; - } - { assertion = cfg.enableWebUI -> cfg.sharedFolders == []; - message = "If using shared folders, the web UI cannot be enabled."; - } - { assertion = cfg.apiKey != "" -> cfg.enableWebUI; - message = "If you're using an API key, you must enable the web server."; - } - ]; - - services.btsync.package = mkOptionDefault pkgs.bittorrentSync14; - - users.users.btsync = { - description = "Bittorrent Sync Service user"; - home = cfg.storagePath; - createHome = true; - uid = config.ids.uids.btsync; - group = "btsync"; - }; - - users.groups = [ - { name = "btsync"; - }]; - - systemd.services.btsync = with pkgs; { - description = "Bittorrent Sync Service"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" "local-fs.target" ]; - serviceConfig = { - Restart = "on-abort"; - UMask = "0002"; - User = "btsync"; - ExecStart = - "${bittorrentSync}/bin/btsync --nodaemon --config ${configFile}"; - }; - }; - - systemd.user.services.btsync = with pkgs; { - description = "Bittorrent Sync user service"; - after = [ "network.target" "local-fs.target" ]; - serviceConfig = { - Restart = "on-abort"; - ExecStart = - "${bittorrentSync}/bin/btsync --nodaemon --config %h/.config/btsync.conf"; - }; - }; - - environment.systemPackages = [ cfg.package ]; - }; -} diff --git a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix index d4f7e95f859f..808cb863a9cf 100644 --- a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix +++ b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix @@ -6,7 +6,7 @@ # # git clone https://github.com/strongswan/strongswan.git # cd strongswan -# git diff 5.5.3..5.6.0 src/swanctl/swanctl.opt +# git diff 5.7.2..5.8.0 src/swanctl/swanctl.opt lib: with (import ./param-constructors.nix lib); @@ -227,6 +227,22 @@ in { irrespective of the value of this option (even when set to no). ''; + childless = mkEnumParam [ "allow" "force" "never" ] "allow" '' + Use childless IKE_SA initiation (RFC 6023) for IKEv2. Acceptable values + are <literal>allow</literal> (the default), <literal>force</literal> and + <literal>never</literal>. If set to <literal>allow</literal>, responders + will accept childless IKE_SAs (as indicated via notify in the IKE_SA_INIT + response) while initiators continue to create regular IKE_SAs with the + first CHILD_SA created during IKE_AUTH, unless the IKE_SA is initiated + explicitly without any children (which will fail if the responder does not + support or has disabled this extension). If set to + <literal>force</literal>, only childless initiation is accepted and the + first CHILD_SA is created with a separate CREATE_CHILD_SA exchange + (e.g. to use an independent DH exchange for all CHILD_SAs). Finally, + setting the option to <literal>never</literal> disables support for + childless IKE_SAs as responder. + ''; + send_certreq = mkYesNoParam yes '' Send certificate request payloads to offer trusted root CA certificates to the peer. Certificate requests help the peer to choose an appropriate @@ -350,6 +366,16 @@ in { name from either the pools section or an external pool. ''; + if_id_in = mkStrParam "0" '' + XFRM interface ID set on inbound policies/SA, can be overridden by child + config, see there for details. + ''; + + if_id_out = mkStrParam "0" '' + XFRM interface ID set on outbound policies/SA, can be overridden by child + config, see there for details. + ''; + mediation = mkYesNoParam no '' Whether this connection is a mediation connection, that is, whether this connection is used to mediate other connections using the IKEv2 Mediation @@ -799,7 +825,7 @@ in { Updown script to invoke on CHILD_SA up and down events. ''; - hostaccess = mkYesNoParam yes '' + hostaccess = mkYesNoParam no '' Hostaccess variable to pass to <literal>updown</literal> script. ''; @@ -960,6 +986,26 @@ in { mask requires at least Linux 4.19. ''; + if_id_in = mkStrParam "0" '' + XFRM interface ID set on inbound policies/SA. This allows installing + duplicate policies/SAs and associates them with an interface with the + same ID. The special value <literal>%unique</literal> sets a unique + interface ID on each CHILD_SA instance, beyond that the value + <literal>%unique-dir</literal> assigns a different unique interface ID + for each CHILD_SA direction (in/out). + ''; + + if_id_out = mkStrParam "0" '' + XFRM interface ID set on outbound policies/SA. This allows installing + duplicate policies/SAs and associates them with an interface with the + same ID. The special value <literal>%unique</literal> sets a unique + interface ID on each CHILD_SA instance, beyond that the value + <literal>%unique-dir</literal> assigns a different unique interface ID + for each CHILD_SA direction (in/out). + + The daemon will not install routes for CHILD_SAs that have this option set. + ''; + tfc_padding = mkParamOfType (with lib.types; either int (enum ["mtu"])) 0 '' Pads ESP packets with additional data to have a consistent ESP packet size for improved Traffic Flow Confidentiality. The padding defines the diff --git a/nixos/modules/services/system/localtime.nix b/nixos/modules/services/system/localtime.nix index c7e897c96448..8e9286b94078 100644 --- a/nixos/modules/services/system/localtime.nix +++ b/nixos/modules/services/system/localtime.nix @@ -20,7 +20,13 @@ in { }; config = mkIf cfg.enable { - services.geoclue2.enable = true; + services.geoclue2 = { + enable = true; + appConfig."localtime" = { + isAllowed = true; + isSystem = true; + }; + }; # so polkit will pick up the rules environment.systemPackages = [ pkgs.localtime ]; diff --git a/nixos/modules/services/torrent/deluge.nix b/nixos/modules/services/torrent/deluge.nix index 84f0437b9411..01a5890a7845 100644 --- a/nixos/modules/services/torrent/deluge.nix +++ b/nixos/modules/services/torrent/deluge.nix @@ -5,8 +5,33 @@ with lib; let cfg = config.services.deluge; cfg_web = config.services.deluge.web; + openFilesLimit = 4096; + listenPortsDefault = [ 6881 6889 ]; + + listToRange = x: { from = elemAt x 0; to = elemAt x 1; }; + + configDir = "${cfg.dataDir}/.config/deluge"; + configFile = pkgs.writeText "core.conf" (builtins.toJSON cfg.config); + declarativeLockFile = "${configDir}/.declarative"; + preStart = if cfg.declarative then '' + if [ -e ${declarativeLockFile} ]; then + # Was declarative before, no need to back up anything + ln -sf ${configFile} ${configDir}/core.conf + ln -sf ${cfg.authFile} ${configDir}/auth + else + # Declarative for the first time, backup stateful files + ln -sb --suffix=.stateful ${configFile} ${configDir}/core.conf + ln -sb --suffix=.stateful ${cfg.authFile} ${configDir}/auth + echo "Autogenerated file that signifies that this server configuration is managed declaratively by NixOS" \ + > ${declarativeLockFile} + fi + '' else '' + if [ -e ${declarativeLockFile} ]; then + rm ${declarativeLockFile} + fi + ''; in { options = { services = { @@ -15,42 +40,151 @@ in { openFilesLimit = mkOption { default = openFilesLimit; - example = 8192; description = '' Number of files to allow deluged to open. ''; }; + + config = mkOption { + type = types.attrs; + default = {}; + example = literalExample '' + { + download_location = "/srv/torrents/"; + max_upload_speed = "1000.0"; + share_ratio_limit = "2.0"; + allow_remote = true; + daemon_port = 58846; + listen_ports = [ ${toString listenPortsDefault} ]; + } + ''; + description = '' + Deluge core configuration for the core.conf file. Only has an effect + when <option>services.deluge.declarative</option> is set to + <literal>true</literal>. String values must be quoted, integer and + boolean values must not. See + <link xlink:href="https://git.deluge-torrent.org/deluge/tree/deluge/core/preferencesmanager.py#n41"/> + for the availaible options. + ''; + }; + + declarative = mkOption { + type = types.bool; + default = false; + description = '' + Whether to use a declarative deluge configuration. + Only if set to <literal>true</literal>, the options + <option>services.deluge.config</option>, + <option>services.deluge.openFirewall</option> and + <option>services.deluge.authFile</option> will be + applied. + ''; + }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = '' + Whether to open the firewall for the ports in + <option>services.deluge.config.listen_ports</option>. It only takes effet if + <option>services.deluge.declarative</option> is set to + <literal>true</literal>. + + It does NOT apply to the daemon port nor the web UI port. To access those + ports secuerly check the documentation + <link xlink:href="https://dev.deluge-torrent.org/wiki/UserGuide/ThinClient#CreateSSHTunnel"/> + or use a VPN or configure certificates for deluge. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/deluge"; + description = '' + The directory where deluge will create files. + ''; + }; + + authFile = mkOption { + type = types.path; + example = "/run/keys/deluge-auth"; + description = '' + The file managing the authentication for deluge, the format of this + file is straightforward, each line contains a + username:password:level tuple in plaintext. It only has an effect + when <option>services.deluge.declarative</option> is set to + <literal>true</literal>. + See <link xlink:href="https://dev.deluge-torrent.org/wiki/UserGuide/Authentication"/> for + more informations. + ''; + }; }; - deluge.web.enable = mkEnableOption "Deluge Web daemon"; + deluge.web = { + enable = mkEnableOption "Deluge Web daemon"; + port = mkOption { + type = types.port; + default = 8112; + description = '' + Deluge web UI port. + ''; + }; + }; }; }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ "d '${configDir}' 0770 deluge deluge" ] + ++ optional (cfg.config ? "download_location") + "d '${cfg.config.download_location}' 0770 deluge deluge" + ++ optional (cfg.config ? "torrentfiles_location") + "d '${cfg.config.torrentfiles_location}' 0770 deluge deluge" + ++ optional (cfg.config ? "move_completed_path") + "d '${cfg.config.move_completed_path}' 0770 deluge deluge"; + systemd.services.deluged = { after = [ "network.target" ]; description = "Deluge BitTorrent Daemon"; wantedBy = [ "multi-user.target" ]; path = [ pkgs.deluge ]; serviceConfig = { - ExecStart = "${pkgs.deluge}/bin/deluged -d"; - # To prevent "Quit & shutdown daemon" from working; we want systemd to manage it! + ExecStart = '' + ${pkgs.deluge}/bin/deluged \ + --do-not-daemonize \ + --config ${configDir} + ''; + # To prevent "Quit & shutdown daemon" from working; we want systemd to + # manage it! Restart = "on-success"; User = "deluge"; Group = "deluge"; + UMask = "0002"; LimitNOFILE = cfg.openFilesLimit; }; + preStart = preStart; }; systemd.services.delugeweb = mkIf cfg_web.enable { - after = [ "network.target" ]; + after = [ "network.target" "deluged.service"]; + requires = [ "deluged.service" ]; description = "Deluge BitTorrent WebUI"; wantedBy = [ "multi-user.target" ]; path = [ pkgs.deluge ]; - serviceConfig.ExecStart = "${pkgs.deluge}/bin/deluge --ui web"; - serviceConfig.User = "deluge"; - serviceConfig.Group = "deluge"; + serviceConfig = { + ExecStart = '' + ${pkgs.deluge}/bin/deluge-web \ + --config ${configDir} \ + --port ${toString cfg.web.port} + ''; + User = "deluge"; + Group = "deluge"; + }; + }; + + networking.firewall = mkIf (cfg.declarative && cfg.openFirewall && !(cfg.config.random_port or true)) { + allowedTCPPortRanges = singleton (listToRange (cfg.config.listen_ports or listenPortsDefault)); + allowedUDPPortRanges = singleton (listToRange (cfg.config.listen_ports or listenPortsDefault)); }; environment.systemPackages = [ pkgs.deluge ]; @@ -58,7 +192,7 @@ in { users.users.deluge = { group = "deluge"; uid = config.ids.uids.deluge; - home = "/var/lib/deluge/"; + home = cfg.dataDir; createHome = true; description = "Deluge Daemon user"; }; diff --git a/nixos/modules/services/x11/compton.nix b/nixos/modules/services/x11/compton.nix index 11db0a133d6d..d4357324c870 100644 --- a/nixos/modules/services/x11/compton.nix +++ b/nixos/modules/services/x11/compton.nix @@ -7,10 +7,19 @@ let cfg = config.services.compton; + literalAttrs = v: + if isString v then toString v + else if isAttrs v then "{\n" + + concatStringsSep "\n" (mapAttrsToList + (name: value: "${literalAttrs name} = ${literalAttrs value};") + v) + + "\n}" + else generators.toPretty {} v; + floatBetween = a: b: with lib; with types; addCheck str (x: versionAtLeast x a && versionOlder x b); - pairOf = x: with types; addCheck (listOf x) (y: lib.length y == 2); + pairOf = x: with types; addCheck (listOf x) (y: length y == 2); opacityRules = optionalString (length cfg.opacityRules != 0) (concatMapStringsSep ",\n" (rule: ''"${rule}"'') cfg.opacityRules); @@ -23,8 +32,7 @@ let fade-in-step = ${elemAt cfg.fadeSteps 0}; fade-out-step = ${elemAt cfg.fadeSteps 1}; fade-exclude = ${toJSON cfg.fadeExclude}; - '' + - optionalString cfg.shadow '' + '' + optionalString cfg.shadow '' # shadows shadow = true; @@ -39,10 +47,7 @@ let inactive-opacity = ${cfg.inactiveOpacity}; wintypes: - { - popup_menu = { opacity = ${cfg.menuOpacity}; } - dropdown_menu = { opacity = ${cfg.menuOpacity}; } - }; + ${literalAttrs cfg.wintypes}; opacity-rule = [ ${opacityRules} @@ -50,7 +55,7 @@ let # other options backend = ${toJSON cfg.backend}; - vsync = ${lib.boolToString cfg.vSync}; + vsync = ${boolToString cfg.vSync}; refresh-rate = ${toString cfg.refreshRate}; '' + cfg.extraOptions); @@ -98,7 +103,7 @@ in { example = [ "window_type *= 'menu'" "name ~= 'Firefox$'" - "focused = 1" + "focused = 1" ]; description = '' List of conditions of windows that should not be faded. @@ -138,7 +143,7 @@ in { example = [ "window_type *= 'menu'" "name ~= 'Firefox$'" - "focused = 1" + "focused = 1" ]; description = '' List of conditions of windows that should have no shadow. @@ -173,6 +178,15 @@ in { ''; }; + wintypes = mkOption { + type = types.attrs; + default = { popup_menu = { opacity = cfg.menuOpacity; }; dropdown_menu = { opacity = cfg.menuOpacity; }; }; + example = {}; + description = '' + Rules for specific window types. + ''; + }; + opacityRules = mkOption { type = types.listOf types.str; default = []; @@ -201,7 +215,7 @@ in { let res = x != "none"; msg = "The type of services.compton.vSync has changed to bool:" - + " interpreting ${x} as ${lib.boolToString res}"; + + " interpreting ${x} as ${boolToString res}"; in if isBool x then x else warn msg res; diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix index b7dd7debcb63..4345a3348081 100644 --- a/nixos/modules/services/x11/redshift.nix +++ b/nixos/modules/services/x11/redshift.nix @@ -119,7 +119,13 @@ in { # needed so that .desktop files are installed, which geoclue cares about environment.systemPackages = [ cfg.package ]; - services.geoclue2.enable = mkIf (cfg.provider == "geoclue2") true; + services.geoclue2 = mkIf (cfg.provider == "geoclue2") { + enable = true; + appConfig."redshift" = { + isAllowed = true; + isSystem = true; + }; + }; systemd.user.services.redshift = let diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 99aa7759c954..4e4d14985b0d 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -360,6 +360,7 @@ in font = mkOption { type = types.nullOr types.path; default = "${realGrub}/share/grub/unicode.pf2"; + defaultText = ''"''${pkgs.grub2}/share/grub/unicode.pf2"''; description = '' Path to a TrueType, OpenType, or pf2 font to be used by Grub. ''; diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index 940d4c0eb973..ebe37ca10a2d 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -154,7 +154,7 @@ def remove_old_entries(gens): except ValueError: pass for path in glob.iglob("@efiSysMountPoint@/efi/nixos/*"): - if not path in known_paths: + if not path in known_paths and not os.path.isdir(path): os.unlink(path) def get_profiles(): diff --git a/nixos/tests/deluge.nix b/nixos/tests/deluge.nix index b4be5e465cc0..22ad84e7bff1 100644 --- a/nixos/tests/deluge.nix +++ b/nixos/tests/deluge.nix @@ -5,25 +5,56 @@ import ./make-test.nix ({ pkgs, ...} : { }; nodes = { - server = + simple = { + services.deluge = { + enable = true; + web.enable = true; + }; + networking.firewall.allowedTCPPorts = [ 8112 ]; + }; + + declarative = { ... }: - { services.deluge = { + { + services.deluge = { enable = true; - web.enable = true; + openFirewall = true; + declarative = true; + config = { + allow_remote = true; + download_location = "/var/lib/deluge/my-download"; + daemon_port = 58846; + listen_ports = [ 6881 6889 ]; + }; + web = { + enable = true; + port = 3142; + }; + authFile = pkgs.writeText "deluge-auth" '' + localclient:a7bef72a890:10 + andrew:password:10 + user3:anotherpass:5 + ''; }; - networking.firewall.allowedTCPPorts = [ 8112 ]; + environment.systemPackages = [ pkgs.deluge ]; }; - client = { }; }; testScript = '' startAll; - $server->waitForUnit("deluged"); - $server->waitForUnit("delugeweb"); - $client->waitForUnit("network.target"); - $client->waitUntilSucceeds("curl --fail http://server:8112"); + $simple->waitForUnit("deluged"); + $simple->waitForUnit("delugeweb"); + $simple->waitForOpenPort("8112"); + $declarative->waitForUnit("network.target"); + $declarative->waitUntilSucceeds("curl --fail http://simple:8112"); + + $declarative->waitForUnit("deluged"); + $declarative->waitForUnit("delugeweb"); + $declarative->waitUntilSucceeds("curl --fail http://declarative:3142"); + $declarative->succeed("deluge-console 'help' | grep -q 'rm - Remove a torrent'"); + $declarative->succeed("deluge-console 'connect 127.0.0.1:58846 andrew password; help' | grep -q 'rm - Remove a torrent'"); ''; }) |