diff options
author | Luke Granger-Brown <git@lukegb.com> | 2021-06-30 23:10:54 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-30 23:10:54 +0100 |
commit | ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183 (patch) | |
tree | 80f5345bab405c0f4a41ad00d1a3fbe5d062734c /nixos/modules | |
parent | 2b220cc57b198ae353afaf2b1859533c60e50bc0 (diff) | |
parent | 272773e1cbdd2f55f174b9b842669a39a64a700d (diff) | |
download | nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.tar nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.tar.gz nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.tar.bz2 nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.tar.lz nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.tar.xz nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.tar.zst nixpkgs-ef4e133b1cd2f118b8826bb1f92dd3b0e2b28183.zip |
Merge branch 'master' into Xe/tailscale-sysctl-not-found
Diffstat (limited to 'nixos/modules')
88 files changed, 1515 insertions, 481 deletions
diff --git a/nixos/modules/config/console.nix b/nixos/modules/config/console.nix index 5be7f06c05d..c5150305bd8 100644 --- a/nixos/modules/config/console.nix +++ b/nixos/modules/config/console.nix @@ -43,13 +43,14 @@ in options.console = { font = mkOption { - type = types.str; + type = with types; either str path; default = "Lat2-Terminus16"; example = "LatArCyrHeb-16"; description = '' The font used for the virtual consoles. Leave empty to use whatever the <command>setfont</command> program considers the default font. + Can be either a font name or a path to a PSF font file. ''; }; diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 0266bbfb121..3f7ae109e8c 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -17,9 +17,9 @@ let binary = "${getBin overriddenPackage}/bin/pulseaudio"; binaryNoDaemon = "${binary} --daemonize=no"; - # Forces 32bit pulseaudio and alsaPlugins to be built/supported for apps + # Forces 32bit pulseaudio and alsa-plugins to be built/supported for apps # using 32bit alsa on 64bit linux. - enable32BitAlsaPlugins = cfg.support32Bit && stdenv.isx86_64 && (pkgs.pkgsi686Linux.alsaLib != null && pkgs.pkgsi686Linux.libpulseaudio != null); + enable32BitAlsaPlugins = cfg.support32Bit && stdenv.isx86_64 && (pkgs.pkgsi686Linux.alsa-lib != null && pkgs.pkgsi686Linux.libpulseaudio != null); myConfigFile = @@ -62,18 +62,18 @@ let # plugin. alsaConf = writeText "asound.conf" ('' pcm_type.pulse { - libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ; + libs.native = ${pkgs.alsa-plugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ; ${lib.optionalString enable32BitAlsaPlugins - "libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ;"} + "libs.32Bit = ${pkgs.pkgsi686Linux.alsa-plugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ;"} } pcm.!default { type pulse hint.description "Default Audio Device (via PulseAudio)" } ctl_type.pulse { - libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ; + libs.native = ${pkgs.alsa-plugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ; ${lib.optionalString enable32BitAlsaPlugins - "libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;"} + "libs.32Bit = ${pkgs.pkgsi686Linux.alsa-plugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;"} } ctl.!default { type pulse diff --git a/nixos/modules/config/swap.nix b/nixos/modules/config/swap.nix index 59bc9e9d11e..a37b46b8c46 100644 --- a/nixos/modules/config/swap.nix +++ b/nixos/modules/config/swap.nix @@ -114,6 +114,19 @@ let ''; }; + discardPolicy = mkOption { + default = null; + example = "once"; + type = types.nullOr (types.enum ["once" "pages" "both" ]); + description = '' + Specify the discard policy for the swap device. If "once", then the + whole swap space is discarded at swapon invocation. If "pages", + asynchronous discard on freed pages is performed, before returning to + the available pages pool. With "both", both policies are activated. + See swapon(8) for more information. + ''; + }; + deviceName = mkOption { type = types.str; internal = true; diff --git a/nixos/modules/config/xdg/portals/wlr.nix b/nixos/modules/config/xdg/portals/wlr.nix new file mode 100644 index 00000000000..55baab0026b --- /dev/null +++ b/nixos/modules/config/xdg/portals/wlr.nix @@ -0,0 +1,67 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.xdg.portal.wlr; + package = pkgs.xdg-desktop-portal-wlr; + settingsFormat = pkgs.formats.ini { }; + configFile = settingsFormat.generate "xdg-desktop-portal-wlr.ini" cfg.settings; +in +{ + meta = { + maintainers = with maintainers; [ minijackson ]; + }; + + options.xdg.portal.wlr = { + enable = mkEnableOption '' + desktop portal for wlroots-based desktops + + This will add the <package>xdg-desktop-portal-wlr</package> package into + the <option>xdg.portal.extraPortals</option> option, and provide the + configuration file + ''; + + settings = mkOption { + description = '' + Configuration for <package>xdg-desktop-portal-wlr</package>. + + See <literal>xdg-desktop-portal-wlr(5)</literal> for supported + values. + ''; + + type = types.submodule { + freeformType = settingsFormat.type; + }; + + default = { }; + + # Example taken from the manpage + example = literalExample '' + { + screencast = { + output_name = "HDMI-A-1"; + max_fps = 30; + exec_before = "disable_notifications.sh"; + exec_after = "enable_notifications.sh"; + chooser_type = "simple"; + chooser_cmd = "''${pkgs.slurp}/bin/slurp -f %o -or"; + }; + } + ''; + }; + }; + + config = mkIf cfg.enable { + xdg.portal = { + enable = true; + extraPortals = [ package ]; + }; + + systemd.user.services.xdg-desktop-portal-wlr.serviceConfig.ExecStart = [ + # Empty ExecStart value to override the field + "" + "${package}/libexec/xdg-desktop-portal-wlr --config=${configFile}" + ]; + }; +} diff --git a/nixos/modules/hardware/corectrl.nix b/nixos/modules/hardware/corectrl.nix new file mode 100644 index 00000000000..3185f6486c7 --- /dev/null +++ b/nixos/modules/hardware/corectrl.nix @@ -0,0 +1,62 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.corectrl; +in +{ + options.programs.corectrl = { + enable = mkEnableOption '' + A tool to overclock amd graphics cards and processors. + Add your user to the corectrl group to run corectrl without needing to enter your password + ''; + + gpuOverclock = { + enable = mkEnableOption '' + true + ''; + ppfeaturemask = mkOption { + type = types.str; + default = "0xfffd7fff"; + example = "0xffffffff"; + description = '' + Sets the `amdgpu.ppfeaturemask` kernel option. + In particular, it is used here to set the overdrive bit. + Default is `0xfffd7fff` as it is less likely to cause flicker issues. + Setting it to `0xffffffff` enables all features. + ''; + }; + }; + }; + + config = mkIf cfg.enable (lib.mkMerge [ + { + environment.systemPackages = [ pkgs.corectrl ]; + + services.dbus.packages = [ pkgs.corectrl ]; + + users.groups.corectrl = { }; + + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if ((action.id == "org.corectrl.helper.init" || + action.id == "org.corectrl.helperkiller.init") && + subject.local == true && + subject.active == true && + subject.isInGroup("corectrl")) { + return polkit.Result.YES; + } + }); + ''; + } + + (lib.mkIf cfg.gpuOverclock.enable { + # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/amd/include/amd_shared.h#n169 + # The overdrive bit + boot.kernelParams = [ "amdgpu.ppfeaturemask=${cfg.gpuOverclock.ppfeaturemask}" ]; + }) + ]); + + meta.maintainers = with lib.maintainers; [ artturin ]; +} diff --git a/nixos/modules/hardware/system-76.nix b/nixos/modules/hardware/system-76.nix index ed661fd3303..d4896541dba 100644 --- a/nixos/modules/hardware/system-76.nix +++ b/nixos/modules/hardware/system-76.nix @@ -34,6 +34,25 @@ let wantedBy = [ "multi-user.target" ]; }; }; + + power-pkg = config.boot.kernelPackages.system76-power; + powerConfig = mkIf cfg.power-daemon.enable { + # Make system76-power usable by root from the command line. + environment.systemPackages = [ power-pkg ]; + + services.dbus.packages = [ power-pkg ]; + + systemd.services.system76-power = { + description = "System76 Power Daemon"; + serviceConfig = { + ExecStart = "${power-pkg}/bin/system76-power daemon"; + Restart = "on-failure"; + Type = "dbus"; + BusName = "com.system76.PowerDaemon"; + }; + wantedBy = [ "multi-user.target" ]; + }; + }; in { options = { hardware.system76 = { @@ -52,8 +71,15 @@ in { description = "Whether to make the system76 out-of-tree kernel modules available"; type = types.bool; }; + + power-daemon.enable = mkOption { + default = cfg.enableAll; + example = true; + description = "Whether to enable the system76 power daemon"; + type = types.bool; + }; }; }; - config = mkMerge [ moduleConfig firmwareConfig ]; + config = mkMerge [ moduleConfig firmwareConfig powerConfig ]; } diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index 97accc7b99a..2be9da8f42a 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -92,7 +92,7 @@ in example = "PCI:4:0:0"; description = '' Bus ID of the AMD APU. You can find it using lspci; for example if lspci - shows the AMD APU at "04:00.0", set this option to "PCI:4:0:0". + shows the AMD APU at "04:00.0", set this option to "PCI:4:0:0". ''; }; @@ -159,7 +159,7 @@ in description = '' The NVIDIA X11 derivation to use. ''; - example = "config.boot.kernelPackages.nvidiaPackages.legacy340"; + example = "config.boot.kernelPackages.nvidiaPackages.legacy_340"; }; }; diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index c2836b5a9a1..d94af0b5bf7 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -428,7 +428,8 @@ let # Rewrite dates for everything in the FS find . -exec touch --date=2000-01-01 {} + - usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]') + # Round up to the nearest multiple of 1MB, for more deterministic du output + usage_size=$(( $(du -s --block-size=1M --apparent-size . | tr -cd '[:digit:]') * 1024 * 1024 )) # Make the image 110% as big as the files need to make up for FAT overhead image_size=$(( ($usage_size * 110) / 100 )) # Make the image fit blocks of 1M @@ -438,7 +439,16 @@ let echo "Image size: $image_size" truncate --size=$image_size "$out" faketime "2000-01-01 00:00:00" mkfs.vfat -i 12345678 -n EFIBOOT "$out" - mcopy -psvm -i "$out" ./EFI ./boot :: + + # Force a fixed order in mcopy for better determinism, and avoid file globbing + for d in $(find EFI boot -type d | sort); do + faketime "2000-01-01 00:00:00" mmd -i "$out" "::/$d" + done + + for f in $(find EFI boot -type f | sort); do + mcopy -pvm -i "$out" "$f" "::/$f" + done + # Verify the FAT partition. fsck.vfat -vn "$out" ''; # */ @@ -680,6 +690,12 @@ in "upperdir=/nix/.rw-store/store" "workdir=/nix/.rw-store/work" ]; + + depends = [ + "/nix/.ro-store" + "/nix/.rw-store/store" + "/nix/.rw-store/work" + ]; }; boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "uas" "overlay" ]; diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix index fa074fdfcc6..238ab6d0617 100644 --- a/nixos/modules/installer/netboot/netboot.nix +++ b/nixos/modules/installer/netboot/netboot.nix @@ -57,6 +57,12 @@ with lib; "upperdir=/nix/.rw-store/store" "workdir=/nix/.rw-store/work" ]; + + depends = [ + "/nix/.ro-store" + "/nix/.rw-store/store" + "/nix/.rw-store/work" + ]; }; boot.initrd.availableKernelModules = [ "squashfs" "overlay" ]; diff --git a/nixos/modules/installer/sd-card/sd-image.nix b/nixos/modules/installer/sd-card/sd-image.nix index d0fe79903d3..2a10a77300e 100644 --- a/nixos/modules/installer/sd-card/sd-image.nix +++ b/nixos/modules/installer/sd-card/sd-image.nix @@ -55,6 +55,22 @@ in ''; }; + firmwarePartitionOffset = mkOption { + type = types.int; + default = 8; + description = '' + Gap in front of the /boot/firmware partition, in mebibytes (1024×1024 + bytes). + Can be increased to make more space for boards requiring to dd u-boot + SPL before actual partitions. + + Unless you are building your own images pre-configured with an + installed U-Boot, you can instead opt to delete the existing `FIRMWARE` + partition, which is used **only** for the Raspberry Pi family of + hardware. + ''; + }; + firmwarePartitionID = mkOption { type = types.str; default = "0x2178694e"; @@ -177,7 +193,7 @@ in zstd -d --no-progress "${rootfsImage}" -o ./root-fs.img # Gap in front of the first partition, in MiB - gap=8 + gap=${toString config.sdImage.firmwarePartitionOffset} # Create the image file sized to fit /boot/firmware and /, plus slack for the gap. rootSizeBlocks=$(du -B 512 --apparent-size ./root-fs.img | awk '{ print $1 }') diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index cb2dbf6c859..1dc0578daca 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -40,7 +40,7 @@ let }; nixos-option = - if lib.versionAtLeast (lib.getVersion pkgs.nix) "2.4pre" + if lib.versionAtLeast (lib.getVersion config.nix.package) "2.4pre" then null else pkgs.callPackage ./nixos-option { }; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 7ea2940292b..2cbbbc522e1 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -252,7 +252,7 @@ in postsrsd = 220; opendkim = 221; dspam = 222; - gale = 223; + # gale = 223; removed 2021-06-10 matrix-synapse = 224; rspamd = 225; # rmilter = 226; # unused, removed 2019-08-22 @@ -562,7 +562,7 @@ in postsrsd = 220; opendkim = 221; dspam = 222; - gale = 223; + # gale = 223; removed 2021-06-10 matrix-synapse = 224; rspamd = 225; # rmilter = 226; # unused, removed 2019-08-22 diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index fc04997bd2e..2d0f5d37f9e 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -9,6 +9,7 @@ ./config/xdg/menus.nix ./config/xdg/mime.nix ./config/xdg/portal.nix + ./config/xdg/portals/wlr.nix ./config/appstream.nix ./config/console.nix ./config/xdg/sounds.nix @@ -44,6 +45,7 @@ ./hardware/ckb-next.nix ./hardware/cpu/amd-microcode.nix ./hardware/cpu/intel-microcode.nix + ./hardware/corectrl.nix ./hardware/digitalbitbox.nix ./hardware/device-tree.nix ./hardware/i2c.nix @@ -136,6 +138,7 @@ ./programs/file-roller.nix ./programs/firejail.nix ./programs/fish.nix + ./programs/flashrom.nix ./programs/flexoptix-app.nix ./programs/freetds.nix ./programs/fuse.nix @@ -151,6 +154,7 @@ ./programs/iftop.nix ./programs/iotop.nix ./programs/java.nix + ./programs/kdeconnect.nix ./programs/kbdlight.nix ./programs/less.nix ./programs/liboping.nix @@ -197,7 +201,6 @@ ./programs/waybar.nix ./programs/wireshark.nix ./programs/wshowkeys.nix - ./programs/x2goserver.nix ./programs/xfs_quota.nix ./programs/xonsh.nix ./programs/xss-lock.nix @@ -594,6 +597,7 @@ ./services/monitoring/loki.nix ./services/monitoring/longview.nix ./services/monitoring/mackerel-agent.nix + ./services/monitoring/metricbeat.nix ./services/monitoring/monit.nix ./services/monitoring/munin.nix ./services/monitoring/nagios.nix @@ -691,11 +695,11 @@ ./services/networking/flannel.nix ./services/networking/freenet.nix ./services/networking/freeradius.nix - ./services/networking/gale.nix ./services/networking/gateone.nix ./services/networking/gdomap.nix ./services/networking/ghostunnel.nix ./services/networking/git-daemon.nix + ./services/networking/globalprotect-vpn.nix ./services/networking/gnunet.nix ./services/networking/go-neb.nix ./services/networking/go-shadowsocks2.nix @@ -839,6 +843,7 @@ ./services/networking/tox-node.nix ./services/networking/toxvpn.nix ./services/networking/tvheadend.nix + ./services/networking/ucarp.nix ./services/networking/unbound.nix ./services/networking/unifi.nix ./services/networking/v2ray.nix @@ -853,6 +858,7 @@ ./services/networking/xandikos.nix ./services/networking/xinetd.nix ./services/networking/xl2tpd.nix + ./services/networking/x2goserver.nix ./services/networking/xrdp.nix ./services/networking/yggdrasil.nix ./services/networking/zerobin.nix diff --git a/nixos/modules/programs/appgate-sdp.nix b/nixos/modules/programs/appgate-sdp.nix index 1dec4ecf9ec..12cb542f4d0 100644 --- a/nixos/modules/programs/appgate-sdp.nix +++ b/nixos/modules/programs/appgate-sdp.nix @@ -5,8 +5,7 @@ with lib; { options = { programs.appgate-sdp = { - enable = mkEnableOption - "AppGate SDP VPN client"; + enable = mkEnableOption "AppGate SDP VPN client"; }; }; @@ -17,7 +16,10 @@ with lib; systemd = { packages = [ pkgs.appgate-sdp ]; # https://github.com/NixOS/nixpkgs/issues/81138 - services.appgatedriver.wantedBy = [ "multi-user.target" ]; + services.appgatedriver.wantedBy = [ "multi-user.target" ]; + services.appgate-dumb-resolver.path = [ pkgs.e2fsprogs ]; + services.appgate-resolver.path = [ pkgs.procps pkgs.e2fsprogs ]; + services.appgatedriver.path = [ pkgs.e2fsprogs ]; }; }; } diff --git a/nixos/modules/programs/flashrom.nix b/nixos/modules/programs/flashrom.nix new file mode 100644 index 00000000000..f026c2e31cd --- /dev/null +++ b/nixos/modules/programs/flashrom.nix @@ -0,0 +1,26 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.flashrom; +in +{ + options.programs.flashrom = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Installs flashrom and configures udev rules for programmers + used by flashrom. Grants access to users in the "flashrom" + group. + ''; + }; + }; + + config = mkIf cfg.enable { + services.udev.packages = [ pkgs.flashrom ]; + environment.systemPackages = [ pkgs.flashrom ]; + users.groups.flashrom = { }; + }; +} diff --git a/nixos/modules/programs/kdeconnect.nix b/nixos/modules/programs/kdeconnect.nix new file mode 100644 index 00000000000..673449b9f63 --- /dev/null +++ b/nixos/modules/programs/kdeconnect.nix @@ -0,0 +1,35 @@ +{ config, pkgs, lib, ... }: +with lib; +{ + options.programs.kdeconnect = { + enable = mkEnableOption '' + kdeconnect. + + Note that it will open the TCP and UDP port from + 1714 to 1764 as they are needed for it to function properly. + You can use the <option>package</option> to use + <code>gnomeExtensions.gsconnect</code> as an alternative + implementation if you use Gnome. + ''; + package = mkOption { + default = pkgs.kdeconnect; + defaultText = "pkgs.kdeconnect"; + type = types.package; + example = literalExample "pkgs.gnomeExtensions.gsconnect"; + description = '' + The package providing the implementation for kdeconnect. + ''; + }; + }; + config = + let + cfg = config.programs.kdeconnect; + in + mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + networking.firewall = rec { + allowedTCPPortRanges = [ { from = 1714; to = 1764; } ]; + allowedUDPPortRanges = allowedTCPPortRanges; + }; + }; +} diff --git a/nixos/modules/programs/phosh.nix b/nixos/modules/programs/phosh.nix index 1f50065f781..cba3f73768e 100644 --- a/nixos/modules/programs/phosh.nix +++ b/nixos/modules/programs/phosh.nix @@ -143,10 +143,14 @@ in { oskItem ]; + systemd.packages = [ pkgs.phosh ]; + programs.feedbackd.enable = true; security.pam.services.phosh = {}; + hardware.opengl.enable = mkDefault true; + services.gnome.core-shell.enable = true; services.gnome.core-os-services.enable = true; services.xserver.displayManager.sessionPackages = [ pkgs.phosh ]; diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix index 3c09d9f00fd..d5819a08e8f 100644 --- a/nixos/modules/programs/sway.nix +++ b/nixos/modules/programs/sway.nix @@ -91,10 +91,9 @@ in { type = with types; listOf package; default = with pkgs; [ swaylock swayidle alacritty dmenu - rxvt-unicode # For backward compatibility (old default terminal) ]; defaultText = literalExample '' - with pkgs; [ swaylock swayidle rxvt-unicode alacritty dmenu ]; + with pkgs; [ swaylock swayidle alacritty dmenu ]; ''; example = literalExample '' with pkgs; [ diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix index 049a315c762..48638fda28d 100644 --- a/nixos/modules/programs/zsh/zsh.nix +++ b/nixos/modules/programs/zsh/zsh.nix @@ -91,7 +91,7 @@ in # before setting your PS1 and etc. Otherwise this will likely to interact with # your ~/.zshrc configuration in unexpected ways as the default prompt sets # a lot of different prompt variables. - autoload -U promptinit && promptinit && prompt walters && setopt prompt_sp + autoload -U promptinit && promptinit && prompt suse && setopt prompt_sp ''; description = '' Shell script code used to initialise the zsh prompt. diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 3cde7e95155..5699025601f 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -397,8 +397,6 @@ let "auth required pam_faillock.so"} ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}"} - ${optionalString cfg.fprintAuth - "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"} ${let p11 = config.security.pam.p11; in optionalString cfg.p11Auth "auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so"} ${let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth @@ -409,6 +407,8 @@ let "auth requisite ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"} ${let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth "auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}"} + ${optionalString cfg.fprintAuth + "auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so"} '' + # Modules in this block require having the password set in PAM_AUTHTOK. # pam_unix is marked as 'sufficient' on NixOS which means nothing will run diff --git a/nixos/modules/security/pam_mount.nix b/nixos/modules/security/pam_mount.nix index 9a0143c155c..e25ace38f57 100644 --- a/nixos/modules/security/pam_mount.nix +++ b/nixos/modules/security/pam_mount.nix @@ -29,6 +29,28 @@ in xlink:href="http://pam-mount.sourceforge.net/pam_mount.conf.5.html" />. ''; }; + + additionalSearchPaths = mkOption { + type = types.listOf types.package; + default = []; + example = literalExample "[ pkgs.bindfs ]"; + description = '' + Additional programs to include in the search path of pam_mount. + Useful for example if you want to use some FUSE filesystems like bindfs. + ''; + }; + + fuseMountOptions = mkOption { + type = types.listOf types.str; + default = []; + example = literalExample '' + [ "nodev" "nosuid" "force-user=%(USER)" "gid=%(USERGID)" "perms=0700" "chmod-deny" "chown-deny" "chgrp-deny" ] + ''; + description = '' + Global mount options that apply to every FUSE volume. + You can define volume-specific options in the volume definitions. + ''; + }; }; }; @@ -60,11 +82,12 @@ in <!-- if activated, requires ofl from hxtools to be present --> <logout wait="0" hup="no" term="no" kill="no" /> <!-- set PATH variable for pam_mount module --> - <path>${pkgs.util-linux}/bin</path> + <path>${makeBinPath ([ pkgs.util-linux ] ++ cfg.additionalSearchPaths)}</path> <!-- create mount point if not present --> <mkmountpoint enable="1" remove="true" /> <!-- specify the binaries to be called --> + <fusemount>${pkgs.fuse}/bin/mount.fuse %(VOLUME) %(MNTPT) -o ${concatStringsSep "," (cfg.fuseMountOptions ++ [ "%(OPTIONS)" ])}</fusemount> <cryptmount>${pkgs.pam_mount}/bin/mount.crypt %(VOLUME) %(MNTPT)</cryptmount> <cryptumount>${pkgs.pam_mount}/bin/umount.crypt %(MNTPT)</cryptumount> <pmvarrun>${pkgs.pam_mount}/bin/pmvarrun -u %(USER) -o %(OPERATION)</pmvarrun> diff --git a/nixos/modules/services/audio/alsa.nix b/nixos/modules/services/audio/alsa.nix index aff3fe2ba42..0d743ed31da 100644 --- a/nixos/modules/services/audio/alsa.nix +++ b/nixos/modules/services/audio/alsa.nix @@ -5,7 +5,7 @@ with lib; let - inherit (pkgs) alsaUtils; + inherit (pkgs) alsa-utils; pulseaudioEnabled = config.hardware.pulseaudio.enable; @@ -88,13 +88,13 @@ in config = mkIf config.sound.enable { - environment.systemPackages = [ alsaUtils ]; + environment.systemPackages = [ alsa-utils ]; environment.etc = mkIf (!pulseaudioEnabled && config.sound.extraConfig != "") { "asound.conf".text = config.sound.extraConfig; }; # ALSA provides a udev rule for restoring volume settings. - services.udev.packages = [ alsaUtils ]; + services.udev.packages = [ alsa-utils ]; boot.kernelModules = optional config.sound.enableOSSEmulation "snd_pcm_oss"; @@ -107,7 +107,7 @@ in Type = "oneshot"; RemainAfterExit = true; ExecStart = "${pkgs.coreutils}/bin/mkdir -p /var/lib/alsa"; - ExecStop = "${alsaUtils}/sbin/alsactl store --ignore"; + ExecStop = "${alsa-utils}/sbin/alsactl store --ignore"; }; }; @@ -115,16 +115,16 @@ in enable = true; bindings = [ # "Mute" media key - { keys = [ 113 ]; events = [ "key" ]; command = "${alsaUtils}/bin/amixer -q set Master toggle"; } + { keys = [ 113 ]; events = [ "key" ]; command = "${alsa-utils}/bin/amixer -q set Master toggle"; } # "Lower Volume" media key - { keys = [ 114 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master ${config.sound.mediaKeys.volumeStep}- unmute"; } + { keys = [ 114 ]; events = [ "key" "rep" ]; command = "${alsa-utils}/bin/amixer -q set Master ${config.sound.mediaKeys.volumeStep}- unmute"; } # "Raise Volume" media key - { keys = [ 115 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master ${config.sound.mediaKeys.volumeStep}+ unmute"; } + { keys = [ 115 ]; events = [ "key" "rep" ]; command = "${alsa-utils}/bin/amixer -q set Master ${config.sound.mediaKeys.volumeStep}+ unmute"; } # "Mic Mute" media key - { keys = [ 190 ]; events = [ "key" ]; command = "${alsaUtils}/bin/amixer -q set Capture toggle"; } + { keys = [ 190 ]; events = [ "key" ]; command = "${alsa-utils}/bin/amixer -q set Capture toggle"; } ]; }; diff --git a/nixos/modules/services/audio/jack.nix b/nixos/modules/services/audio/jack.nix index f341b432f75..d0a95b87ee1 100644 --- a/nixos/modules/services/audio/jack.nix +++ b/nixos/modules/services/audio/jack.nix @@ -8,7 +8,7 @@ let 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; + enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.isx86_64 && pkgs.pkgsi686Linux.alsa-lib != null; umaskNeeded = versionOlder cfg.jackd.package.version "1.9.12"; bridgeNeeded = versionAtLeast cfg.jackd.package.version "1.9.12"; @@ -129,9 +129,9 @@ in { (mkIf pcmPlugin { sound.extraConfig = '' pcm_type.jack { - libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_jack.so ; + libs.native = ${pkgs.alsa-plugins}/lib/alsa-lib/libasound_module_pcm_jack.so ; ${lib.optionalString enable32BitAlsaPlugins - "libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;"} + "libs.32Bit = ${pkgs.pkgsi686Linux.alsa-plugins}/lib/alsa-lib/libasound_module_pcm_jack.so ;"} } pcm.!default { @func getenv @@ -234,7 +234,7 @@ in { environment = { systemPackages = [ cfg.jackd.package ]; - etc."alsa/conf.d/50-jack.conf".source = "${pkgs.alsaPlugins}/etc/alsa/conf.d/50-jack.conf"; + etc."alsa/conf.d/50-jack.conf".source = "${pkgs.alsa-plugins}/etc/alsa/conf.d/50-jack.conf"; variables.JACK_PROMISCUOUS_SERVER = "jackaudio"; }; diff --git a/nixos/modules/services/audio/roon-bridge.nix b/nixos/modules/services/audio/roon-bridge.nix new file mode 100644 index 00000000000..85273a2039c --- /dev/null +++ b/nixos/modules/services/audio/roon-bridge.nix @@ -0,0 +1,74 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + name = "roon-bridge"; + cfg = config.services.roon-bridge; +in { + options = { + services.roon-bridge = { + enable = mkEnableOption "Roon Bridge"; + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open ports in the firewall for the bridge. + + UDP: 9003 + TCP: 9100 - 9200 + ''; + }; + user = mkOption { + type = types.str; + default = "roon-bridge"; + description = '' + User to run the Roon bridge as. + ''; + }; + group = mkOption { + type = types.str; + default = "roon-bridge"; + description = '' + Group to run the Roon Bridge as. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.roon-bridge = { + after = [ "network.target" ]; + description = "Roon Bridge"; + wantedBy = [ "multi-user.target" ]; + + environment.ROON_DATAROOT = "/var/lib/${name}"; + + serviceConfig = { + ExecStart = "${pkgs.roon-bridge}/start.sh"; + LimitNOFILE = 8192; + User = cfg.user; + Group = cfg.group; + StateDirectory = name; + }; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPortRanges = [ + { from = 9100; to = 9200; } + ]; + allowedUDPPorts = [ 9003 ]; + }; + + + users.groups.${cfg.group} = {}; + users.users.${cfg.user} = + if cfg.user == "roon-bridge" then { + isSystemUser = true; + description = "Roon Bridge user"; + group = cfg.group; + extraGroups = [ "audio" ]; + } + else {}; + }; +} diff --git a/nixos/modules/services/backup/duplicity.nix b/nixos/modules/services/backup/duplicity.nix index 1f6883ed02b..6949fa8b995 100644 --- a/nixos/modules/services/backup/duplicity.nix +++ b/nixos/modules/services/backup/duplicity.nix @@ -157,7 +157,7 @@ in ${dup} cleanup ${target} --force ${extra} ${lib.optionalString (cfg.cleanup.maxAge != null) "${dup} remove-older-than ${lib.escapeShellArg cfg.cleanup.maxAge} ${target} --force ${extra}"} ${lib.optionalString (cfg.cleanup.maxFull != null) "${dup} remove-all-but-n-full ${toString cfg.cleanup.maxFull} ${target} --force ${extra}"} - ${lib.optionalString (cfg.cleanup.maxIncr != null) "${dup} remove-all-incr-but-n-full ${toString cfg.cleanup.maxIncr} ${target} --force ${extra}"} + ${lib.optionalString (cfg.cleanup.maxIncr != null) "${dup} remove-all-inc-of-but-n-full ${toString cfg.cleanup.maxIncr} ${target} --force ${extra}"} exec ${dup} ${if cfg.fullIfOlderThan == "always" then "full" else "incr"} ${lib.escapeShellArgs ( [ cfg.root cfg.targetUrl ] ++ concatMap (p: [ "--include" p ]) cfg.include diff --git a/nixos/modules/services/backup/sanoid.nix b/nixos/modules/services/backup/sanoid.nix index 0472fb4ba1e..be44a43b6d3 100644 --- a/nixos/modules/services/backup/sanoid.nix +++ b/nixos/modules/services/backup/sanoid.nix @@ -10,74 +10,51 @@ let description = "dataset/template options"; }; - # Default values from https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf - commonOptions = { hourly = mkOption { description = "Number of hourly snapshots."; - type = types.ints.unsigned; - default = 48; + type = with types; nullOr ints.unsigned; + default = null; }; daily = mkOption { description = "Number of daily snapshots."; - type = types.ints.unsigned; - default = 90; + type = with types; nullOr ints.unsigned; + default = null; }; monthly = mkOption { description = "Number of monthly snapshots."; - type = types.ints.unsigned; - default = 6; + type = with types; nullOr ints.unsigned; + default = null; }; yearly = mkOption { description = "Number of yearly snapshots."; - type = types.ints.unsigned; - default = 0; + type = with types; nullOr ints.unsigned; + default = null; }; autoprune = mkOption { description = "Whether to automatically prune old snapshots."; - type = types.bool; - default = true; + type = with types; nullOr bool; + default = null; }; autosnap = mkOption { description = "Whether to automatically take snapshots."; - type = types.bool; - default = true; - }; - - settings = mkOption { - description = '' - Free-form settings for this template/dataset. See - <link xlink:href="https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf"/> - for allowed values. - ''; - type = datasetSettingsType; - }; - }; - - commonConfig = config: { - settings = { - hourly = mkDefault config.hourly; - daily = mkDefault config.daily; - monthly = mkDefault config.monthly; - yearly = mkDefault config.yearly; - autoprune = mkDefault config.autoprune; - autosnap = mkDefault config.autosnap; + type = with types; nullOr bool; + default = null; }; }; - datasetOptions = { - useTemplate = mkOption { + datasetOptions = rec { + use_template = mkOption { description = "Names of the templates to use for this dataset."; - type = (types.listOf (types.enum (attrNames cfg.templates))) // { - description = "list of template names"; - }; + type = types.listOf (types.enum (attrNames cfg.templates)); default = []; }; + useTemplate = use_template; recursive = mkOption { description = "Whether to recursively snapshot dataset children."; @@ -85,19 +62,12 @@ let default = false; }; - processChildrenOnly = mkOption { + process_children_only = mkOption { description = "Whether to only snapshot child datasets if recursing."; type = types.bool; default = false; }; - }; - - datasetConfig = config: { - settings = { - use_template = mkDefault config.useTemplate; - recursive = mkDefault config.recursive; - process_children_only = mkDefault config.processChildrenOnly; - }; + processChildrenOnly = process_children_only; }; # Extract pool names from configured datasets @@ -109,11 +79,11 @@ let else generators.mkValueStringDefault {} v; mkKeyValue = k: v: if v == null then "" + else if k == "processChildrenOnly" then "" + else if k == "useTemplate" then "" else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v; in generators.toINI { inherit mkKeyValue; } cfg.settings; - configDir = pkgs.writeTextDir "sanoid.conf" configFile; - in { # Interface @@ -135,19 +105,21 @@ in { }; datasets = mkOption { - type = types.attrsOf (types.submodule ({ config, ... }: { + type = types.attrsOf (types.submodule ({config, options, ...}: { + freeformType = datasetSettingsType; options = commonOptions // datasetOptions; - config = mkMerge [ (commonConfig config) (datasetConfig config) ]; + config.use_template = mkAliasDefinitions (options.useTemplate or {}); + config.process_children_only = mkAliasDefinitions (options.processChildrenOnly or {}); })); default = {}; description = "Datasets to snapshot."; }; templates = mkOption { - type = types.attrsOf (types.submodule ({ config, ... }: { + type = types.attrsOf (types.submodule { + freeformType = datasetSettingsType; options = commonOptions; - config = commonConfig config; - })); + }); default = {}; description = "Templates for datasets."; }; @@ -177,8 +149,8 @@ in { config = mkIf cfg.enable { services.sanoid.settings = mkMerge [ - (mapAttrs' (d: v: nameValuePair ("template_" + d) v.settings) cfg.templates) - (mapAttrs (d: v: v.settings) cfg.datasets) + (mapAttrs' (d: v: nameValuePair ("template_" + d) v) cfg.templates) + (mapAttrs (d: v: v) cfg.datasets) ]; systemd.services.sanoid = { @@ -191,7 +163,7 @@ in { ExecStart = lib.escapeShellArgs ([ "${pkgs.sanoid}/bin/sanoid" "--cron" - "--configdir" configDir + "--configdir" (pkgs.writeTextDir "sanoid.conf" configFile) ] ++ cfg.extraArgs); ExecStopPost = map (pool: lib.escapeShellArgs [ "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" pool diff --git a/nixos/modules/services/cluster/kubernetes/pki.nix b/nixos/modules/services/cluster/kubernetes/pki.nix index 8de6a3ba0d8..d9311d3e3a0 100644 --- a/nixos/modules/services/cluster/kubernetes/pki.nix +++ b/nixos/modules/services/cluster/kubernetes/pki.nix @@ -189,6 +189,7 @@ in # manually paste it in place. Just symlink. # otherwise, create the target file, ready for users to insert the token + mkdir -p $(dirname ${certmgrAPITokenPath}) if [ -f "${cfsslAPITokenPath}" ]; then ln -fs "${cfsslAPITokenPath}" "${certmgrAPITokenPath}" else diff --git a/nixos/modules/services/cluster/kubernetes/proxy.nix b/nixos/modules/services/cluster/kubernetes/proxy.nix index 7aa449f9aa2..42729f54643 100644 --- a/nixos/modules/services/cluster/kubernetes/proxy.nix +++ b/nixos/modules/services/cluster/kubernetes/proxy.nix @@ -59,7 +59,7 @@ in description = "Kubernetes Proxy Service"; wantedBy = [ "kubernetes.target" ]; after = [ "kube-apiserver.service" ]; - path = with pkgs; [ iptables conntrack_tools ]; + path = with pkgs; [ iptables conntrack-tools ]; serviceConfig = { Slice = "kubernetes.slice"; ExecStart = ''${top.package}/bin/kube-proxy \ diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index c4d51958e23..9c0740f28c9 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -52,7 +52,7 @@ in { }; port = mkOption { - type = types.int; + type = types.port; default = 6379; description = "The port for Redis to listen to."; }; diff --git a/nixos/modules/services/desktops/espanso.nix b/nixos/modules/services/desktops/espanso.nix index cd2eadf8816..4ef6724dda0 100644 --- a/nixos/modules/services/desktops/espanso.nix +++ b/nixos/modules/services/desktops/espanso.nix @@ -12,7 +12,6 @@ in { config = mkIf cfg.enable { systemd.user.services.espanso = { description = "Espanso daemon"; - path = with pkgs; [ espanso libnotify xclip ]; serviceConfig = { ExecStart = "${pkgs.espanso}/bin/espanso daemon"; Restart = "on-failure"; diff --git a/nixos/modules/services/desktops/pipewire/pipewire.conf.json b/nixos/modules/services/desktops/pipewire/pipewire.conf.json index a9330f54f4f..a923ab4db23 100644 --- a/nixos/modules/services/desktops/pipewire/pipewire.conf.json +++ b/nixos/modules/services/desktops/pipewire/pipewire.conf.json @@ -74,7 +74,18 @@ "args": { "factory.name": "support.node.driver", "node.name": "Dummy-Driver", - "priority.driver": 8000 + "node.group": "pipewire.dummy", + "priority.driver": 20000 + } + }, + { + "factory": "spa-node-factory", + "args": { + "factory.name": "support.node.driver", + "node.name": "Freewheel-Driver", + "priority.driver": 19000, + "node.group": "pipewire.freewheel", + "node.freewheel": true } } ], diff --git a/nixos/modules/services/games/terraria.nix b/nixos/modules/services/games/terraria.nix index 9e8e5ae8759..7312c7e6b63 100644 --- a/nixos/modules/services/games/terraria.nix +++ b/nixos/modules/services/games/terraria.nix @@ -42,7 +42,7 @@ in }; port = mkOption { - type = types.int; + type = types.port; default = 7777; description = '' Specifies the port to listen on. @@ -50,7 +50,7 @@ in }; maxPlayers = mkOption { - type = types.int; + type = types.ints.u8; default = 255; description = '' Sets the max number of players (between 1 and 255). diff --git a/nixos/modules/services/hardware/actkbd.nix b/nixos/modules/services/hardware/actkbd.nix index daa407ca1f0..f7770f85da3 100644 --- a/nixos/modules/services/hardware/actkbd.nix +++ b/nixos/modules/services/hardware/actkbd.nix @@ -75,7 +75,7 @@ in type = types.listOf (types.submodule bindingCfg); default = []; example = lib.literalExample '' - [ { keys = [ 113 ]; events = [ "key" ]; command = "''${pkgs.alsaUtils}/bin/amixer -q set Master toggle"; } + [ { keys = [ 113 ]; events = [ "key" ]; command = "''${pkgs.alsa-utils}/bin/amixer -q set Master toggle"; } ] ''; description = '' diff --git a/nixos/modules/services/hardware/auto-cpufreq.nix b/nixos/modules/services/hardware/auto-cpufreq.nix index 72c4eccaff7..f846476b30b 100644 --- a/nixos/modules/services/hardware/auto-cpufreq.nix +++ b/nixos/modules/services/hardware/auto-cpufreq.nix @@ -12,7 +12,13 @@ in { config = mkIf cfg.enable { environment.systemPackages = [ pkgs.auto-cpufreq ]; - systemd.packages = [ pkgs.auto-cpufreq ]; - systemd.services.auto-cpufreq.path = with pkgs; [ bash coreutils ]; + systemd = { + packages = [ pkgs.auto-cpufreq ]; + services.auto-cpufreq = { + # Workaround for https://github.com/NixOS/nixpkgs/issues/81138 + wantedBy = [ "multi-user.target" ]; + path = with pkgs; [ bash coreutils ]; + }; + }; }; } diff --git a/nixos/modules/services/misc/bees.nix b/nixos/modules/services/misc/bees.nix index b0ed2d5c286..6b8cae84642 100644 --- a/nixos/modules/services/misc/bees.nix +++ b/nixos/modules/services/misc/bees.nix @@ -57,7 +57,7 @@ let }; options.extraOptions = mkOption { type = listOf str; - default = []; + default = [ ]; description = '' Extra command-line options passed to the daemon. See upstream bees documentation. ''; @@ -67,7 +67,8 @@ let }; }; -in { +in +{ options.services.beesd = { filesystems = mkOption { @@ -87,37 +88,42 @@ in { }; }; config = { - systemd.services = mapAttrs' (name: fs: nameValuePair "beesd@${name}" { - description = "Block-level BTRFS deduplication for %i"; - after = [ "sysinit.target" ]; + systemd.services = mapAttrs' + (name: fs: nameValuePair "beesd@${name}" { + description = "Block-level BTRFS deduplication for %i"; + after = [ "sysinit.target" ]; - serviceConfig = let - configOpts = [ - fs.spec - "verbosity=${toString fs.verbosity}" - "idxSizeMB=${toString fs.hashTableSizeMB}" - "workDir=${fs.workDir}" - ]; - configOptsStr = escapeShellArgs configOpts; - in { - # Values from https://github.com/Zygo/bees/blob/v0.6.1/scripts/beesd%40.service.in - ExecStart = "${pkgs.bees}/bin/bees-service-wrapper run ${configOptsStr} -- --no-timestamps ${escapeShellArgs fs.extraOptions}"; - ExecStopPost = "${pkgs.bees}/bin/bees-service-wrapper cleanup ${configOptsStr}"; - CPUAccounting = true; - CPUWeight = 12; - IOSchedulingClass = "idle"; - IOSchedulingPriority = 7; - IOWeight = 10; - KillMode = "control-group"; - KillSignal = "SIGTERM"; - MemoryAccounting = true; - Nice = 19; - Restart = "on-abnormal"; - StartupCPUWeight = 25; - StartupIOWeight = 25; - SyslogIdentifier = "bees"; # would otherwise be "bees-service-wrapper" - }; - wantedBy = ["multi-user.target"]; - }) cfg.filesystems; + serviceConfig = + let + configOpts = [ + fs.spec + "verbosity=${toString fs.verbosity}" + "idxSizeMB=${toString fs.hashTableSizeMB}" + "workDir=${fs.workDir}" + ]; + configOptsStr = escapeShellArgs configOpts; + in + { + # Values from https://github.com/Zygo/bees/blob/v0.6.5/scripts/beesd@.service.in + ExecStart = "${pkgs.bees}/bin/bees-service-wrapper run ${configOptsStr} -- --no-timestamps ${escapeShellArgs fs.extraOptions}"; + ExecStopPost = "${pkgs.bees}/bin/bees-service-wrapper cleanup ${configOptsStr}"; + CPUAccounting = true; + CPUSchedulingPolicy = "batch"; + CPUWeight = 12; + IOSchedulingClass = "idle"; + IOSchedulingPriority = 7; + IOWeight = 10; + KillMode = "control-group"; + KillSignal = "SIGTERM"; + MemoryAccounting = true; + Nice = 19; + Restart = "on-abnormal"; + StartupCPUWeight = 25; + StartupIOWeight = 25; + SyslogIdentifier = "beesd"; # would otherwise be "bees-service-wrapper" + }; + wantedBy = [ "multi-user.target" ]; + }) + cfg.filesystems; }; } diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix index 32360d43768..eb266f043eb 100644 --- a/nixos/modules/services/misc/etcd.nix +++ b/nixos/modules/services/misc/etcd.nix @@ -184,7 +184,7 @@ in { }; }; - environment.systemPackages = [ pkgs.etcdctl ]; + environment.systemPackages = [ pkgs.etcd ]; users.users.etcd = { uid = config.ids.uids.etcd; diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 253d87537cf..237c20e4b7f 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -10,7 +10,7 @@ let postgresqlPackage = if config.services.postgresql.enable then config.services.postgresql.package else - pkgs.postgresql; + pkgs.postgresql_12; gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket"; gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket"; @@ -145,7 +145,7 @@ let }; }; - gitlabEnv = { + gitlabEnv = cfg.packages.gitlab.gitlabEnv // { HOME = "${cfg.statePath}/home"; PUMA_PATH = "${cfg.statePath}/"; GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/"; @@ -462,7 +462,7 @@ in { }; port = mkOption { - type = types.int; + type = types.port; default = 8080; description = '' GitLab server port for copy-paste URLs, e.g. 80 or 443 if you're @@ -841,6 +841,10 @@ in { assertion = cfg.secrets.jwsFile != null; message = "services.gitlab.secrets.jwsFile must be set!"; } + { + assertion = versionAtLeast postgresqlPackage.version "12.0.0"; + message = "PostgreSQL >=12 is required to run GitLab 14."; + } ]; environment.systemPackages = [ pkgs.git gitlab-rake gitlab-rails cfg.packages.gitlab-shell ]; diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index 1e33381de24..d68d7b05c17 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -66,7 +66,9 @@ in { meta.maintainers = teams.home-assistant.members; options.services.home-assistant = { - enable = mkEnableOption "Home Assistant"; + # Running home-assistant on NixOS is considered an installation method that is unsupported by the upstream project. + # https://github.com/home-assistant/architecture/blob/master/adr/0012-define-supported-installation-method.md#decision + enable = mkEnableOption "Home Assistant. Please note that this installation method is unsupported upstream"; configDir = mkOption { default = "/var/lib/hass"; @@ -266,6 +268,52 @@ in { "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ])); + componentsUsingBluetooth = [ + # Components that require the AF_BLUETOOTH address family + "bluetooth_tracker" + "bluetooth_le_tracker" + ]; + componentsUsingSerialDevices = [ + # Components that require access to serial devices (/dev/tty*) + # List generated from home-assistant documentation: + # git clone https://github.com/home-assistant/home-assistant.io/ + # cd source/_integrations + # rg "/dev/tty" -l | cut -d'/' -f3 | cut -d'.' -f1 | sort + # And then extended by references found in the source code, these + # mostly the ones using config flows already. + "acer_projector" + "alarmdecoder" + "arduino" + "blackbird" + "dsmr" + "edl21" + "elkm1" + "elv" + "enocean" + "firmata" + "flexit" + "gpsd" + "insteon" + "kwb" + "lacrosse" + "mhz19" + "modbus" + "modem_callerid" + "mysensors" + "nad" + "numato" + "rflink" + "rfxtrx" + "scsgate" + "serial" + "serial_pm" + "sms" + "upb" + "velbus" + "w800rf32" + "xbee" + "zha" + ]; in { ExecStart = "${package}/bin/hass --runner --config '${cfg.configDir}'"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; @@ -279,11 +327,11 @@ in { # Hardening AmbientCapabilities = capabilities; CapabilityBoundingSet = capabilities; - DeviceAllow = [ + DeviceAllow = (optionals (any useComponent componentsUsingSerialDevices) [ "char-ttyACM rw" "char-ttyAMA rw" "char-ttyUSB rw" - ]; + ]); DevicePolicy = "closed"; LockPersonality = true; MemoryDenyWriteExecute = true; @@ -312,13 +360,15 @@ in { "AF_INET6" "AF_NETLINK" "AF_UNIX" - ] ++ optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [ + ] ++ optionals (any useComponent componentsUsingBluetooth) [ "AF_BLUETOOTH" ]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; - SupplementaryGroups = [ "dialout" ]; + SupplementaryGroups = optionals (any useComponent componentsUsingSerialDevices) [ + "dialout" + ]; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service" diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix index dff58745304..3c734a94819 100644 --- a/nixos/modules/services/misc/matrix-synapse.nix +++ b/nixos/modules/services/misc/matrix-synapse.nix @@ -143,6 +143,13 @@ in { List of additional Matrix plugins to make available. ''; }; + withJemalloc = mkOption { + type = types.bool; + default = false; + description = '' + Whether to preload jemalloc to reduce memory fragmentation and overall usage. + ''; + }; no_tls = mkOption { type = types.bool; default = false; @@ -231,7 +238,7 @@ in { type = types.listOf (types.submodule { options = { port = mkOption { - type = types.int; + type = types.port; example = 8448; description = '' The port to listen for HTTP(S) requests on. @@ -720,7 +727,11 @@ in { --keys-directory ${cfg.dataDir} \ --generate-keys ''; - environment.PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; + environment = { + PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; + } // optionalAttrs (cfg.withJemalloc) { + LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so"; + }; serviceConfig = { Type = "notify"; User = "matrix-synapse"; diff --git a/nixos/modules/services/misc/sourcehut/builds.nix b/nixos/modules/services/misc/sourcehut/builds.nix index e228665784e..a17a1010dbf 100644 --- a/nixos/modules/services/misc/sourcehut/builds.nix +++ b/nixos/modules/services/misc/sourcehut/builds.nix @@ -48,7 +48,6 @@ in default = false; description = '' Run workers for builds.sr.ht. - Perform manually on machine: `cd ${scfg.statePath}/images; docker build -t qemu -f qemu/Dockerfile .` ''; }; @@ -161,6 +160,21 @@ in partOf = [ "buildsrht.service" ]; description = "builds.sr.ht worker service"; path = [ pkgs.openssh pkgs.docker ]; + preStart = let qemuPackage = pkgs.qemu_kvm; + in '' + if [[ "$(docker images -q qemu:latest 2> /dev/null)" == "" || "$(cat ${statePath}/docker-image-qemu 2> /dev/null || true)" != "${qemuPackage.version}" ]]; then + # Create and import qemu:latest image for docker + ${ + pkgs.dockerTools.streamLayeredImage { + name = "qemu"; + tag = "latest"; + contents = [ qemuPackage ]; + } + } | docker load + # Mark down current package version + printf "%s" "${qemuPackage.version}" > ${statePath}/docker-image-qemu + fi + ''; serviceConfig = { Type = "simple"; User = user; diff --git a/nixos/modules/services/misc/synergy.nix b/nixos/modules/services/misc/synergy.nix index 7990a9f6f4c..d6cd5d7f0d6 100644 --- a/nixos/modules/services/misc/synergy.nix +++ b/nixos/modules/services/misc/synergy.nix @@ -70,6 +70,26 @@ in type = types.bool; description = "Whether the Synergy server should be started automatically."; }; + tls = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether TLS encryption should be used. + + Using this requires a TLS certificate that can be + generated by starting the Synergy GUI once and entering + a valid product key. + ''; + }; + + cert = mkOption { + type = types.nullOr types.str; + default = null; + example = "~/.synergy/SSL/Synergy.pem"; + description = "The TLS certificate to use for encryption."; + }; + }; }; }; @@ -95,7 +115,7 @@ in description = "Synergy server"; wantedBy = optional cfgS.autoStart "graphical-session.target"; path = [ pkgs.synergy ]; - serviceConfig.ExecStart = ''${pkgs.synergy}/bin/synergys -c ${cfgS.configFile} -f ${optionalString (cfgS.address != "") "-a ${cfgS.address}"} ${optionalString (cfgS.screenName != "") "-n ${cfgS.screenName}" }''; + serviceConfig.ExecStart = ''${pkgs.synergy}/bin/synergys -c ${cfgS.configFile} -f${optionalString (cfgS.address != "") " -a ${cfgS.address}"}${optionalString (cfgS.screenName != "") " -n ${cfgS.screenName}"}${optionalString cfgS.tls.enable " --enable-crypto"}${optionalString (cfgS.tls.cert != null) (" --tls-cert=${cfgS.tls.cert}")}''; serviceConfig.Restart = "on-failure"; }; }) diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 4ebde6f9b10..c3e1f72945b 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -94,7 +94,7 @@ let description = "Name of the datasource. Required."; }; type = mkOption { - type = types.enum ["graphite" "prometheus" "cloudwatch" "elasticsearch" "influxdb" "opentsdb" "mysql" "mssql" "postgres" "loki"]; + type = types.str; description = "Datasource type. Required."; }; access = mkOption { @@ -337,11 +337,16 @@ in { defaultText = "pkgs.grafana"; type = types.package; }; + declarativePlugins = mkOption { type = with types; nullOr (listOf path); default = null; description = "If non-null, then a list of packages containing Grafana plugins to install. If set, plugins cannot be manually installed."; example = literalExample "with pkgs.grafanaPlugins; [ grafana-piechart-panel ]"; + # Make sure each plugin is added only once; otherwise building + # the link farm fails, since the same path is added multiple + # times. + apply = x: if isList x then lib.unique x else x; }; dataDir = mkOption { @@ -635,20 +640,28 @@ in { QT_QPA_PLATFORM = "offscreen"; } // mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions; script = '' + set -o errexit -o pipefail -o nounset -o errtrace + shopt -s inherit_errexit + ${optionalString (cfg.auth.google.clientSecretFile != null) '' - export GF_AUTH_GOOGLE_CLIENT_SECRET="$(cat ${escapeShellArg cfg.auth.google.clientSecretFile})" + GF_AUTH_GOOGLE_CLIENT_SECRET="$(<${escapeShellArg cfg.auth.google.clientSecretFile})" + export GF_AUTH_GOOGLE_CLIENT_SECRET ''} ${optionalString (cfg.database.passwordFile != null) '' - export GF_DATABASE_PASSWORD="$(cat ${escapeShellArg cfg.database.passwordFile})" + GF_DATABASE_PASSWORD="$(<${escapeShellArg cfg.database.passwordFile})" + export GF_DATABASE_PASSWORD ''} ${optionalString (cfg.security.adminPasswordFile != null) '' - export GF_SECURITY_ADMIN_PASSWORD="$(cat ${escapeShellArg cfg.security.adminPasswordFile})" + GF_SECURITY_ADMIN_PASSWORD="$(<${escapeShellArg cfg.security.adminPasswordFile})" + export GF_SECURITY_ADMIN_PASSWORD ''} ${optionalString (cfg.security.secretKeyFile != null) '' - export GF_SECURITY_SECRET_KEY="$(cat ${escapeShellArg cfg.security.secretKeyFile})" + GF_SECURITY_SECRET_KEY="$(<${escapeShellArg cfg.security.secretKeyFile})" + export GF_SECURITY_SECRET_KEY ''} ${optionalString (cfg.smtp.passwordFile != null) '' - export GF_SMTP_PASSWORD="$(cat ${escapeShellArg cfg.smtp.passwordFile})" + GF_SMTP_PASSWORD="$(<${escapeShellArg cfg.smtp.passwordFile})" + export GF_SMTP_PASSWORD ''} ${optionalString cfg.provision.enable '' export GF_PATHS_PROVISIONING=${provisionConfDir}; diff --git a/nixos/modules/services/monitoring/metricbeat.nix b/nixos/modules/services/monitoring/metricbeat.nix new file mode 100644 index 00000000000..b285559eaa9 --- /dev/null +++ b/nixos/modules/services/monitoring/metricbeat.nix @@ -0,0 +1,152 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) + attrValues + literalExample + mkEnableOption + mkIf + mkOption + types + ; + cfg = config.services.metricbeat; + + settingsFormat = pkgs.formats.yaml {}; + +in +{ + options = { + + services.metricbeat = { + + enable = mkEnableOption "metricbeat"; + + package = mkOption { + type = types.package; + default = pkgs.metricbeat; + defaultText = literalExample "pkgs.metricbeat"; + example = literalExample "pkgs.metricbeat7"; + description = '' + The metricbeat package to use + ''; + }; + + modules = mkOption { + description = '' + Metricbeat modules are responsible for reading metrics from the various sources. + + This is like <literal>services.metricbeat.settings.metricbeat.modules</literal>, + but structured as an attribute set. This has the benefit that multiple + NixOS modules can contribute settings to a single metricbeat module. + + A module can be specified multiple times by choosing a different <literal><name></literal> + for each, but setting <xref linkend="opt-services.metricbeat.modules._name_.module"/> to the same value. + + See <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-modules.html"/>. + ''; + default = {}; + type = types.attrsOf (types.submodule ({ name, ... }: { + freeformType = settingsFormat.type; + options = { + module = mkOption { + type = types.str; + default = name; + defaultText = literalExample ''<name>''; + description = '' + The name of the module. + + Look for the value after <literal>module:</literal> on the individual + module pages linked from <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-modules.html"/>. + ''; + }; + }; + })); + example = { + system = { + metricsets = ["cpu" "load" "memory" "network" "process" "process_summary" "uptime" "socket_summary"]; + enabled = true; + period = "10s"; + processes = [".*"]; + cpu.metrics = ["percentages" "normalized_percentages"]; + core.metrics = ["percentages"]; + }; + }; + }; + + settings = mkOption { + type = types.submodule { + freeformType = settingsFormat.type; + options = { + + name = mkOption { + type = types.str; + default = ""; + description = '' + Name of the beat. Defaults to the hostname. + See <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/configuration-general-options.html#_name"/>. + ''; + }; + + tags = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Tags to place on the shipped metrics. + See <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/configuration-general-options.html#_tags_2"/>. + ''; + }; + + metricbeat.modules = mkOption { + type = types.listOf settingsFormat.type; + default = []; + internal = true; + description = '' + The metric collecting modules. Use <xref linkend="opt-services.metricbeat.modules"/> instead. + + See <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-modules.html"/>. + ''; + }; + }; + }; + default = {}; + description = '' + Configuration for metricbeat. See <link xlink:href="https://www.elastic.co/guide/en/beats/metricbeat/current/configuring-howto-metricbeat.html"/> for supported values. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + + assertions = [ + { + # empty modules would cause a failure at runtime + assertion = cfg.settings.metricbeat.modules != []; + message = "services.metricbeat: You must configure one or more modules."; + } + ]; + + services.metricbeat.settings.metricbeat.modules = attrValues cfg.modules; + + systemd.services.metricbeat = { + description = "metricbeat metrics shipper"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = '' + ${cfg.package}/bin/metricbeat \ + -c ${settingsFormat.generate "metricbeat.yml" cfg.settings} \ + --path.data $STATE_DIRECTORY \ + --path.logs $LOGS_DIRECTORY \ + ; + ''; + Restart = "always"; + DynamicUser = true; + ProtectSystem = "strict"; + ProtectHome = "tmpfs"; + StateDirectory = "metricbeat"; + LogsDirectory = "metricbeat"; + }; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index e08f23d8eb0..8fe689ef3db 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -945,6 +945,7 @@ in { RuntimeDirectoryMode = "0700"; WorkingDirectory = workingDir; StateDirectory = cfg.stateDir; + StateDirectoryMode = "0700"; }; }; }; diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 212ba06ef75..46015c9ec1e 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -56,6 +56,7 @@ let "redis" "rspamd" "rtl_433" + "script" "snmp" "smokeping" "sql" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/script.nix b/nixos/modules/services/monitoring/prometheus/exporters/script.nix new file mode 100644 index 00000000000..104ab859f2e --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/script.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.script; + configFile = pkgs.writeText "script-exporter.yaml" (builtins.toJSON cfg.settings); +in +{ + port = 9172; + extraOpts = { + settings.scripts = mkOption { + type = with types; listOf (submodule { + options = { + name = mkOption { + type = str; + example = "sleep"; + description = "Name of the script."; + }; + script = mkOption { + type = str; + example = "sleep 5"; + description = "Shell script to execute when metrics are requested."; + }; + timeout = mkOption { + type = nullOr int; + default = null; + example = 60; + description = "Optional timeout for the script in seconds."; + }; + }; + }); + example = literalExample '' + { + scripts = [ + { name = "sleep"; script = "sleep 5"; } + ]; + } + ''; + description = '' + All settings expressed as an Nix attrset. + + Check the official documentation for the corresponding YAML + settings that can all be used here: <link xlink:href="https://github.com/adhocteam/script_exporter#sample-configuration" /> + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-script-exporter}/bin/script_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --config.file ${configFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + NoNewPrivileges = true; + ProtectHome = true; + ProtectSystem = "strict"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + }; + }; +} diff --git a/nixos/modules/services/monitoring/zabbix-agent.nix b/nixos/modules/services/monitoring/zabbix-agent.nix index e7dd9e3393d..7eb6449e384 100644 --- a/nixos/modules/services/monitoring/zabbix-agent.nix +++ b/nixos/modules/services/monitoring/zabbix-agent.nix @@ -157,7 +157,10 @@ in wantedBy = [ "multi-user.target" ]; - path = [ "/run/wrappers" ] ++ cfg.extraPackages; + # https://www.zabbix.com/documentation/current/manual/config/items/userparameters + # > User parameters are commands executed by Zabbix agent. + # > /bin/sh is used as a command line interpreter under UNIX operating systems. + path = with pkgs; [ bash "/run/wrappers" ] ++ cfg.extraPackages; serviceConfig = { ExecStart = "@${cfg.package}/sbin/zabbix_agentd zabbix_agentd -f --config ${configFile}"; diff --git a/nixos/modules/services/network-filesystems/davfs2.nix b/nixos/modules/services/network-filesystems/davfs2.nix index 4b6f85e4a2c..8cf314fe63a 100644 --- a/nixos/modules/services/network-filesystems/davfs2.nix +++ b/nixos/modules/services/network-filesystems/davfs2.nix @@ -70,6 +70,24 @@ in }; }; + security.wrappers."mount.davfs" = { + program = "mount.davfs"; + source = "${pkgs.davfs2}/bin/mount.davfs"; + owner = "root"; + group = cfg.davGroup; + setuid = true; + permissions = "u+rx,g+x"; + }; + + security.wrappers."umount.davfs" = { + program = "umount.davfs"; + source = "${pkgs.davfs2}/bin/umount.davfs"; + owner = "root"; + group = cfg.davGroup; + setuid = true; + permissions = "u+rx,g+x"; + }; + }; } diff --git a/nixos/modules/services/networking/babeld.nix b/nixos/modules/services/networking/babeld.nix index 5e14283179a..aae6f1498a4 100644 --- a/nixos/modules/services/networking/babeld.nix +++ b/nixos/modules/services/networking/babeld.nix @@ -104,6 +104,7 @@ in ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile} -I /run/babeld/babeld.pid -S /var/lib/babeld/state"; AmbientCapabilities = [ "CAP_NET_ADMIN" ]; CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; + DevicePolicy = "closed"; DynamicUser = true; IPAddressAllow = [ "fe80::/64" "ff00::/8" "::1/128" "127.0.0.0/8" ]; IPAddressDeny = "any"; @@ -123,12 +124,17 @@ in RemoveIPC = true; ProtectHome = true; ProtectHostname = true; + ProtectProc = "invisible"; PrivateMounts = true; PrivateTmp = true; PrivateDevices = true; PrivateUsers = false; # kernel_route(ADD): Operation not permitted + ProcSubset = "pid"; SystemCallArchitectures = "native"; - SystemCallFilter = [ "@system-service" ]; + SystemCallFilter = [ + "@system-service" + "~@privileged @resources" + ]; UMask = "0177"; RuntimeDirectory = "babeld"; StateDirectory = "babeld"; diff --git a/nixos/modules/services/networking/firefox/sync-server.nix b/nixos/modules/services/networking/firefox/sync-server.nix index 6842aa73561..24f76864953 100644 --- a/nixos/modules/services/networking/firefox/sync-server.nix +++ b/nixos/modules/services/networking/firefox/sync-server.nix @@ -67,7 +67,7 @@ in }; listen.port = mkOption { - type = types.int; + type = types.port; default = 5000; description = '' Port on which the sync server listen to. diff --git a/nixos/modules/services/networking/gale.nix b/nixos/modules/services/networking/gale.nix deleted file mode 100644 index cb954fd836b..00000000000 --- a/nixos/modules/services/networking/gale.nix +++ /dev/null @@ -1,181 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.gale; - # we convert the path to a string to avoid it being copied to the nix store, - # otherwise users could read the private key as all files in the store are - # world-readable - keyPath = toString cfg.keyPath; - # ...but we refer to the pubkey file using a path so that we can ensure the - # config gets rebuilt if the public key changes (we can assume the private key - # will never change without the public key having changed) - gpubFile = cfg.keyPath + "/${cfg.domain}.gpub"; - home = "/var/lib/gale"; - keysPrepared = cfg.keyPath != null && lib.pathExists cfg.keyPath; -in -{ - options = { - services.gale = { - enable = mkEnableOption "the Gale messaging daemon"; - - user = mkOption { - default = "gale"; - type = types.str; - description = "Username for the Gale daemon."; - }; - - group = mkOption { - default = "gale"; - type = types.str; - description = "Group name for the Gale daemon."; - }; - - setuidWrapper = mkOption { - default = null; - description = "Configuration for the Gale gksign setuid wrapper."; - }; - - domain = mkOption { - default = ""; - type = types.str; - description = "Domain name for the Gale system."; - }; - - keyPath = mkOption { - default = null; - type = types.nullOr types.path; - description = '' - Directory containing the key pair for this Gale domain. The expected - filename will be taken from the domain option with ".gpri" and ".gpub" - appended. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be added to <filename>/etc/gale/conf</filename>. - ''; - }; - }; - }; - - config = mkMerge [ - (mkIf cfg.enable { - assertions = [{ - assertion = cfg.domain != ""; - message = "A domain must be set for Gale."; - }]; - - warnings = mkIf (!keysPrepared) [ - "You must run gale-install in order to generate a domain key." - ]; - - system.activationScripts.gale = mkIf cfg.enable ( - stringAfter [ "users" "groups" ] '' - chmod 755 ${home} - mkdir -m 0777 -p ${home}/auth/cache - mkdir -m 1777 -p ${home}/auth/local # GALE_DOMAIN.gpub - mkdir -m 0700 -p ${home}/auth/private # ROOT.gpub - mkdir -m 0755 -p ${home}/auth/trusted # ROOT - mkdir -m 0700 -p ${home}/.gale - mkdir -m 0700 -p ${home}/.gale/auth - mkdir -m 0700 -p ${home}/.gale/auth/private # GALE_DOMAIN.gpri - - ln -sf ${pkgs.gale}/etc/gale/auth/trusted/ROOT "${home}/auth/trusted/ROOT" - chown ${cfg.user}:${cfg.group} ${home} ${home}/auth ${home}/auth/* - chown ${cfg.user}:${cfg.group} ${home}/.gale ${home}/.gale/auth ${home}/.gale/auth/private - '' - ); - - environment = { - etc = { - "gale/auth".source = home + "/auth"; # symlink /var/lib/gale/auth - "gale/conf".text = '' - GALE_USER ${cfg.user} - GALE_DOMAIN ${cfg.domain} - ${cfg.extraConfig} - ''; - }; - - systemPackages = [ pkgs.gale ]; - }; - - users.users.${cfg.user} = { - description = "Gale daemon"; - uid = config.ids.uids.gale; - group = cfg.group; - home = home; - createHome = true; - }; - - users.groups = [{ - name = cfg.group; - gid = config.ids.gids.gale; - }]; - }) - (mkIf (cfg.enable && keysPrepared) { - assertions = [ - { - assertion = cfg.keyPath != null - && lib.pathExists (cfg.keyPath + "/${cfg.domain}.gpub"); - message = "Couldn't find a Gale public key for ${cfg.domain}."; - } - { - assertion = cfg.keyPath != null - && lib.pathExists (cfg.keyPath + "/${cfg.domain}.gpri"); - message = "Couldn't find a Gale private key for ${cfg.domain}."; - } - ]; - - services.gale.setuidWrapper = { - program = "gksign"; - source = "${pkgs.gale}/bin/gksign"; - owner = cfg.user; - group = cfg.group; - setuid = true; - setgid = false; - }; - - security.wrappers.gksign = cfg.setuidWrapper; - - systemd.services.gale-galed = { - description = "Gale messaging daemon"; - wantedBy = [ "multi-user.target" ]; - wants = [ "gale-gdomain.service" ]; - after = [ "network.target" ]; - - preStart = '' - install -m 0640 -o ${cfg.user} -g ${cfg.group} ${keyPath}/${cfg.domain}.gpri "${home}/.gale/auth/private/" - install -m 0644 -o ${cfg.user} -g ${cfg.group} ${gpubFile} "${home}/.gale/auth/private/${cfg.domain}.gpub" - install -m 0644 -o ${cfg.user} -g ${cfg.group} ${gpubFile} "${home}/auth/local/${cfg.domain}.gpub" - ''; - - serviceConfig = { - Type = "forking"; - ExecStart = "@${pkgs.gale}/bin/galed galed"; - User = cfg.user; - Group = cfg.group; - PermissionsStartOnly = true; - }; - }; - - systemd.services.gale-gdomain = { - description = "Gale AKD daemon"; - wantedBy = [ "multi-user.target" ]; - requires = [ "gale-galed.service" ]; - after = [ "gale-galed.service" ]; - - serviceConfig = { - Type = "forking"; - ExecStart = "@${pkgs.gale}/bin/gdomain gdomain"; - User = cfg.user; - Group = cfg.group; - }; - }; - }) - ]; -} diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix index 52c895215fb..98f80dd4bc4 100644 --- a/nixos/modules/services/networking/git-daemon.nix +++ b/nixos/modules/services/networking/git-daemon.nix @@ -74,7 +74,7 @@ in }; port = mkOption { - type = types.int; + type = types.port; default = 9418; description = "Port to listen on."; }; diff --git a/nixos/modules/services/networking/globalprotect-vpn.nix b/nixos/modules/services/networking/globalprotect-vpn.nix new file mode 100644 index 00000000000..367a42687e1 --- /dev/null +++ b/nixos/modules/services/networking/globalprotect-vpn.nix @@ -0,0 +1,43 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.globalprotect; + + execStart = if cfg.csdWrapper == null then + "${pkgs.globalprotect-openconnect}/bin/gpservice" + else + "${pkgs.globalprotect-openconnect}/bin/gpservice --csd-wrapper=${cfg.csdWrapper}"; +in + +{ + options.services.globalprotect = { + enable = mkEnableOption "globalprotect"; + + csdWrapper = mkOption { + description = '' + A script that will produce a Host Integrity Protection (HIP) report, + as described at <link xlink:href="https://www.infradead.org/openconnect/hip.html" /> + ''; + default = null; + example = literalExample "\${pkgs.openconnect}/libexec/openconnect/hipreport.sh"; + type = types.nullOr types.path; + }; + }; + + config = mkIf cfg.enable { + services.dbus.packages = [ pkgs.globalprotect-openconnect ]; + + systemd.services.gpservice = { + description = "GlobalProtect openconnect DBus service"; + serviceConfig = { + Type="dbus"; + BusName="com.yuezk.qt.GPService"; + ExecStart=execStart; + }; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + }; + }; +} diff --git a/nixos/modules/services/networking/go-neb.nix b/nixos/modules/services/networking/go-neb.nix index 991ae38f30a..765834fad83 100644 --- a/nixos/modules/services/networking/go-neb.nix +++ b/nixos/modules/services/networking/go-neb.nix @@ -5,7 +5,8 @@ with lib; let cfg = config.services.go-neb; - configFile = pkgs.writeText "config.yml" (builtins.toJSON cfg.config); + settingsFormat = pkgs.formats.yaml {}; + configFile = settingsFormat.generate "config.yaml" cfg.config; in { options.services.go-neb = { enable = mkEnableOption "Extensible matrix bot written in Go"; @@ -16,13 +17,26 @@ in { default = ":4050"; }; + secretFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/go-neb.env"; + description = '' + Environment variables from this file will be interpolated into the + final config file using envsubst with this syntax: <literal>$ENVIRONMENT</literal> + or <literal>''${VARIABLE}</literal>. + The file should contain lines formatted as <literal>SECRET_VAR=SECRET_VALUE</literal>. + This is useful to avoid putting secrets into the nix store. + ''; + }; + baseUrl = mkOption { type = types.str; description = "Public-facing endpoint that can receive webhooks."; }; config = mkOption { - type = types.uniq types.attrs; + inherit (settingsFormat) type; description = '' Your <filename>config.yaml</filename> as a Nix attribute set. See <link xlink:href="https://github.com/matrix-org/go-neb/blob/master/config.sample.yaml">config.sample.yaml</link> @@ -32,18 +46,30 @@ in { }; config = mkIf cfg.enable { - systemd.services.go-neb = { + systemd.services.go-neb = let + finalConfigFile = if cfg.secretFile == null then configFile else "/var/run/go-neb/config.yaml"; + in { description = "Extensible matrix bot written in Go"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; environment = { BASE_URL = cfg.baseUrl; BIND_ADDRESS = cfg.bindAddress; - CONFIG_FILE = configFile; + CONFIG_FILE = finalConfigFile; }; serviceConfig = { + ExecStartPre = lib.optional (cfg.secretFile != null) + (pkgs.writeShellScript "pre-start" '' + umask 077 + export $(xargs < ${cfg.secretFile}) + ${pkgs.envsubst}/bin/envsubst -i "${configFile}" > ${finalConfigFile} + chown go-neb ${finalConfigFile} + ''); + PermissionsStartOnly = true; + RuntimeDirectory = "go-neb"; ExecStart = "${pkgs.go-neb}/bin/go-neb"; + User = "go-neb"; DynamicUser = true; }; }; diff --git a/nixos/modules/services/networking/monero.nix b/nixos/modules/services/networking/monero.nix index 952d1d47ca6..9a9084e4ce1 100644 --- a/nixos/modules/services/networking/monero.nix +++ b/nixos/modules/services/networking/monero.nix @@ -110,7 +110,7 @@ in }; rpc.port = mkOption { - type = types.int; + type = types.port; default = 18081; description = '' Port the RPC server will bind to. diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index 135f29be58c..064018057cd 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -22,36 +22,51 @@ let enableIwd = cfg.wifi.backend == "iwd"; - configFile = pkgs.writeText "NetworkManager.conf" '' - [main] - plugins=keyfile - dhcp=${cfg.dhcp} - dns=${cfg.dns} - # If resolvconf is disabled that means that resolv.conf is managed by some other module. - rc-manager=${if config.networking.resolvconf.enable then "resolvconf" else "unmanaged"} - - [keyfile] - ${optionalString (cfg.unmanaged != []) - ''unmanaged-devices=${lib.concatStringsSep ";" cfg.unmanaged}''} - - [logging] - level=${cfg.logLevel} - audit=${lib.boolToString config.security.audit.enable} - - [connection] - ipv6.ip6-privacy=2 - ethernet.cloned-mac-address=${cfg.ethernet.macAddress} - wifi.cloned-mac-address=${cfg.wifi.macAddress} - ${optionalString (cfg.wifi.powersave != null) - ''wifi.powersave=${if cfg.wifi.powersave then "3" else "2"}''} - - [device] - wifi.scan-rand-mac-address=${if cfg.wifi.scanRandMacAddress then "yes" else "no"} - wifi.backend=${cfg.wifi.backend} - - ${cfg.extraConfig} + mkValue = v: + if v == true then "yes" + else if v == false then "no" + else if lib.isInt v then toString v + else v; + + mkSection = name: attrs: '' + [${name}] + ${ + lib.concatStringsSep "\n" + (lib.mapAttrsToList + (k: v: "${k}=${mkValue v}") + (lib.filterAttrs + (k: v: v != null) + attrs)) + } ''; + configFile = pkgs.writeText "NetworkManager.conf" (lib.concatStringsSep "\n" [ + (mkSection "main" { + plugins = "keyfile"; + dhcp = cfg.dhcp; + dns = cfg.dns; + # If resolvconf is disabled that means that resolv.conf is managed by some other module. + rc-manager = + if config.networking.resolvconf.enable then "resolvconf" + else "unmanaged"; + }) + (mkSection "keyfile" { + unmanaged-devices = + if cfg.unmanaged == [] then null + else lib.concatStringsSep ";" cfg.unmanaged; + }) + (mkSection "logging" { + audit = config.security.audit.enable; + level = cfg.logLevel; + }) + (mkSection "connection" cfg.connectionConfig) + (mkSection "device" { + "wifi.scan-rand-mac-address" = cfg.wifi.scanRandMacAddress; + "wifi.backend" = cfg.wifi.backend; + }) + cfg.extraConfig + ]); + /* [network-manager] Identity=unix-group:networkmanager @@ -154,6 +169,28 @@ in { ''; }; + connectionConfig = mkOption { + type = with types; attrsOf (nullOr (oneOf [ + bool + int + str + ])); + default = {}; + description = '' + Configuration for the [connection] section of NetworkManager.conf. + Refer to + <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html"> + https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html#id-1.2.3.11 + </link> + or + <citerefentry> + <refentrytitle>NetworkManager.conf</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry> + for more information. + ''; + }; + extraConfig = mkOption { type = types.lines; default = ""; @@ -482,6 +519,18 @@ in { (mkIf enableIwd { wireless.iwd.enable = true; }) + + { + networkmanager.connectionConfig = { + "ipv6.ip6-privacy" = 2; + "ethernet.cloned-mac-address" = cfg.ethernet.macAddress; + "wifi.cloned-mac-address" = cfg.wifi.macAddress; + "wifi.powersave" = + if cfg.wifi.powersave == null then null + else if cfg.wifi.powersave then 3 + else 2; + }; + } ]; boot.kernelModules = [ "ctr" ]; diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix index 2687230a158..bd75083a4a7 100644 --- a/nixos/modules/services/networking/pleroma.nix +++ b/nixos/modules/services/networking/pleroma.nix @@ -8,7 +8,7 @@ in { package = mkOption { type = types.package; - default = pkgs.pleroma-otp; + default = pkgs.pleroma; description = "Pleroma package to use."; }; diff --git a/nixos/modules/services/networking/solanum.nix b/nixos/modules/services/networking/solanum.nix index b6496fb8b35..dc066a24549 100644 --- a/nixos/modules/services/networking/solanum.nix +++ b/nixos/modules/services/networking/solanum.nix @@ -2,7 +2,7 @@ let inherit (lib) mkEnableOption mkIf mkOption types; - inherit (pkgs) solanum; + inherit (pkgs) solanum util-linux; cfg = config.services.solanum; configFile = pkgs.writeText "solanum.conf" cfg.config; @@ -78,12 +78,20 @@ in config = mkIf cfg.enable (lib.mkMerge [ { + + environment.etc."solanum/ircd.conf".source = configFile; + systemd.services.solanum = { description = "Solanum IRC daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; + reloadIfChanged = true; + restartTriggers = [ + configFile + ]; serviceConfig = { - ExecStart = "${solanum}/bin/solanum -foreground -logfile /dev/stdout -configfile ${configFile} -pidfile /run/solanum/ircd.pid"; + ExecStart = "${solanum}/bin/solanum -foreground -logfile /dev/stdout -configfile /etc/solanum/ircd.conf -pidfile /run/solanum/ircd.pid"; + ExecReload = "${util-linux}/bin/kill -HUP $MAINPID"; DynamicUser = true; User = "solanum"; StateDirectory = "solanum"; diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 089c7a12afb..91caa2ccb42 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -41,6 +41,10 @@ let Warning: If you are using <literal>NixOps</literal> then don't use this option since it will replace the key required for deployment via ssh. ''; + example = [ + "ssh-rsa AAAAB3NzaC1yc2etc/etc/etcjwrsh8e596z6J0l7 example@host" + "ssh-ed25519 AAAAC3NzaCetcetera/etceteraJZMfk3QPfQ foo@bar" + ]; }; keyFiles = mkOption { @@ -252,7 +256,17 @@ in authorizedKeysFiles = mkOption { type = types.listOf types.str; default = []; - description = "Files from which authorized keys are read."; + description = '' + Specify the rules for which files to read on the host. + + This is an advanced option. If you're looking to configure user + keys, you can generally use <xref linkend="opt-users.users._name_.openssh.authorizedKeys.keys"/> + or <xref linkend="opt-users.users._name_.openssh.authorizedKeys.keyFiles"/>. + + These are paths relative to the host root file system or home + directories and they are subject to certain token expansion rules. + See AuthorizedKeysFile in man sshd_config for details. + ''; }; authorizedKeysCommand = mkOption { @@ -337,15 +351,12 @@ in logLevel = mkOption { type = types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ]; - default = "VERBOSE"; + default = "INFO"; # upstream default description = '' Gives the verbosity level that is used when logging messages from sshd(8). The possible values are: - QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is VERBOSE. DEBUG and DEBUG1 + QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is INFO. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level violates the privacy of users and is not recommended. - - LogLevel VERBOSE logs user's key fingerprint on login. - Needed to have a clear audit track of which key was used to log in. ''; }; diff --git a/nixos/modules/services/networking/tailscale.nix b/nixos/modules/services/networking/tailscale.nix index d1b23b72a25..3f88ff53dff 100644 --- a/nixos/modules/services/networking/tailscale.nix +++ b/nixos/modules/services/networking/tailscale.nix @@ -15,6 +15,12 @@ in { description = "The port to listen on for tunnel traffic (0=autoselect)."; }; + interfaceName = mkOption { + type = types.str; + default = "tailscale0"; + description = ''The interface name for tunnel traffic. Use "userspace-networking" (beta) to not use TUN.''; + }; + package = mkOption { type = types.package; default = pkgs.tailscale; @@ -29,7 +35,10 @@ in { systemd.services.tailscaled = { wantedBy = [ "multi-user.target" ]; path = [ pkgs.openresolv pkgs.procps ]; - serviceConfig.Environment = "PORT=${toString cfg.port}"; + serviceConfig.Environment = [ + "PORT=${toString cfg.port}" + ''"FLAGS=--tun ${lib.escapeShellArg cfg.interfaceName}"'' + ]; }; }; } diff --git a/nixos/modules/services/networking/ucarp.nix b/nixos/modules/services/networking/ucarp.nix new file mode 100644 index 00000000000..9b19a19687b --- /dev/null +++ b/nixos/modules/services/networking/ucarp.nix @@ -0,0 +1,183 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.networking.ucarp; + + ucarpExec = concatStringsSep " " ( + [ + "${cfg.package}/bin/ucarp" + "--interface=${cfg.interface}" + "--srcip=${cfg.srcIp}" + "--vhid=${toString cfg.vhId}" + "--passfile=${cfg.passwordFile}" + "--addr=${cfg.addr}" + "--advbase=${toString cfg.advBase}" + "--advskew=${toString cfg.advSkew}" + "--upscript=${cfg.upscript}" + "--downscript=${cfg.downscript}" + "--deadratio=${toString cfg.deadratio}" + ] + ++ (optional cfg.preempt "--preempt") + ++ (optional cfg.neutral "--neutral") + ++ (optional cfg.shutdown "--shutdown") + ++ (optional cfg.ignoreIfState "--ignoreifstate") + ++ (optional cfg.noMcast "--nomcast") + ++ (optional (cfg.extraParam != null) "--xparam=${cfg.extraParam}") + ); +in { + options.networking.ucarp = { + enable = mkEnableOption "ucarp, userspace implementation of CARP"; + + interface = mkOption { + type = types.str; + description = "Network interface to bind to."; + example = "eth0"; + }; + + srcIp = mkOption { + type = types.str; + description = "Source (real) IP address of this host."; + }; + + vhId = mkOption { + type = types.ints.between 1 255; + description = "Virtual IP identifier shared between CARP hosts."; + example = 1; + }; + + passwordFile = mkOption { + type = types.str; + description = "File containing shared password between CARP hosts."; + example = "/run/keys/ucarp-password"; + }; + + preempt = mkOption { + type = types.bool; + description = '' + Enable preemptive failover. + Thus, this host becomes the CARP master as soon as possible. + ''; + default = false; + }; + + neutral = mkOption { + type = types.bool; + description = "Do not run downscript at start if the host is the backup."; + default = false; + }; + + addr = mkOption { + type = types.str; + description = "Virtual shared IP address."; + }; + + advBase = mkOption { + type = types.ints.unsigned; + description = "Advertisement frequency in seconds."; + default = 1; + }; + + advSkew = mkOption { + type = types.ints.unsigned; + description = "Advertisement skew in seconds."; + default = 0; + }; + + upscript = mkOption { + type = types.path; + description = '' + Command to run after become master, the interface name, virtual address + and optional extra parameters are passed as arguments. + ''; + example = '' + pkgs.writeScript "upscript" ''' + #!/bin/sh + $\{pkgs.iproute2\}/bin/ip addr add "$2"/24 dev "$1" + '''; + ''; + }; + + downscript = mkOption { + type = types.path; + description = '' + Command to run after become backup, the interface name, virtual address + and optional extra parameters are passed as arguments. + ''; + example = '' + pkgs.writeScript "downscript" ''' + #!/bin/sh + $\{pkgs.iproute2\}/bin/ip addr del "$2"/24 dev "$1" + '''; + ''; + }; + + deadratio = mkOption { + type = types.ints.unsigned; + description = "Ratio to consider a host as dead."; + default = 3; + }; + + shutdown = mkOption { + type = types.bool; + description = "Call downscript at exit."; + default = false; + }; + + ignoreIfState = mkOption { + type = types.bool; + description = "Ignore interface state, e.g., down or no carrier."; + default = false; + }; + + noMcast = mkOption { + type = types.bool; + description = "Use broadcast instead of multicast advertisements."; + default = false; + }; + + extraParam = mkOption { + type = types.nullOr types.str; + description = "Extra parameter to pass to the up/down scripts."; + default = null; + }; + + package = mkOption { + type = types.package; + description = '' + Package that should be used for ucarp. + + Please note that the default package, pkgs.ucarp, has not received any + upstream updates for a long time and can be considered as unmaintained. + ''; + default = pkgs.ucarp; + defaultText = "pkgs.ucarp"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.ucarp = { + description = "ucarp, userspace implementation of CARP"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + Type = "exec"; + ExecStart = ucarpExec; + + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + ProtectClock = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ oxzi ]; +} diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index d9308b37064..c0a4ce40760 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -40,7 +40,13 @@ in { default = []; example = [ "wlan0" "wlan1" ]; description = '' - The interfaces <command>wpa_supplicant</command> will use. + The interfaces <command>wpa_supplicant</command> will use. If empty, it will + automatically use all wireless interfaces. + <warning><para> + The automatic discovery of interfaces does not work reliably on boot: + it may fail and leave the system without network. When possible, specify + a known interface name. + </para></warning> ''; }; @@ -219,18 +225,19 @@ in { }; config = mkIf cfg.enable { - assertions = [ - { assertion = cfg.interfaces != []; - message = '' - No network interfaces for wpa_supplicant have been configured. - Please, specify at least one using networking.wireless.interfaces. - ''; - } - ] ++ flip mapAttrsToList cfg.networks (name: cfg: { + assertions = flip mapAttrsToList cfg.networks (name: cfg: { assertion = with cfg; count (x: x != null) [ psk pskRaw auth ] <= 1; message = ''options networking.wireless."${name}".{psk,pskRaw,auth} are mutually exclusive''; }); + warnings = + optional (cfg.interfaces == [] && config.systemd.services.wpa_supplicant.wantedBy != []) + '' + No network interfaces for wpa_supplicant have been configured: the service + may randomly fail to start at boot. You should specify at least one using the option + networking.wireless.interfaces. + ''; + environment.systemPackages = [ package ]; services.dbus.packages = [ package ]; @@ -261,7 +268,20 @@ in { then echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead." fi iface_args="-s -u -D${cfg.driver} ${configStr}" - args="${concatMapStringsSep " -N " (i: "-i${i} $iface_args") ifaces}" + ${if ifaces == [] then '' + for i in $(cd /sys/class/net && echo *); do + DEVTYPE= + UEVENT_PATH=/sys/class/net/$i/uevent + if [ -e "$UEVENT_PATH" ]; then + source "$UEVENT_PATH" + if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then + args+="''${args:+ -N} -i$i $iface_args" + fi + fi + done + '' else '' + args="${concatMapStringsSep " -N " (i: "-i${i} $iface_args") ifaces}" + ''} exec wpa_supplicant $args ''; }; diff --git a/nixos/modules/programs/x2goserver.nix b/nixos/modules/services/networking/x2goserver.nix index 05707a56542..48020fc1cec 100644 --- a/nixos/modules/programs/x2goserver.nix +++ b/nixos/modules/services/networking/x2goserver.nix @@ -3,7 +3,7 @@ with lib; let - cfg = config.programs.x2goserver; + cfg = config.services.x2goserver; defaults = { superenicer = { enable = cfg.superenicer.enable; }; @@ -17,7 +17,11 @@ let ''; in { - options.programs.x2goserver = { + imports = [ + (mkRenamedOptionModule [ "programs" "x2goserver" ] [ "services" "x2goserver" ]) + ]; + + options.services.x2goserver = { enable = mkEnableOption "x2goserver" // { description = '' Enables the x2goserver module. @@ -63,6 +67,14 @@ in { config = mkIf cfg.enable { + # x2goserver can run X11 program even if "services.xserver.enable = false" + xdg = { + autostart.enable = true; + menus.enable = true; + mime.enable = true; + icons.enable = true; + }; + environment.systemPackages = [ pkgs.x2goserver ]; users.groups.x2go = {}; diff --git a/nixos/modules/services/networking/xrdp.nix b/nixos/modules/services/networking/xrdp.nix index b7dd1c5d99d..9be7c3233e2 100644 --- a/nixos/modules/services/networking/xrdp.nix +++ b/nixos/modules/services/networking/xrdp.nix @@ -61,6 +61,12 @@ in ''; }; + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open the firewall for the specified RDP port."; + }; + sslKey = mkOption { type = types.str; default = "/etc/xrdp/key.pem"; @@ -99,6 +105,8 @@ in config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + # xrdp can run X11 program even if "services.xserver.enable = false" xdg = { autostart.enable = true; diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix index 0c24972823d..499d3466750 100644 --- a/nixos/modules/services/security/fail2ban.nix +++ b/nixos/modules/services/security/fail2ban.nix @@ -45,7 +45,12 @@ in enable = mkOption { default = false; type = types.bool; - description = "Whether to enable the fail2ban service."; + description = '' + Whether to enable the fail2ban service. + + See the documentation of <option>services.fail2ban.jails</option> + for what jails are enabled by default. + ''; }; package = mkOption { @@ -221,6 +226,15 @@ in defined in <filename>/etc/fail2ban/action.d</filename>, while filters are defined in <filename>/etc/fail2ban/filter.d</filename>. + + NixOS comes with a default <literal>sshd</literal> jail; + for it to work well, + <option>services.openssh.logLevel</option> should be set to + <literal>"VERBOSE"</literal> or higher so that fail2ban + can observe failed login attempts. + This module sets it to <literal>"VERBOSE"</literal> if + not set otherwise, so enabling fail2ban can make SSH logs + more verbose. ''; }; @@ -257,7 +271,6 @@ in partOf = optional config.networking.firewall.enable "firewall.service"; restartTriggers = [ fail2banConf jailConf pathsConf ]; - reloadIfChanged = true; path = [ cfg.package cfg.packageFirewall pkgs.iproute2 ] ++ cfg.extraPackages; @@ -314,6 +327,9 @@ in banaction_allports = ${cfg.banaction-allports} ''; # Block SSH if there are too many failing connection attempts. + # Benefits from verbose sshd logging to observe failed login attempts, + # so we set that here unless the user overrode it. + services.openssh.logLevel = lib.mkDefault "VERBOSE"; services.fail2ban.jails.sshd = mkDefault '' enabled = true port = ${concatMapStringsSep "," (p: toString p) config.services.openssh.ports} diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix index 2696dca4c76..63271848e94 100644 --- a/nixos/modules/services/security/privacyidea.nix +++ b/nixos/modules/services/security/privacyidea.nix @@ -7,7 +7,7 @@ let uwsgi = pkgs.uwsgi.override { plugins = [ "python3" ]; }; python = uwsgi.python3; - penv = python.withPackages (ps: [ ps.privacyidea ]); + penv = python.withPackages (const [ pkgs.privacyidea ]); logCfg = pkgs.writeText "privacyidea-log.cfg" '' [formatters] keys=detail @@ -194,7 +194,7 @@ in (mkIf cfg.enable { - environment.systemPackages = [ python.pkgs.privacyidea ]; + environment.systemPackages = [ pkgs.privacyidea ]; services.postgresql.enable = mkDefault true; diff --git a/nixos/modules/services/system/self-deploy.nix b/nixos/modules/services/system/self-deploy.nix index 3c82ed4fc59..33d15e08f4a 100644 --- a/nixos/modules/services/system/self-deploy.nix +++ b/nixos/modules/services/system/self-deploy.nix @@ -37,7 +37,9 @@ in }; nixAttribute = lib.mkOption { - type = lib.types.str; + type = with lib.types; nullOr str; + + default = null; description = '' Attribute of `nixFile` that builds the current system. diff --git a/nixos/modules/services/ttys/getty.nix b/nixos/modules/services/ttys/getty.nix index 2480e681de8..8345dfabeb7 100644 --- a/nixos/modules/services/ttys/getty.nix +++ b/nixos/modules/services/ttys/getty.nix @@ -118,7 +118,7 @@ in let speeds = concatStringsSep "," (map toString config.services.getty.serialSpeed); in { serviceConfig.ExecStart = [ "" # override upstream default with an empty ExecStart - (gettyCmd "%I ${speeds} $TERM") + (gettyCmd "%I --keep-baud ${speeds} $TERM") ]; restartIfChanged = false; }; diff --git a/nixos/modules/services/web-apps/discourse.nix b/nixos/modules/services/web-apps/discourse.nix index 49958fc6190..d3ae072f86a 100644 --- a/nixos/modules/services/web-apps/discourse.nix +++ b/nixos/modules/services/web-apps/discourse.nix @@ -30,6 +30,9 @@ in package = lib.mkOption { type = lib.types.package; default = pkgs.discourse; + apply = p: p.override { + plugins = lib.unique (p.enabledPlugins ++ cfg.plugins); + }; defaultText = "pkgs.discourse"; description = '' The discourse package to use. @@ -356,7 +359,7 @@ in }; port = lib.mkOption { - type = lib.types.int; + type = lib.types.port; default = 25; description = '' The port of the SMTP server Discourse should use to @@ -731,8 +734,6 @@ in cp -r ${cfg.package}/share/discourse/config.dist/* /run/discourse/config/ cp -r ${cfg.package}/share/discourse/public.dist/* /run/discourse/public/ - cp -r ${cfg.package}/share/discourse/plugins.dist/* /run/discourse/plugins/ - ${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} /run/discourse/plugins/") cfg.plugins} ln -sf /var/lib/discourse/uploads /run/discourse/public/uploads ln -sf /var/lib/discourse/backups /run/discourse/public/backups diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix index 2df762882fa..997604754e4 100644 --- a/nixos/modules/services/web-apps/jitsi-meet.nix +++ b/nixos/modules/services/web-apps/jitsi-meet.nix @@ -186,9 +186,10 @@ in } ]; extraModules = [ "pubsub" ]; + extraPluginPaths = [ "${pkgs.jitsi-meet-prosody}/share/prosody-plugins" ]; extraConfig = mkAfter '' - Component "focus.${cfg.hostName}" - component_secret = os.getenv("JICOFO_COMPONENT_SECRET") + Component "focus.${cfg.hostName}" "client_proxy" + target_address = "focus@auth.${cfg.hostName}" ''; virtualHosts.${cfg.hostName} = { enabled = true; @@ -254,6 +255,7 @@ in + optionalString cfg.prosody.enable '' ${config.services.prosody.package}/bin/prosodyctl register focus auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jicofo-user-secret)" ${config.services.prosody.package}/bin/prosodyctl register jvb auth.${cfg.hostName} "$(cat ${videobridgeSecret})" + ${config.services.prosody.package}/bin/prosodyctl mod_roster_command subscribe focus.${cfg.hostName} focus@auth.${cfg.hostName} # generate self-signed certificates if [ ! -f /var/lib/jitsi-meet.crt ]; then diff --git a/nixos/modules/services/web-apps/matomo.nix b/nixos/modules/services/web-apps/matomo.nix index 75da474dc44..79a0354e22b 100644 --- a/nixos/modules/services/web-apps/matomo.nix +++ b/nixos/modules/services/web-apps/matomo.nix @@ -77,6 +77,16 @@ in { ''; }; + periodicArchiveProcessingUrl = mkOption { + type = types.str; + default = "${user}.${fqdn}"; + example = "matomo.yourdomain.org"; + description = '' + URL of the host, without https prefix. By default, this is ${user}.${fqdn}, but you may want to change it if you + run Matomo on a different URL than matomo.yourdomain. + ''; + }; + nginx = mkOption { type = types.nullOr (types.submodule ( recursiveUpdate @@ -190,7 +200,7 @@ in { UMask = "0007"; CPUSchedulingPolicy = "idle"; IOSchedulingClass = "idle"; - ExecStart = "${cfg.package}/bin/matomo-console core:archive --url=https://${user}.${fqdn}"; + ExecStart = "${cfg.package}/bin/matomo-console core:archive --url=https://${cfg.periodicArchiveProcessingUrl}"; }; }; diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index a7b93c9c459..df7035c03cc 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -202,7 +202,7 @@ let let documentRoot = if hostOpts.documentRoot != null then hostOpts.documentRoot - else pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out" + else pkgs.emptyDirectory ; mkLocations = locations: concatStringsSep "\n" (map (config: '' diff --git a/nixos/modules/services/web-servers/darkhttpd.nix b/nixos/modules/services/web-servers/darkhttpd.nix index d6649fd472d..f6b693139a1 100644 --- a/nixos/modules/services/web-servers/darkhttpd.nix +++ b/nixos/modules/services/web-servers/darkhttpd.nix @@ -19,7 +19,7 @@ in { port = mkOption { default = 80; - type = ints.u16; + type = types.port; description = '' Port to listen on. Pass 0 to let the system choose any free port for you. diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix index d1cb8a8dc25..7a691aa7891 100644 --- a/nixos/modules/services/web-servers/lighttpd/default.nix +++ b/nixos/modules/services/web-servers/lighttpd/default.nix @@ -134,7 +134,7 @@ in port = mkOption { default = 80; - type = types.int; + type = types.port; description = '' TCP port number for lighttpd to bind to. ''; diff --git a/nixos/modules/services/web-servers/minio.nix b/nixos/modules/services/web-servers/minio.nix index 381a55faff1..d075449012f 100644 --- a/nixos/modules/services/web-servers/minio.nix +++ b/nixos/modules/services/web-servers/minio.nix @@ -4,6 +4,11 @@ with lib; let cfg = config.services.minio; + + legacyCredentials = cfg: pkgs.writeText "minio-legacy-credentials" '' + MINIO_ROOT_USER=${cfg.accessKey} + MINIO_ROOT_PASSWORD=${cfg.secretKey} + ''; in { meta.maintainers = [ maintainers.bachp ]; @@ -49,6 +54,17 @@ in ''; }; + rootCredentialsFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + File containing the MINIO_ROOT_USER, default is "minioadmin", and + MINIO_ROOT_PASSWORD (length >= 8), default is "minioadmin"; in the format of + an EnvironmentFile=, as described by systemd.exec(5). + ''; + example = "/etc/nixos/minio-root-credentials"; + }; + region = mkOption { default = "us-east-1"; type = types.str; @@ -72,6 +88,8 @@ in }; config = mkIf cfg.enable { + warnings = optional ((cfg.accessKey != "") || (cfg.secretKey != "")) "services.minio.`accessKey` and services.minio.`secretKey` are deprecated, please use services.minio.`rootCredentialsFile` instead."; + systemd.tmpfiles.rules = [ "d '${cfg.configDir}' - minio minio - -" ] ++ (map (x: "d '" + x + "' - minio minio - - ") cfg.dataDir); @@ -86,14 +104,13 @@ in User = "minio"; Group = "minio"; LimitNOFILE = 65536; + EnvironmentFile = if (cfg.rootCredentialsFile != null) then cfg.rootCredentialsFile + else if ((cfg.accessKey != "") || (cfg.secretKey != "")) then (legacyCredentials cfg) + else null; }; environment = { MINIO_REGION = "${cfg.region}"; MINIO_BROWSER = "${if cfg.browser then "on" else "off"}"; - } // optionalAttrs (cfg.accessKey != "") { - MINIO_ACCESS_KEY = "${cfg.accessKey}"; - } // optionalAttrs (cfg.secretKey != "") { - MINIO_SECRET_KEY = "${cfg.secretKey}"; }; }; diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 1c7d4024479..bc18bcaa7b3 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -169,7 +169,7 @@ with lib; description = '' Whether to enable HTTP 3. This requires using <literal>pkgs.nginxQuic</literal> package - which can be achived by setting <literal>services.nginx.package = pkgs.nginxQuic;</literal>. + which can be achieved by setting <literal>services.nginx.package = pkgs.nginxQuic;</literal>. Note that HTTP 3 support is experimental and *not* yet recommended for production. Read more at https://quic.nginx.org/ diff --git a/nixos/modules/services/x11/desktop-managers/cinnamon.nix b/nixos/modules/services/x11/desktop-managers/cinnamon.nix index 101c64c7b3e..d201c1a5334 100644 --- a/nixos/modules/services/x11/desktop-managers/cinnamon.nix +++ b/nixos/modules/services/x11/desktop-managers/cinnamon.nix @@ -198,6 +198,7 @@ in environment.systemPackages = (with pkgs // pkgs.gnome // pkgs.cinnamon; pkgs.gnome.removePackagesByName [ # cinnamon team apps + bulky blueberry warpinator diff --git a/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixos/modules/services/x11/desktop-managers/gnome.nix index 2b2ee019aeb..b0859321a52 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome.nix @@ -180,7 +180,7 @@ in enable = mkOption { type = types.bool; default = false; - description = "Enable Gnome 3 desktop manager."; + description = "Enable GNOME desktop manager."; }; sessionPath = mkOption { @@ -283,7 +283,7 @@ in (mkIf (cfg.enable || flashbackEnabled) { # Seed our configuration into nixos-generate-config system.nixos-generate-config.desktopConfiguration = ['' - # Enable the GNOME 3 Desktop Environment. + # Enable the GNOME Desktop Environment. services.xserver.displayManager.gdm.enable = true; services.xserver.desktopManager.gnome.enable = true; '']; diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index e1b9a21eb9f..ef9ec438cc1 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -99,7 +99,8 @@ in autoSuspend = mkOption { default = true; description = '' - Suspend the machine after inactivity. + On the GNOME Display Manager login screen, suspend the machine after inactivity. + (Does not affect automatic suspend while logged in, or at lock screen.) ''; type = types.bool; }; diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix index 9b0757153cc..439708bc47e 100644 --- a/nixos/modules/services/x11/hardware/libinput.nix +++ b/nixos/modules/services/x11/hardware/libinput.nix @@ -188,27 +188,27 @@ let cfg = config.services.xserver.libinput; }; mkX11ConfigForDevice = deviceType: matchIs: '' - Identifier "libinput ${deviceType} configuration" - MatchDriver "libinput" - MatchIs${matchIs} "${xorgBool true}" - ${optionalString (cfg.${deviceType}.dev != null) ''MatchDevicePath "${cfg.${deviceType}.dev}"''} - Option "AccelProfile" "${cfg.${deviceType}.accelProfile}" - ${optionalString (cfg.${deviceType}.accelSpeed != null) ''Option "AccelSpeed" "${cfg.${deviceType}.accelSpeed}"''} - ${optionalString (cfg.${deviceType}.buttonMapping != null) ''Option "ButtonMapping" "${cfg.${deviceType}.buttonMapping}"''} - ${optionalString (cfg.${deviceType}.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.${deviceType}.calibrationMatrix}"''} - ${optionalString (cfg.${deviceType}.clickMethod != null) ''Option "ClickMethod" "${cfg.${deviceType}.clickMethod}"''} - Option "LeftHanded" "${xorgBool cfg.${deviceType}.leftHanded}" - Option "MiddleEmulation" "${xorgBool cfg.${deviceType}.middleEmulation}" - Option "NaturalScrolling" "${xorgBool cfg.${deviceType}.naturalScrolling}" - ${optionalString (cfg.${deviceType}.scrollButton != null) ''Option "ScrollButton" "${toString cfg.${deviceType}.scrollButton}"''} - Option "ScrollMethod" "${cfg.${deviceType}.scrollMethod}" - Option "HorizontalScrolling" "${xorgBool cfg.${deviceType}.horizontalScrolling}" - Option "SendEventsMode" "${cfg.${deviceType}.sendEventsMode}" - Option "Tapping" "${xorgBool cfg.${deviceType}.tapping}" - Option "TappingDragLock" "${xorgBool cfg.${deviceType}.tappingDragLock}" - Option "DisableWhileTyping" "${xorgBool cfg.${deviceType}.disableWhileTyping}" - ${cfg.${deviceType}.additionalOptions} - ''; + Identifier "libinput ${deviceType} configuration" + MatchDriver "libinput" + MatchIs${matchIs} "${xorgBool true}" + ${optionalString (cfg.${deviceType}.dev != null) ''MatchDevicePath "${cfg.${deviceType}.dev}"''} + Option "AccelProfile" "${cfg.${deviceType}.accelProfile}" + ${optionalString (cfg.${deviceType}.accelSpeed != null) ''Option "AccelSpeed" "${cfg.${deviceType}.accelSpeed}"''} + ${optionalString (cfg.${deviceType}.buttonMapping != null) ''Option "ButtonMapping" "${cfg.${deviceType}.buttonMapping}"''} + ${optionalString (cfg.${deviceType}.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.${deviceType}.calibrationMatrix}"''} + ${optionalString (cfg.${deviceType}.clickMethod != null) ''Option "ClickMethod" "${cfg.${deviceType}.clickMethod}"''} + Option "LeftHanded" "${xorgBool cfg.${deviceType}.leftHanded}" + Option "MiddleEmulation" "${xorgBool cfg.${deviceType}.middleEmulation}" + Option "NaturalScrolling" "${xorgBool cfg.${deviceType}.naturalScrolling}" + ${optionalString (cfg.${deviceType}.scrollButton != null) ''Option "ScrollButton" "${toString cfg.${deviceType}.scrollButton}"''} + Option "ScrollMethod" "${cfg.${deviceType}.scrollMethod}" + Option "HorizontalScrolling" "${xorgBool cfg.${deviceType}.horizontalScrolling}" + Option "SendEventsMode" "${cfg.${deviceType}.sendEventsMode}" + Option "Tapping" "${xorgBool cfg.${deviceType}.tapping}" + Option "TappingDragLock" "${xorgBool cfg.${deviceType}.tappingDragLock}" + Option "DisableWhileTyping" "${xorgBool cfg.${deviceType}.disableWhileTyping}" + ${cfg.${deviceType}.additionalOptions} + ''; in { imports = diff --git a/nixos/modules/services/x11/window-managers/fvwm.nix b/nixos/modules/services/x11/window-managers/fvwm.nix index 9a51b9cd660..e283886ecc4 100644 --- a/nixos/modules/services/x11/window-managers/fvwm.nix +++ b/nixos/modules/services/x11/window-managers/fvwm.nix @@ -4,7 +4,7 @@ with lib; let cfg = config.services.xserver.windowManager.fvwm; - fvwm = pkgs.fvwm.override { gestures = cfg.gestures; }; + fvwm = pkgs.fvwm.override { enableGestures = cfg.gestures; }; in { diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 4dde4476d2c..37e004ae80a 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -81,13 +81,7 @@ let monitors = forEach xrandrHeads (h: '' Option "monitor-${h.config.output}" "${h.name}" ''); - # First option is indented through the space in the config but any - # subsequent options aren't so we need to apply indentation to - # them here - monitorsIndented = if length monitors > 1 - then singleton (head monitors) ++ map (m: " " + m) (tail monitors) - else monitors; - in concatStrings monitorsIndented; + in concatStrings monitors; # Here we chain every monitor from the left to right, so we have: # m4 right of m3 right of m2 right of m1 .----.----.----.----. @@ -138,10 +132,15 @@ let echo '${cfg.filesSection}' >> $out echo 'EndSection' >> $out + echo >> $out echo "$config" >> $out ''; # */ + prefixStringLines = prefix: str: + concatMapStringsSep "\n" (line: prefix + line) (splitString "\n" str); + + indent = prefixStringLines " "; in { @@ -358,6 +357,13 @@ in description = '' The contents of the configuration file of the X server (<filename>xorg.conf</filename>). + + This option is set by multiple modules, and the configs are + concatenated together. + + In Xorg configs the last config entries take precedence, + so you may want to use <literal>lib.mkAfter</literal> on this option + to override NixOS's defaults. ''; }; @@ -736,29 +742,29 @@ in Section "ServerFlags" Option "AllowMouseOpenFail" "on" Option "DontZap" "${if cfg.enableCtrlAltBackspace then "off" else "on"}" - ${cfg.serverFlagsSection} + ${indent cfg.serverFlagsSection} EndSection Section "Module" - ${cfg.moduleSection} + ${indent cfg.moduleSection} EndSection Section "Monitor" Identifier "Monitor[0]" - ${cfg.monitorSection} + ${indent cfg.monitorSection} EndSection # Additional "InputClass" sections - ${flip concatMapStrings cfg.inputClassSections (inputClassSection: '' - Section "InputClass" - ${inputClassSection} - EndSection + ${flip (concatMapStringsSep "\n") cfg.inputClassSections (inputClassSection: '' + Section "InputClass" + ${indent inputClassSection} + EndSection '')} Section "ServerLayout" Identifier "Layout[all]" - ${cfg.serverLayoutSection} + ${indent cfg.serverLayoutSection} # Reference the Screen sections for each driver. This will # cause the X server to try each in turn. ${flip concatMapStrings (filter (d: d.display) cfg.drivers) (d: '' @@ -781,9 +787,9 @@ in Identifier "Device-${driver.name}[0]" Driver "${driver.driverName or driver.name}" ${if cfg.useGlamor then ''Option "AccelMethod" "glamor"'' else ""} - ${cfg.deviceSection} - ${driver.deviceSection or ""} - ${xrandrDeviceSection} + ${indent cfg.deviceSection} + ${indent (driver.deviceSection or "")} + ${indent xrandrDeviceSection} EndSection ${optionalString driver.display '' @@ -794,18 +800,22 @@ in Monitor "Monitor[0]" ''} - ${cfg.screenSection} - ${driver.screenSection or ""} + ${indent cfg.screenSection} + ${indent (driver.screenSection or "")} ${optionalString (cfg.defaultDepth != 0) '' DefaultDepth ${toString cfg.defaultDepth} ''} ${optionalString - (driver.name != "virtualbox" && + ( + driver.name != "virtualbox" + && (cfg.resolutions != [] || cfg.extraDisplaySettings != "" || - cfg.virtualScreen != null)) + cfg.virtualScreen != null + ) + ) (let f = depth: '' @@ -813,7 +823,7 @@ in Depth ${toString depth} ${optionalString (cfg.resolutions != []) "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}"} - ${cfg.extraDisplaySettings} + ${indent cfg.extraDisplaySettings} ${optionalString (cfg.virtualScreen != null) "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"} EndSubSection diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 363d8e47a0f..1a6a9d99d5b 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -38,11 +38,11 @@ in default = pkgs.linuxPackages; type = types.unspecified // { merge = mergeEqualOption; }; apply = kernelPackages: kernelPackages.extend (self: super: { - kernel = super.kernel.override { + kernel = super.kernel.override (originalArgs: { inherit randstructSeed; - kernelPatches = super.kernel.kernelPatches ++ kernelPatches; + kernelPatches = (originalArgs.kernelPatches or []) ++ kernelPatches; features = lib.recursiveUpdate super.kernel.features features; - }; + }); }); # We don't want to evaluate all of linuxPackages for the manual # - some of it might not even evaluate correctly. diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index 065d6cc95d1..d274a38a270 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -24,13 +24,15 @@ let specialFSTypes = [ "proc" "sysfs" "tmpfs" "ramfs" "devtmpfs" "devpts" ]; + nonEmptyWithoutTrailingSlash = addCheckDesc "non-empty without trailing slash" types.str + (s: isNonEmpty s && (builtins.match ".+/" s) == null); + coreFileSystemOpts = { name, config, ... }: { options = { mountPoint = mkOption { example = "/mnt/usb"; - type = addCheckDesc "non-empty without trailing slash" types.str - (s: isNonEmpty s && (builtins.match ".+/" s) == null); + type = nonEmptyWithoutTrailingSlash; description = "Location of the mounted the file system."; }; @@ -55,6 +57,20 @@ let type = types.listOf nonEmptyStr; }; + depends = mkOption { + default = [ ]; + example = [ "/persist" ]; + type = types.listOf nonEmptyWithoutTrailingSlash; + description = '' + List of paths that should be mounted before this one. This filesystem's + <option>device</option> and <option>mountPoint</option> are always + checked and do not need to be included explicitly. If a path is added + to this list, any other filesystem whose mount point is a parent of + the path will be mounted before this filesystem. The paths do not need + to actually be the <option>mountPoint</option> of some other filesystem. + ''; + }; + }; config = { @@ -238,8 +254,11 @@ in skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck; # https://wiki.archlinux.org/index.php/fstab#Filepath_spaces escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string; - swapOptions = sw: "defaults" - + optionalString (sw.priority != null) ",pri=${toString sw.priority}"; + swapOptions = sw: concatStringsSep "," ( + [ "defaults" ] + ++ optional (sw.priority != null) "pri=${toString sw.priority}" + ++ optional (sw.discardPolicy != null) "discard${optionalString (sw.discardPolicy != "both") "=${toString sw.discardPolicy}"}" + ); in '' # This is a generated file. Do not edit! # diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix index b154cf9f5f0..029d8a00295 100644 --- a/nixos/modules/tasks/trackpoint.nix +++ b/nixos/modules/tasks/trackpoint.nix @@ -87,9 +87,9 @@ with lib; }) (mkIf (cfg.emulateWheel) { - services.xserver.inputClassSections = - ['' - Identifier "Trackpoint Wheel Emulation" + services.xserver.inputClassSections = [ + '' + Identifier "Trackpoint Wheel Emulation" MatchProduct "${if cfg.fakeButtons then "PS/2 Generic Mouse" else "ETPS/2 Elantech TrackPoint|Elantech PS/2 TrackPoint|TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint|${cfg.device}"}" MatchDevicePath "/dev/input/event*" Option "EmulateWheel" "true" @@ -97,7 +97,8 @@ with lib; Option "Emulate3Buttons" "false" Option "XAxisMapping" "6 7" Option "YAxisMapping" "4 5" - '']; + '' + ]; }) (mkIf cfg.fakeButtons { diff --git a/nixos/modules/virtualisation/ec2-amis.nix b/nixos/modules/virtualisation/ec2-amis.nix index 892af513b03..d38f41ab39d 100644 --- a/nixos/modules/virtualisation/ec2-amis.nix +++ b/nixos/modules/virtualisation/ec2-amis.nix @@ -348,5 +348,24 @@ let self = { "20.09".ap-east-1.hvm-ebs = "ami-0c42f97e5b1fda92f"; "20.09".sa-east-1.hvm-ebs = "ami-021637976b094959d"; - latest = self."20.09"; + # 21.05.740.aa576357673 + "21.05".eu-west-1.hvm-ebs = "ami-048dbc738074a3083"; + "21.05".eu-west-2.hvm-ebs = "ami-0234cf81fec68315d"; + "21.05".eu-west-3.hvm-ebs = "ami-020e459baf709107d"; + "21.05".eu-central-1.hvm-ebs = "ami-0857d5d1309ab8b77"; + "21.05".eu-north-1.hvm-ebs = "ami-05403e3ae53d3716f"; + "21.05".us-east-1.hvm-ebs = "ami-0d3002ba40b5b9897"; + "21.05".us-east-2.hvm-ebs = "ami-069a0ca1bde6dea52"; + "21.05".us-west-1.hvm-ebs = "ami-0b415460a84bcf9bc"; + "21.05".us-west-2.hvm-ebs = "ami-093cba49754abd7f8"; + "21.05".ca-central-1.hvm-ebs = "ami-065c13e1d52d60b33"; + "21.05".ap-southeast-1.hvm-ebs = "ami-04f570c70ff9b665e"; + "21.05".ap-southeast-2.hvm-ebs = "ami-02a3d1df595df5ef6"; + "21.05".ap-northeast-1.hvm-ebs = "ami-027836fddb5c56012"; + "21.05".ap-northeast-2.hvm-ebs = "ami-0edacd41dc7700c39"; + "21.05".ap-south-1.hvm-ebs = "ami-0b279b5bb55288059"; + "21.05".ap-east-1.hvm-ebs = "ami-06dc98082bc55c1fc"; + "21.05".sa-east-1.hvm-ebs = "ami-04737dd49b98936c6"; + + latest = self."21.05"; }; in self diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index 61ebc3ab8cf..f45f1802d91 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -155,6 +155,13 @@ in { config = mkIf cfg.enable { + assertions = [ + { + assertion = config.security.polkit.enable; + message = "The libvirtd module currently requires Polkit to be enabled ('security.polkit.enable = true')."; + } + ]; + environment = { # this file is expected in /etc/qemu and not sysconfdir (/var/lib) etc."qemu/bridge.conf".text = lib.concatMapStringsSep "\n" (e: diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index 071edda8269..272c696807a 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -58,7 +58,19 @@ in { Run <literal>VBoxManage modifyvm --help</literal> to see more options. ''; - }; + }; + exportParams = mkOption { + type = with types; listOf (oneOf [ str int bool (listOf str) ]); + example = [ + "--vsys" "0" "--vendor" "ACME Inc." + ]; + default = []; + description = '' + Parameters passed to the Virtualbox export command. + + Run <literal>VBoxManage export --help</literal> to see more options. + ''; + }; extraDisk = mkOption { description = '' Optional extra disk/hdd configuration. @@ -158,7 +170,7 @@ in { echo "exporting VirtualBox VM..." mkdir -p $out fn="$out/${cfg.vmFileName}" - VBoxManage export "$vmName" --output "$fn" --options manifest + VBoxManage export "$vmName" --output "$fn" --options manifest ${escapeShellArgs cfg.exportParams} rm -v $diskImage |