diff options
Diffstat (limited to 'nixos/modules/services')
25 files changed, 1233 insertions, 705 deletions
diff --git a/nixos/modules/services/audio/jack.nix b/nixos/modules/services/audio/jack.nix new file mode 100644 index 000000000000..aa3351f401af --- /dev/null +++ b/nixos/modules/services/audio/jack.nix @@ -0,0 +1,290 @@ +{ 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. + ''; + }; + + dmixConfig = mkOption { + type = types.lines; + default = ""; + example = '' + period_size 2048 + periods 2 + ''; + description = '' + For music production software that still doesn't support JACK natively you + would like to put buffer/period adjustments here + to decrease dmix device latency. + ''; + }; + + 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 + ${cfg.loopback.dmixConfig} + } + } + 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/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index 7e3c230fff71..66d55b650a45 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -18,16 +18,12 @@ let in (pName mysql == pName pkgs.mysql57) && ((builtins.compareVersions mysql.version "5.7") >= 0); - pidFile = "${cfg.pidDir}/mysqld.pid"; - - mysqldAndInstallOptions = - "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}"; mysqldOptions = - "${mysqldAndInstallOptions} --pid-file=${pidFile}"; + "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}"; # For MySQL 5.7+, --insecure creates the root user without password # (earlier versions and MariaDB do this by default). installOptions = - "${mysqldAndInstallOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}"; + "${mysqldOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}"; in @@ -80,11 +76,6 @@ in description = "Location where MySQL stores its table files"; }; - pidDir = mkOption { - default = "/run/mysqld"; - description = "Location of the file which stores the PID of the MySQL server"; - }; - extraOptions = mkOption { type = types.lines; default = ""; @@ -296,6 +287,10 @@ in ${cfg.extraOptions} ''; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} mysql -" + ]; + systemd.services.mysql = let hasNotify = (cfg.package == pkgs.mariadb); in { @@ -313,70 +308,69 @@ in pkgs.nettools ]; - preStart = - '' - if ! test -e ${cfg.dataDir}/mysql; then - mkdir -m 0700 -p ${cfg.dataDir} - chown -R ${cfg.user} ${cfg.dataDir} - ${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${installOptions} - touch /tmp/mysql_init - fi - - mkdir -m 0755 -p ${cfg.pidDir} - chown -R ${cfg.user} ${cfg.pidDir} - ''; + preStart = '' + if ! test -e ${cfg.dataDir}/mysql; then + ${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${installOptions} + touch /tmp/mysql_init + fi + ''; serviceConfig = { + User = cfg.user; + Group = "mysql"; Type = if hasNotify then "notify" else "simple"; RuntimeDirectory = "mysqld"; + RuntimeDirectoryMode = "0755"; # The last two environment variables are used for starting Galera clusters ExecStart = "${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION"; }; - postStart = '' - ${lib.optionalString (!hasNotify) '' - # Wait until the MySQL server is available for use - count=0 - while [ ! -e /run/mysqld/mysqld.sock ] - do - if [ $count -eq 30 ] - then - echo "Tried 30 times, giving up..." - exit 1 - fi - - echo "MySQL daemon not yet started. Waiting for 1 second..." - count=$((count++)) - sleep 1 - done - ''} + postStart = + let + cmdWatchForMysqlSocket = '' + # Wait until the MySQL server is available for use + count=0 + while [ ! -e /run/mysqld/mysqld.sock ] + do + if [ $count -eq 30 ] + then + echo "Tried 30 times, giving up..." + exit 1 + fi + + echo "MySQL daemon not yet started. Waiting for 1 second..." + count=$((count++)) + sleep 1 + done + ''; + cmdInitialDatabases = concatMapStrings (database: '' + # Create initial databases + if ! test -e "${cfg.dataDir}/${database.name}"; then + echo "Creating initial database: ${database.name}" + ( echo 'create database `${database.name}`;' + + ${optionalString (database.schema != null) '' + echo 'use `${database.name}`;' + + # TODO: this silently falls through if database.schema does not exist, + # we should catch this somehow and exit, but can't do it here because we're in a subshell. + if [ -f "${database.schema}" ] + then + cat ${database.schema} + elif [ -d "${database.schema}" ] + then + cat ${database.schema}/mysql-databases/*.sql + fi + ''} + ) | ${mysql}/bin/mysql -u root -N + fi + '') cfg.initialDatabases; + in + lib.optionalString (!hasNotify) cmdWatchForMysqlSocket + '' if [ -f /tmp/mysql_init ] then - ${concatMapStrings (database: - '' - # Create initial databases - if ! test -e "${cfg.dataDir}/${database.name}"; then - echo "Creating initial database: ${database.name}" - ( echo 'create database `${database.name}`;' - - ${optionalString (database.schema != null) '' - echo 'use `${database.name}`;' - - # TODO: this silently falls through if database.schema does not exist, - # we should catch this somehow and exit, but can't do it here because we're in a subshell. - if [ -f "${database.schema}" ] - then - cat ${database.schema} - elif [ -d "${database.schema}" ] - then - cat ${database.schema}/mysql-databases/*.sql - fi - ''} - ) | ${mysql}/bin/mysql -u root -N - fi - '') cfg.initialDatabases} - + ${cmdInitialDatabases} ${optionalString (cfg.replication.role == "master") '' # Set up the replication master 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/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix index baa7c3ade52e..52ae25201c35 100644 --- a/nixos/modules/services/misc/octoprint.nix +++ b/nixos/modules/services/misc/octoprint.nix @@ -7,7 +7,7 @@ let cfg = config.services.octoprint; baseConfig = { - plugins.cura.cura_engine = "${pkgs.curaengine_stable}/bin/CuraEngine"; + plugins.curalegacy.cura_engine = "${pkgs.curaengine_stable}/bin/CuraEngine"; server.host = cfg.host; server.port = cfg.port; webcam.ffmpeg = "${pkgs.ffmpeg.bin}/bin/ffmpeg"; diff --git a/nixos/modules/services/misc/zoneminder.nix b/nixos/modules/services/misc/zoneminder.nix index 01720ba432ed..9c555e8031c4 100644 --- a/nixos/modules/services/misc/zoneminder.nix +++ b/nixos/modules/services/misc/zoneminder.nix @@ -229,6 +229,8 @@ in { location / { try_files $uri $uri/ /index.php?$args =404; + rewrite ^/skins/.*/css/fonts/(.*)$ /fonts/$1 permanent; + location ~ /api/(css|img|ico) { rewrite ^/api(.+)$ /api/app/webroot/$1 break; try_files $uri $uri/ =404; diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index fa53107ef24b..20e7eba43412 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -34,6 +34,7 @@ let unifi = import ./exporters/unifi.nix { inherit config lib pkgs; }; varnish = import ./exporters/varnish.nix { inherit config lib pkgs; }; bind = import ./exporters/bind.nix { inherit config lib pkgs; }; + wireguard = import ./exporters/wireguard.nix { inherit config lib pkgs; }; }; mkExporterOpts = ({ name, port }: { diff --git a/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix b/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix index a3f1d9d31323..530206681d36 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix @@ -28,7 +28,7 @@ in serviceConfig = { DynamicUser = true; ExecStart = '' - ${pkgs.prometheus-fritzbox-exporter}/bin/fritzbox_exporter \ + ${pkgs.prometheus-fritzbox-exporter}/bin/exporter \ -listen-address ${cfg.listenAddress}:${toString cfg.port} \ -gateway-address ${cfg.gatewayAddress} \ -gateway-port ${toString cfg.gatewayPort} \ diff --git a/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix b/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix new file mode 100644 index 000000000000..c5b84e574b8d --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix @@ -0,0 +1,42 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.wireguard; +in { + port = 9586; + extraOpts = { + verbose = mkEnableOption "Verbose logging mode for prometheus-wireguard-exporter"; + + wireguardConfig = mkOption { + type = with types; nullOr (either path str); + default = null; + + description = '' + Path to the Wireguard Config to + <link xlink:href="https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/2.0.0#usage">add the peer's name to the stats of a peer</link>. + + Please note that <literal>networking.wg-quick</literal> is required for this feature + as <literal>networking.wireguard</literal> uses + <citerefentry><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry> + to set the peers up. + ''; + }; + }; + serviceOpts = { + script = '' + ${pkgs.prometheus-wireguard-exporter}/bin/prometheus_wireguard_exporter \ + -p ${toString cfg.port} \ + ${optionalString cfg.verbose "-v"} \ + ${optionalString (cfg.wireguardConfig != null) "-n ${cfg.wireguardConfig}"} + ''; + + path = [ pkgs.wireguard-tools ]; + + serviceConfig = { + DynamicUser = true; + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + }; + }; +} 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 = '' |