diff options
Diffstat (limited to 'nixos/modules')
206 files changed, 6706 insertions, 2086 deletions
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix index 619f36cd5150..4101ef82f3e1 100644 --- a/nixos/modules/config/networking.nix +++ b/nixos/modules/config/networking.nix @@ -290,8 +290,8 @@ in ln -s /run/systemd/resolve/resolv.conf /run/resolvconf/interfaces/systemd ''} - # Make sure resolv.conf is up to date if not managed by systemd - ${optionalString (!config.services.resolved.enable) '' + # Make sure resolv.conf is up to date if not managed manually or by systemd + ${optionalString (!config.environment.etc?"resolv.conf") '' ${pkgs.openresolv}/bin/resolvconf -u ''} ''; diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix index ae3e17ac27b6..e1c4d0d602af 100644 --- a/nixos/modules/config/no-x-libs.nix +++ b/nixos/modules/config/no-x-libs.nix @@ -35,7 +35,7 @@ with lib; networkmanager_pptp = pkgs.networkmanager_pptp.override { withGnome = false; }; networkmanager_vpnc = pkgs.networkmanager_vpnc.override { withGnome = false; }; networkmanager_iodine = pkgs.networkmanager_iodine.override { withGnome = false; }; - pinentry = pkgs.pinentry.override { gtk2 = null; qt4 = null; }; + pinentry = pkgs.pinentry_ncurses; }; }; } diff --git a/nixos/modules/config/power-management.nix b/nixos/modules/config/power-management.nix index a4a4d6e1a6af..4c37e8a6208c 100644 --- a/nixos/modules/config/power-management.nix +++ b/nixos/modules/config/power-management.nix @@ -69,9 +69,6 @@ in config = mkIf cfg.enable { - # Leftover for old setups, should be set by nixos-generate-config now - powerManagement.cpuFreqGovernor = mkDefault "ondemand"; - systemd.targets.post-resume = { description = "Post-Resume Actions"; requires = [ "post-resume.service" ]; diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 8b9c3570476a..a9c5fc75660d 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -45,7 +45,7 @@ let uid = ids.uids.pulseaudio; gid = ids.gids.pulseaudio; - stateDir = "/var/run/pulse"; + stateDir = "/run/pulse"; # Create pulse/client.conf even if PulseAudio is disabled so # that we can disable the autospawn feature in programs that @@ -101,7 +101,8 @@ in { each user that tries to use the sound system. The server runs with user privileges. This is the recommended and most secure way to use PulseAudio. If true, one system-wide PulseAudio - server is launched on boot, running as the user "pulse". + server is launched on boot, running as the user "pulse", and + only users in the "audio" group will have access to the server. Please read the PulseAudio documentation for more details. ''; }; @@ -219,6 +220,12 @@ in { { target = "pulse/daemon.conf"; source = writeText "daemon.conf" (lib.generators.toKeyValue {} cfg.daemon.config); } + + { target = "openal/alsoft.conf"; + source = writeText "alsoft.conf" "drivers=pulse"; } + + { target = "libao.conf"; + source = writeText "libao.conf" "default_driver=pulse"; } ]; # Allow PulseAudio to get realtime priority using rtkit. diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix index 65f2e5d7af99..398660967c52 100644 --- a/nixos/modules/config/shells-environment.nix +++ b/nixos/modules/config/shells-environment.nix @@ -36,7 +36,7 @@ in default = {}; description = '' A set of environment variables used in the global environment. - These variables will be set on shell initialisation. + These variables will be set on shell initialisation (e.g. in /etc/profile). The value of each variable can be either a string or a list of strings. The latter is concatenated, interspersed with colon characters. diff --git a/nixos/modules/installer/cd-dvd/channel.nix b/nixos/modules/installer/cd-dvd/channel.nix index ddb00f174d1a..4a1983167957 100644 --- a/nixos/modules/installer/cd-dvd/channel.nix +++ b/nixos/modules/installer/cd-dvd/channel.nix @@ -12,7 +12,7 @@ let # CD. These are installed into the "nixos" channel of the root # user, as expected by nixos-rebuild/nixos-install. FIXME: merge # with make-channel.nix. - channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" + channelSources = pkgs.runCommand "nixos-${config.system.nixos.version}" { } '' mkdir -p $out @@ -21,7 +21,7 @@ let if [ ! -e $out/nixos/nixpkgs ]; then ln -s . $out/nixos/nixpkgs fi - echo -n ${config.system.nixosVersionSuffix} > $out/nixos/.version-suffix + echo -n ${config.system.nixos.versionSuffix} > $out/nixos/.version-suffix ''; in diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index 2569860a098f..756c8751d00e 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -16,7 +16,7 @@ with lib; ]; # ISO naming. - isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixosLabel}-${pkgs.stdenv.system}.iso"; + isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixos.label}-${pkgs.stdenv.system}.iso"; isoImage.volumeID = substring 0 11 "NIXOS_ISO"; diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index a039f7fdcb6e..811449e9fe7e 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -39,31 +39,31 @@ let DEFAULT boot LABEL boot - MENU LABEL NixOS ${config.system.nixosLabel}${config.isoImage.appendToMenuLabel} - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} # A variant to boot with 'nomodeset' LABEL boot-nomodeset - MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (nomodeset) - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (nomodeset) + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} # A variant to boot with 'copytoram' LABEL boot-copytoram - MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (copytoram) - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (copytoram) + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} # A variant to boot with verbose logging to the console LABEL boot-nomodeset - MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (debug) - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug) + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7 - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} ''; isolinuxMemtest86Entry = '' @@ -82,35 +82,35 @@ let mkdir -p $out/loader/entries cat << EOF > $out/loader/entries/nixos-iso.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} - linux /boot/bzImage - initrd /boot/initrd + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} EOF # A variant to boot with 'nomodeset' cat << EOF > $out/loader/entries/nixos-iso-nomodeset.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} version nomodeset - linux /boot/bzImage - initrd /boot/initrd + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset EOF # A variant to boot with 'copytoram' cat << EOF > $out/loader/entries/nixos-iso-copytoram.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} version copytoram - linux /boot/bzImage - initrd /boot/initrd + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram EOF # A variant to boot with verbose logging to the console cat << EOF > $out/loader/entries/nixos-iso-debug.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (debug) - linux /boot/bzImage - initrd /boot/initrd + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug) + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7 EOF @@ -127,8 +127,8 @@ let mkdir ./contents && cd ./contents cp -rp "${efiDir}"/* . mkdir ./boot - cp -p "${config.boot.kernelPackages.kernel}/bzImage" \ - "${config.system.build.initialRamdisk}/initrd" ./boot/ + cp -p "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}" \ + "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}" ./boot/ touch --date=@0 ./* usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]') @@ -346,11 +346,11 @@ in }; target = "/isolinux/isolinux.cfg"; } - { source = config.boot.kernelPackages.kernel + "/bzImage"; - target = "/boot/bzImage"; + { source = config.boot.kernelPackages.kernel + "/" + config.system.boot.loader.kernelFile; + target = "/boot/" + config.system.boot.loader.kernelFile; } - { source = config.system.build.initialRamdisk + "/initrd"; - target = "/boot/initrd"; + { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile; + target = "/boot/" + config.system.boot.loader.initrdFile; } { source = config.system.build.squashfsStore; target = "/nix-store.squashfs"; @@ -361,7 +361,7 @@ in { source = config.isoImage.splashImage; target = "/isolinux/background.png"; } - { source = pkgs.writeText "version" config.system.nixosVersion; + { source = pkgs.writeText "version" config.system.nixos.label; target = "/version.txt"; } ] ++ optionals config.isoImage.makeEfiBootable [ diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix index efb9ba39bcd4..3306846b7fa7 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix @@ -27,6 +27,7 @@ in boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; + boot.consoleLogLevel = lib.mkDefault 7; boot.kernelPackages = pkgs.linuxPackages_latest; # The serial ports listed here are: @@ -42,8 +43,17 @@ in populateBootCommands = let configTxt = pkgs.writeText "config.txt" '' kernel=u-boot-rpi3.bin + + # Boot in 64-bit mode. arm_control=0x200 + + # U-Boot used to need this to work, regardless of whether UART is actually used or not. + # TODO: check when/if this can be removed. enable_uart=1 + + # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel + # when attempting to show low-voltage or overtemperature warnings. + avoid_warnings=1 ''; in '' (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/boot/) diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix index 880a6bf2e1e8..08903ba397a1 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -27,6 +27,7 @@ in boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; + boot.consoleLogLevel = lib.mkDefault 7; boot.kernelPackages = pkgs.linuxPackages_latest; # The serial ports listed here are: # - ttyS0: for Tegra (Jetson TK1) @@ -42,11 +43,18 @@ in sdImage = { populateBootCommands = let configTxt = pkgs.writeText "config.txt" '' + # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel + # when attempting to show low-voltage or overtemperature warnings. + avoid_warnings=1 + [pi2] kernel=u-boot-rpi2.bin [pi3] kernel=u-boot-rpi3.bin + + # U-Boot used to need this to work, regardless of whether UART is actually used or not. + # TODO: check when/if this can be removed. enable_uart=1 ''; in '' diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix index eb676eae05e8..2833b75b84d8 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix @@ -27,6 +27,7 @@ in boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; + boot.consoleLogLevel = lib.mkDefault 7; boot.kernelPackages = pkgs.linuxPackages_rpi; # FIXME: this probably should be in installation-device.nix diff --git a/nixos/modules/installer/cd-dvd/system-tarball.nix b/nixos/modules/installer/cd-dvd/system-tarball.nix index 1962a1959ead..e72d4a5b4910 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball.nix @@ -8,7 +8,7 @@ with lib; let - versionFile = pkgs.writeText "nixos-version" config.system.nixosVersion; + versionFile = pkgs.writeText "nixos-label" config.system.nixos.label; in @@ -58,8 +58,8 @@ in # Individual files to be included on the CD, outside of the Nix # store on the CD. tarball.contents = - [ { source = config.system.build.initialRamdisk + "/initrd"; - target = "/boot/initrd"; + [ { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile; + target = "/boot/" + config.system.boot.loader.initrdFile; } { source = versionFile; target = "/nixos-version.txt"; diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix index 0f6046339b37..52239b619126 100644 --- a/nixos/modules/installer/netboot/netboot.nix +++ b/nixos/modules/installer/netboot/netboot.nix @@ -18,17 +18,17 @@ with lib; }; - config = { - - boot.loader.grub.version = 2; - + config = rec { # Don't build the GRUB menu builder script, since we don't need it # here and it causes a cyclic dependency. boot.loader.grub.enable = false; # !!! Hack - attributes expected by other modules. - system.boot.loader.kernelFile = "bzImage"; - environment.systemPackages = [ pkgs.grub2 pkgs.grub2_efi pkgs.syslinux ]; + environment.systemPackages = [ pkgs.grub2_efi ] + ++ (if pkgs.stdenv.system == "aarch64-linux" + then [] + else [ pkgs.grub2 pkgs.syslinux ]); + system.boot.loader.kernelFile = pkgs.stdenv.platform.kernelTarget; fileSystems."/" = { fsType = "tmpfs"; @@ -84,7 +84,12 @@ with lib; ]; }; - system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" "#!ipxe\nkernel bzImage init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}\ninitrd initrd\nboot"; + system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" '' + #!ipxe + kernel ${pkgs.stdenv.platform.kernelTarget} init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} + initrd initrd + boot + ''; boot.loader.timeout = 10; diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix index 321fb9a2030a..131c779b1ab1 100644 --- a/nixos/modules/installer/tools/nix-fallback-paths.nix +++ b/nixos/modules/installer/tools/nix-fallback-paths.nix @@ -1,5 +1,6 @@ { - x86_64-linux = "/nix/store/b4s1gxiis1ryvybnjhdjvgc5sr1nq0ys-nix-1.11.15"; - i686-linux = "/nix/store/kgb5hs7qw13bvb6icramv1ry9dard3h9-nix-1.11.15"; - x86_64-darwin = "/nix/store/dgwz3dxdzs2wwd7pg7cdhvl8rv0qpnbj-nix-1.11.15"; + x86_64-linux = "/nix/store/gy4yv67gv3j6in0lalw37j353zdmfcwm-nix-1.11.16"; + i686-linux = "/nix/store/ifmyq5ryfxhhrzh62hiq65xyz1fwffga-nix-1.11.16"; + aarch64-linux = "/nix/store/y9mfv3sx75mbfibf1zna1kq9v98fk2nb-nix-1.11.16"; + x86_64-darwin = "/nix/store/hwpp7kia2f0in5ns2hiw41q38k30jpj2-nix-1.11.16"; } diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 7c737e84de0a..a82ee63fd0cd 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -625,7 +625,7 @@ $bootLoaderConfig # compatible, in order to avoid breaking some software such as database # servers. You should change this only after NixOS release notes say you # should. - system.stateVersion = "${\(qw(@nixosRelease@))}"; # Did you read the comment? + system.stateVersion = "${\(qw(@release@))}"; # Did you read the comment? } EOF diff --git a/nixos/modules/installer/tools/nixos-version.sh b/nixos/modules/installer/tools/nixos-version.sh index 77a1b458a342..190c49a33ec6 100644 --- a/nixos/modules/installer/tools/nixos-version.sh +++ b/nixos/modules/installer/tools/nixos-version.sh @@ -6,9 +6,9 @@ case "$1" in exit 1 ;; --hash|--revision) - echo "@nixosRevision@" + echo "@revision@" ;; *) - echo "@nixosVersion@ (@nixosCodeName@)" + echo "@version@ (@codeName@)" ;; esac diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index a3bae78c0ffc..eab5f1147667 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -55,7 +55,7 @@ let src = ./nixos-generate-config.pl; path = [ pkgs.btrfs-progs ]; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; - inherit (config.system) nixosRelease; + inherit (config.system.nixos) release; }; nixos-option = makeProg { @@ -66,7 +66,7 @@ let nixos-version = makeProg { name = "nixos-version"; src = ./nixos-version.sh; - inherit (config.system) nixosVersion nixosCodeName nixosRevision; + inherit (config.system.nixos) version codeName revision; }; in diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index c10b5a0ec932..c0c6a6ef9244 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -65,7 +65,7 @@ foldingathome = 37; sabnzbd = 38; #kdm = 39; # dropped in 17.03 - ghostone = 40; + #ghostone = 40; # dropped in 18.03 git = 41; fourstore = 42; fourstorehttp = 43; @@ -197,10 +197,10 @@ #input = 174; # unused sddm = 175; tss = 176; - memcached = 177; + #memcached = 177; removed 2018-01-03 ntp = 179; zabbix = 180; - redis = 181; + #redis = 181; removed 2018-01-03 unifi = 183; uptimed = 184; zope2 = 185; @@ -281,8 +281,8 @@ stanchion = 262; riak-cs = 263; infinoted = 264; - keystone = 265; - glance = 266; + # keystone = 265; # unused, removed 2017-12-13 + # glance = 266; # unused, removed 2017-12-13 couchpotato = 267; gogs = 268; pdns-recursor = 269; @@ -301,6 +301,9 @@ pykms = 282; kodi = 283; restya-board = 284; + mighttpd2 = 285; + hass = 286; + monero = 287; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -348,7 +351,7 @@ #foldingathome = 37; # unused #sabnzd = 38; # unused #kdm = 39; # unused, even before 17.03 - ghostone = 40; + #ghostone = 40; # dropped in 18.03 git = 41; fourstore = 42; fourstorehttp = 43; @@ -475,10 +478,10 @@ input = 174; sddm = 175; tss = 176; - #memcached = 177; # unused + #memcached = 177; # unused, removed 2018-01-03 #ntp = 179; # unused #zabbix = 180; # unused - #redis = 181; # unused + #redis = 181; # unused, removed 2018-01-03 #unifi = 183; # unused #uptimed = 184; # unused #zope2 = 185; # unused @@ -551,8 +554,8 @@ stanchion = 262; riak-cs = 263; infinoted = 264; - keystone = 265; - glance = 266; + # keystone = 265; # unused, removed 2017-12-13 + # glance = 266; # unused, removed 2017-12-13 couchpotato = 267; gogs = 268; kresd = 270; @@ -570,6 +573,9 @@ pykms = 282; kodi = 283; restya-board = 284; + mighttpd2 = 285; + hass = 286; + monero = 287; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/misc/label.nix b/nixos/modules/misc/label.nix new file mode 100644 index 000000000000..250914e8f82e --- /dev/null +++ b/nixos/modules/misc/label.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.system.nixos; +in + +{ + + options.system = { + + nixos.label = mkOption { + type = types.str; + description = '' + NixOS version name to be used in the names of generated + outputs and boot labels. + + If you ever wanted to influence the labels in your GRUB menu, + this is the option for you. + + The default is <option>system.nixos.tags</option> separated by + "-" + "-" + <envar>NIXOS_LABEL_VERSION</envar> environment + variable (defaults to the value of + <option>system.nixos.version</option>). + + Can be overriden by setting <envar>NIXOS_LABEL</envar>. + + Useful for not loosing track of configurations built from different + nixos branches/revisions, e.g.: + + <screen> + #!/bin/sh + today=`date +%Y%m%d` + branch=`(cd nixpkgs ; git branch 2>/dev/null | sed -n '/^\* / { s|^\* ||; p; }')` + revision=`(cd nixpkgs ; git rev-parse HEAD)` + export NIXOS_LABEL_VERSION="$today.$branch-''${revision:0:7}" + nixos-rebuild switch</screen> + ''; + }; + + nixos.tags = mkOption { + type = types.listOf types.str; + default = []; + example = [ "with-xen" ]; + description = '' + Strings to prefix to the default + <option>system.nixos.label</option>. + + Useful for not loosing track of configurations built with + different options, e.g.: + + <screen> + { + system.nixos.tags = [ "with-xen" ]; + virtualisation.xen.enable = true; + } + </screen> + ''; + }; + + }; + + config = { + # This is set here rather than up there so that changing it would + # not rebuild the manual + system.nixos.label = mkDefault (maybeEnv "NIXOS_LABEL" + (concatStringsSep "-" (sort (x: y: x < y) cfg.tags) + + "-" + maybeEnv "NIXOS_LABEL_VERSION" cfg.version)); + }; + +} diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index 1793c1447d60..e747fbc6755c 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -3,11 +3,13 @@ with lib; let + cfg = config.nixpkgs; + isConfig = x: - builtins.isAttrs x || builtins.isFunction x; + builtins.isAttrs x || lib.isFunction x; optCall = f: x: - if builtins.isFunction f + if lib.isFunction f then f x else f; @@ -38,16 +40,55 @@ let overlayType = mkOptionType { name = "nixpkgs-overlay"; description = "nixpkgs overlay"; - check = builtins.isFunction; + check = lib.isFunction; merge = lib.mergeOneOption; }; - _pkgs = import ../../.. config.nixpkgs; + pkgsType = mkOptionType { + name = "nixpkgs"; + description = "An evaluation of Nixpkgs; the top level attribute set of packages"; + check = builtins.isAttrs; + }; in { options.nixpkgs = { + + pkgs = mkOption { + defaultText = literalExample + ''import "''${nixos}/.." { + inherit (config.nixpkgs) config overlays system; + } + ''; + default = import ../../.. { inherit (cfg) config overlays system; }; + type = pkgsType; + example = literalExample ''import <nixpkgs> {}''; + description = '' + This is the evaluation of Nixpkgs that will be provided to + all NixOS modules. Defining this option has the effect of + ignoring the other options that would otherwise be used to + evaluate Nixpkgs, because those are arguments to the default + value. The default value imports the Nixpkgs source files + relative to the location of this NixOS module, because + NixOS and Nixpkgs are distributed together for consistency, + so the <code>nixos</code> in the default value is in fact a + relative path. The <code>config</code>, <code>overlays</code> + and <code>system</code> come from this option's siblings. + + This option can be used by applications like NixOps to increase + the performance of evaluation, or to create packages that depend + on a container that should be built with the exact same evaluation + of Nixpkgs, for example. Applications like this should set + their default value using <code>lib.mkDefault</code>, so + user-provided configuration can override it without using + <code>lib</code>. + + Note that using a distinct version of Nixpkgs with NixOS may + be an unexpected source of problems. Use this option with care. + ''; + }; + config = mkOption { default = {}; example = literalExample @@ -59,6 +100,8 @@ in The configuration of the Nix Packages collection. (For details, see the Nixpkgs documentation.) It allows you to set package configuration options. + + Ignored when <code>nixpkgs.pkgs</code> is set. ''; }; @@ -69,7 +112,6 @@ in [ (self: super: { openssh = super.openssh.override { hpnSupport = true; - withKerberos = true; kerberos = self.libkrb5; }; }; @@ -83,6 +125,8 @@ in takes as an argument the <emphasis>original</emphasis> Nixpkgs. The first argument should be used for finding dependencies, and the second should be used for overriding recipes. + + Ignored when <code>nixpkgs.pkgs</code> is set. ''; }; @@ -94,14 +138,16 @@ in If unset, it defaults to the platform type of your host system. Specifying this option is useful when doing distributed multi-platform deployment, or when building virtual machines. + + Ignored when <code>nixpkgs.pkgs</code> is set. ''; }; }; config = { _module.args = { - pkgs = _pkgs; - pkgs_i686 = _pkgs.pkgsi686Linux; + pkgs = cfg.pkgs; + pkgs_i686 = cfg.pkgs.pkgsi686Linux; }; }; } diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix index 48cde2ebbc8a..6af584250a70 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -3,7 +3,7 @@ with lib; let - cfg = config.system; + cfg = config.system.nixos; releaseFile = "${toString pkgs.path}/.version"; suffixFile = "${toString pkgs.path}/.version-suffix"; @@ -16,51 +16,27 @@ in options.system = { - stateVersion = mkOption { - type = types.str; - default = cfg.nixosRelease; - description = '' - Every once in a while, a new NixOS release may change - configuration defaults in a way incompatible with stateful - data. For instance, if the default version of PostgreSQL - changes, the new version will probably be unable to read your - existing databases. To prevent such breakage, you can set the - value of this option to the NixOS release with which you want - to be compatible. The effect is that NixOS will option - defaults corresponding to the specified release (such as using - an older version of PostgreSQL). - ''; - }; - - nixosLabel = mkOption { - type = types.str; - description = '' - Label to be used in the names of generated outputs and boot - labels. - ''; - }; - - nixosVersion = mkOption { + nixos.version = mkOption { internal = true; type = types.str; description = "The full NixOS version (e.g. <literal>16.03.1160.f2d4ee1</literal>)."; }; - nixosRelease = mkOption { + nixos.release = mkOption { readOnly = true; type = types.str; default = fileContents releaseFile; description = "The NixOS release (e.g. <literal>16.03</literal>)."; }; - nixosVersionSuffix = mkOption { + nixos.versionSuffix = mkOption { internal = true; type = types.str; default = if pathExists suffixFile then fileContents suffixFile else "pre-git"; description = "The NixOS version suffix (e.g. <literal>1160.f2d4ee1</literal>)."; }; - nixosRevision = mkOption { + nixos.revision = mkOption { internal = true; type = types.str; default = if pathIsDirectory gitRepo then commitIdFromGitRepo gitRepo @@ -69,12 +45,28 @@ in description = "The Git revision from which this NixOS configuration was built."; }; - nixosCodeName = mkOption { + nixos.codeName = mkOption { readOnly = true; type = types.str; description = "The NixOS release code name (e.g. <literal>Emu</literal>)."; }; + stateVersion = mkOption { + type = types.str; + default = cfg.release; + description = '' + Every once in a while, a new NixOS release may change + configuration defaults in a way incompatible with stateful + data. For instance, if the default version of PostgreSQL + changes, the new version will probably be unable to read your + existing databases. To prevent such breakage, you can set the + value of this option to the NixOS release with which you want + to be compatible. The effect is that NixOS will option + defaults corresponding to the specified release (such as using + an older version of PostgreSQL). + ''; + }; + defaultChannel = mkOption { internal = true; type = types.str; @@ -86,16 +78,15 @@ in config = { - system = { + system.nixos = { # These defaults are set here rather than up there so that # changing them would not rebuild the manual - nixosLabel = mkDefault cfg.nixosVersion; - nixosVersion = mkDefault (cfg.nixosRelease + cfg.nixosVersionSuffix); - nixosRevision = mkIf (pathIsDirectory gitRepo) (mkDefault gitCommitId); - nixosVersionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId)); + version = mkDefault (cfg.release + cfg.versionSuffix); + revision = mkIf (pathIsDirectory gitRepo) (mkDefault gitCommitId); + versionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId)); # Note: code names must only increase in alphabetical order. - nixosCodeName = "Impala"; + codeName = "Impala"; }; # Generate /etc/os-release. See @@ -105,10 +96,10 @@ in '' NAME=NixOS ID=nixos - VERSION="${config.system.nixosVersion} (${config.system.nixosCodeName})" - VERSION_CODENAME=${toLower config.system.nixosCodeName} - VERSION_ID="${config.system.nixosVersion}" - PRETTY_NAME="NixOS ${config.system.nixosVersion} (${config.system.nixosCodeName})" + VERSION="${cfg.version} (${cfg.codeName})" + VERSION_CODENAME=${toLower cfg.codeName} + VERSION_ID="${cfg.version}" + PRETTY_NAME="NixOS ${cfg.version} (${cfg.codeName})" HOME_URL="https://nixos.org/" SUPPORT_URL="https://nixos.org/nixos/support.html" BUG_REPORT_URL="https://github.com/NixOS/nixpkgs/issues" diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 3b4f41171adc..fabe686ff4b4 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -60,6 +60,7 @@ ./misc/extra-arguments.nix ./misc/ids.nix ./misc/lib.nix + ./misc/label.nix ./misc/locate.nix ./misc/meta.nix ./misc/nixpkgs.nix @@ -71,9 +72,11 @@ ./programs/bcc.nix ./programs/blcr.nix ./programs/browserpass.nix + ./programs/ccache.nix ./programs/cdemu.nix ./programs/chromium.nix ./programs/command-not-found/command-not-found.nix + ./programs/criu.nix ./programs/dconf.nix ./programs/environment.nix ./programs/fish.nix @@ -83,6 +86,7 @@ ./programs/info.nix ./programs/java.nix ./programs/kbdlight.nix + ./programs/less.nix ./programs/light.nix ./programs/man.nix ./programs/mosh.nix @@ -90,7 +94,9 @@ ./programs/nano.nix ./programs/npm.nix ./programs/oblogout.nix + ./programs/plotinus.nix ./programs/qt5ct.nix + ./programs/rootston.nix ./programs/screen.nix ./programs/slock.nix ./programs/shadow.nix @@ -99,16 +105,20 @@ ./programs/ssh.nix ./programs/ssmtp.nix ./programs/sysdig.nix + ./programs/systemtap.nix ./programs/sway.nix ./programs/thefuck.nix ./programs/tmux.nix ./programs/venus.nix ./programs/vim.nix + ./programs/way-cooler.nix ./programs/wireshark.nix ./programs/xfs_quota.nix ./programs/xonsh.nix + ./programs/yabar.nix ./programs/zsh/oh-my-zsh.nix ./programs/zsh/zsh.nix + ./programs/zsh/zsh-autoenv.nix ./programs/zsh/zsh-syntax-highlighting.nix ./rename.nix ./security/acme.nix @@ -147,6 +157,7 @@ ./services/backup/almir.nix ./services/backup/bacula.nix ./services/backup/crashplan.nix + ./services/backup/crashplan-small-business.nix ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix ./services/backup/rsnapshot.nix @@ -196,7 +207,9 @@ ./services/desktops/dleyna-renderer.nix ./services/desktops/dleyna-server.nix ./services/desktops/geoclue2.nix + ./services/desktops/pipewire.nix ./services/desktops/gnome3/at-spi2-core.nix + ./services/desktops/gnome3/chrome-gnome-shell.nix ./services/desktops/gnome3/evolution-data-server.nix ./services/desktops/gnome3/gnome-disks.nix ./services/desktops/gnome3/gnome-documents.nix @@ -210,19 +223,18 @@ ./services/desktops/gnome3/seahorse.nix ./services/desktops/gnome3/sushi.nix ./services/desktops/gnome3/tracker.nix + ./services/desktops/gnome3/tracker-miners.nix ./services/desktops/profile-sync-daemon.nix ./services/desktops/telepathy.nix ./services/development/hoogle.nix ./services/editors/emacs.nix ./services/editors/infinoted.nix ./services/games/factorio.nix - ./services/games/ghost-one.nix ./services/games/minecraft-server.nix ./services/games/minetest-server.nix ./services/games/terraria.nix ./services/hardware/acpid.nix ./services/hardware/actkbd.nix - ./services/hardware/amd-hybrid-graphics.nix ./services/hardware/bluetooth.nix ./services/hardware/brltty.nix ./services/hardware/freefall.nix @@ -238,9 +250,11 @@ ./services/hardware/tlp.nix ./services/hardware/thinkfan.nix ./services/hardware/trezord.nix + ./services/hardware/u2f.nix ./services/hardware/udev.nix ./services/hardware/udisks2.nix ./services/hardware/upower.nix + ./services/hardware/usbmuxd.nix ./services/hardware/thermald.nix ./services/logging/SystemdJournal2Gelf.nix ./services/logging/awstats.nix @@ -256,6 +270,8 @@ ./services/logging/rsyslogd.nix ./services/logging/syslog-ng.nix ./services/logging/syslogd.nix + ./services/mail/clamsmtp.nix + ./services/mail/dkimproxy-out.nix ./services/mail/dovecot.nix ./services/mail/dspam.nix ./services/mail/exim.nix @@ -307,6 +323,7 @@ ./services/misc/gogs.nix ./services/misc/gollum.nix ./services/misc/gpsd.nix + ./services/misc/home-assistant.nix ./services/misc/ihaskell.nix ./services/misc/irkerd.nix ./services/misc/jackett.nix @@ -327,6 +344,7 @@ ./services/misc/nix-ssh-serve.nix ./services/misc/nzbget.nix ./services/misc/octoprint.nix + ./services/misc/osrm.nix ./services/misc/packagekit.nix ./services/misc/parsoid.nix ./services/misc/phd.nix @@ -351,6 +369,7 @@ ./services/misc/taskserver ./services/misc/tzupdate.nix ./services/misc/uhub.nix + ./services/misc/xmr-stak.nix ./services/misc/zookeeper.nix ./services/monitoring/apcupsd.nix ./services/monitoring/arbtt.nix @@ -397,14 +416,17 @@ ./services/monitoring/vnstat.nix ./services/monitoring/zabbix-agent.nix ./services/monitoring/zabbix-server.nix + ./services/network-filesystems/beegfs.nix ./services/network-filesystems/cachefilesd.nix + ./services/network-filesystems/davfs2.nix ./services/network-filesystems/drbd.nix ./services/network-filesystems/glusterfs.nix ./services/network-filesystems/kbfs.nix ./services/network-filesystems/ipfs.nix ./services/network-filesystems/netatalk.nix ./services/network-filesystems/nfsd.nix - ./services/network-filesystems/openafs-client/default.nix + ./services/network-filesystems/openafs/client.nix + ./services/network-filesystems/openafs/server.nix ./services/network-filesystems/rsyncd.nix ./services/network-filesystems/samba.nix ./services/network-filesystems/tahoe.nix @@ -413,6 +435,7 @@ ./services/network-filesystems/yandex-disk.nix ./services/network-filesystems/xtreemfs.nix ./services/networking/amuled.nix + ./services/networking/aria2.nix ./services/networking/asterisk.nix ./services/networking/atftpd.nix ./services/networking/avahi-daemon.nix @@ -477,6 +500,7 @@ ./services/networking/minidlna.nix ./services/networking/miniupnpd.nix ./services/networking/mosquitto.nix + ./services/networking/monero.nix ./services/networking/miredo.nix ./services/networking/mstpd.nix ./services/networking/murmur.nix @@ -487,6 +511,7 @@ ./services/networking/ngircd.nix ./services/networking/nghttpx/default.nix ./services/networking/nix-serve.nix + ./services/networking/nixops-dns.nix ./services/networking/nntp-proxy.nix ./services/networking/nsd.nix ./services/networking/ntopng.nix @@ -514,6 +539,7 @@ ./services/networking/redsocks.nix ./services/networking/resilio.nix ./services/networking/rpcbind.nix + ./services/networking/rxe.nix ./services/networking/sabnzbd.nix ./services/networking/searx.nix ./services/networking/seeks.nix @@ -529,6 +555,7 @@ ./services/networking/ssh/lshd.nix ./services/networking/ssh/sshd.nix ./services/networking/strongswan.nix + ./services/networking/stunnel.nix ./services/networking/supplicant.nix ./services/networking/supybot.nix ./services/networking/syncthing.nix @@ -587,6 +614,7 @@ ./services/system/cloud-init.nix ./services/system/dbus.nix ./services/system/earlyoom.nix + ./services/system/localtime.nix ./services/system/kerberos.nix ./services/system/nscd.nix ./services/system/saslauthd.nix @@ -622,6 +650,7 @@ ./services/web-servers/lighttpd/default.nix ./services/web-servers/lighttpd/gitweb.nix ./services/web-servers/lighttpd/inginious.nix + ./services/web-servers/mighttpd2.nix ./services/web-servers/minio.nix ./services/web-servers/nginx/default.nix ./services/web-servers/phpfpm/default.nix @@ -668,8 +697,10 @@ ./services/x11/xserver.nix ./system/activation/activation-script.nix ./system/activation/top-level.nix + ./system/boot/binfmt.nix ./system/boot/coredump.nix ./system/boot/emergency-mode.nix + ./system/boot/grow-partition.nix ./system/boot/initrd-network.nix ./system/boot/initrd-ssh.nix ./system/boot/kernel.nix @@ -736,6 +767,7 @@ ./virtualisation/lxcfs.nix ./virtualisation/lxd.nix ./virtualisation/amazon-options.nix + ./virtualisation/hyperv-guest.nix ./virtualisation/openvswitch.nix ./virtualisation/parallels-guest.nix ./virtualisation/rkt.nix @@ -744,6 +776,4 @@ ./virtualisation/vmware-guest.nix ./virtualisation/xen-dom0.nix ./virtualisation/xe-guest-utilities.nix - ./virtualisation/openstack/keystone.nix - ./virtualisation/openstack/glance.nix ] diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix index 3c7e516c497f..f56640f19782 100644 --- a/nixos/modules/profiles/all-hardware.nix +++ b/nixos/modules/profiles/all-hardware.nix @@ -19,13 +19,12 @@ "sata_sil" "sata_sil24" "sata_sis" "sata_svw" "sata_sx4" "sata_uli" "sata_via" "sata_vsc" - "pata_ali" "pata_amd" "pata_artop" "pata_atiixp" - "pata_cs5520" "pata_cs5530" "pata_cs5535" "pata_efar" + "pata_ali" "pata_amd" "pata_artop" "pata_atiixp" "pata_efar" "pata_hpt366" "pata_hpt37x" "pata_hpt3x2n" "pata_hpt3x3" "pata_it8213" "pata_it821x" "pata_jmicron" "pata_marvell" "pata_mpiix" "pata_netcell" "pata_ns87410" "pata_oldpiix" "pata_pcmcia" "pata_pdc2027x" "pata_qdi" "pata_rz1000" - "pata_sc1200" "pata_serverworks" "pata_sil680" "pata_sis" + "pata_serverworks" "pata_sil680" "pata_sis" "pata_sl82c105" "pata_triflex" "pata_via" "pata_winbond" diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix index 77d86f8d7405..5b4e68beb6a6 100644 --- a/nixos/modules/profiles/clone-config.nix +++ b/nixos/modules/profiles/clone-config.nix @@ -17,7 +17,7 @@ let # you should use files). moduleFiles = # FIXME: use typeOf (Nix 1.6.1). - filter (x: !isAttrs x && !builtins.isFunction x) modules; + filter (x: !isAttrs x && !lib.isFunction x) modules; # Partition module files because between NixOS and non-NixOS files. NixOS # files may change if the repository is updated. diff --git a/nixos/modules/profiles/qemu-guest.nix b/nixos/modules/profiles/qemu-guest.nix index 987eb051b98c..a1ec1d45395e 100644 --- a/nixos/modules/profiles/qemu-guest.nix +++ b/nixos/modules/profiles/qemu-guest.nix @@ -4,7 +4,7 @@ { config, pkgs, ... }: { - boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ]; + boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ]; boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" ]; boot.initrd.postDeviceCommands = diff --git a/nixos/modules/programs/adb.nix b/nixos/modules/programs/adb.nix index 18290555b79d..f648d70bd9fa 100644 --- a/nixos/modules/programs/adb.nix +++ b/nixos/modules/programs/adb.nix @@ -16,6 +16,7 @@ with lib; To grant access to a user, it must be part of adbusers group: <code>users.extraUsers.alice.extraGroups = ["adbusers"];</code> ''; + relatedPackages = [ ["androidenv" "platformTools"] ]; }; }; }; diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix index ef1acdfe66e6..1abdb4973a44 100644 --- a/nixos/modules/programs/bash/bash.nix +++ b/nixos/modules/programs/bash/bash.nix @@ -14,13 +14,16 @@ let bashCompletion = optionalString cfg.enableCompletion '' # Check whether we're running a version of Bash that has support for # programmable completion. If we do, enable all modules installed in - # the system (and user profile). + # the system and user profile in obsolete /etc/bash_completion.d/ + # directories. Bash loads completions in all + # $XDG_DATA_DIRS/share/bash-completion/completions/ + # on demand, so they do not need to be sourced here. if shopt -q progcomp &>/dev/null; then . "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh" nullglobStatus=$(shopt -p nullglob) shopt -s nullglob for p in $NIX_PROFILES; do - for m in "$p/etc/bash_completion.d/"* "$p/share/bash-completion/completions/"*; do + for m in "$p/etc/bash_completion.d/"*; do . $m done done diff --git a/nixos/modules/programs/ccache.nix b/nixos/modules/programs/ccache.nix new file mode 100644 index 000000000000..874774c72b47 --- /dev/null +++ b/nixos/modules/programs/ccache.nix @@ -0,0 +1,83 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.programs.ccache; +in { + options.programs.ccache = { + # host configuration + enable = mkEnableOption "CCache"; + cacheDir = mkOption { + type = types.path; + description = "CCache directory"; + default = "/var/cache/ccache"; + }; + # target configuration + packageNames = mkOption { + type = types.listOf types.str; + description = "Nix top-level packages to be compiled using CCache"; + default = []; + example = [ "wxGTK30" "qt48" "ffmpeg_3_3" "libav_all" ]; + }; + }; + + config = mkMerge [ + # host configuration + (mkIf cfg.enable { + systemd.tmpfiles.rules = [ "d ${cfg.cacheDir} 0770 root nixbld -" ]; + + # "nix-ccache --show-stats" and "nix-ccache --clear" + security.wrappers.nix-ccache = { + group = "nixbld"; + setgid = true; + source = pkgs.writeScript "nix-ccache.pl" '' + #!${pkgs.perl}/bin/perl + + %ENV=( CCACHE_DIR => '${cfg.cacheDir}' ); + sub untaint { + my $v = shift; + return '-C' if $v eq '-C' || $v eq '--clear'; + return '-V' if $v eq '-V' || $v eq '--version'; + return '-s' if $v eq '-s' || $v eq '--show-stats'; + return '-z' if $v eq '-z' || $v eq '--zero-stats'; + exec('${pkgs.ccache}/bin/ccache', '-h'); + } + exec('${pkgs.ccache}/bin/ccache', map { untaint $_ } @ARGV); + ''; + }; + }) + + # target configuration + (mkIf (cfg.packageNames != []) { + nixpkgs.overlays = [ + (self: super: genAttrs cfg.packageNames (pn: super.${pn}.override { stdenv = builtins.trace "with ccache: ${pn}" self.ccacheStdenv; })) + + (self: super: { + ccacheWrapper = super.ccacheWrapper.override { + extraConfig = '' + export CCACHE_COMPRESS=1 + export CCACHE_DIR="${cfg.cacheDir}" + export CCACHE_UMASK=007 + if [ ! -d "$CCACHE_DIR" ]; then + echo "=====" + echo "Directory '$CCACHE_DIR' does not exist" + echo "Please create it with:" + echo " sudo mkdir -m0770 '$CCACHE_DIR'" + echo " sudo chown root:nixbld '$CCACHE_DIR'" + echo "=====" + exit 1 + fi + if [ ! -w "$CCACHE_DIR" ]; then + echo "=====" + echo "Directory '$CCACHE_DIR' is not accessible for user $(whoami)" + echo "Please verify its access permissions" + echo "=====" + exit 1 + fi + ''; + }; + }) + ]; + }) + ]; +} \ No newline at end of file diff --git a/nixos/modules/programs/criu.nix b/nixos/modules/programs/criu.nix new file mode 100644 index 000000000000..48cf5c88a9fc --- /dev/null +++ b/nixos/modules/programs/criu.nix @@ -0,0 +1,26 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.programs.criu; +in { + + options = { + programs.criu = { + enable = mkOption { + default = false; + description = '' + Install <command>criu</command> along with necessary kernel options. + ''; + }; + }; + }; + config = mkIf cfg.enable { + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isYes "CHECKPOINT_RESTORE") + ]; + boot.kernel.features.criu = true; + environment.systemPackages = [ pkgs.criu ]; + }; + +} diff --git a/nixos/modules/programs/dconf.nix b/nixos/modules/programs/dconf.nix index 1b7e20799819..27bfdf022e7d 100644 --- a/nixos/modules/programs/dconf.nix +++ b/nixos/modules/programs/dconf.nix @@ -1,7 +1,8 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: + +with lib; let - inherit (lib) mkOption mkIf types mapAttrsToList; cfg = config.programs.dconf; mkDconfProfile = name: path: @@ -13,6 +14,7 @@ in options = { programs.dconf = { + enable = mkEnableOption "dconf"; profiles = mkOption { type = types.attrsOf types.path; @@ -26,9 +28,15 @@ in ###### implementation - config = mkIf (cfg.profiles != {}) { - environment.etc = + config = mkIf (cfg.profiles != {} || cfg.enable) { + environment.etc = optionals (cfg.profiles != {}) (mapAttrsToList mkDconfProfile cfg.profiles); + + environment.variables.GIO_EXTRA_MODULES = optional cfg.enable + "${pkgs.gnome3.dconf.lib}/lib/gio/modules"; + # https://github.com/NixOS/nixpkgs/pull/31891 + #environment.variables.XDG_DATA_DIRS = optional cfg.enable + # "$(echo ${pkgs.gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas-*)"; }; } diff --git a/nixos/modules/programs/less.nix b/nixos/modules/programs/less.nix new file mode 100644 index 000000000000..c0283c9e6862 --- /dev/null +++ b/nixos/modules/programs/less.nix @@ -0,0 +1,118 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.less; + + configFile = '' + #command + ${concatStringsSep "\n" + (mapAttrsToList (command: action: "${command} ${action}") cfg.commands) + } + ${if cfg.clearDefaultCommands then "#stop" else ""} + + #line-edit + ${concatStringsSep "\n" + (mapAttrsToList (command: action: "${command} ${action}") cfg.lineEditingKeys) + } + + #env + ${concatStringsSep "\n" + (mapAttrsToList (variable: values: "${variable}=${values}") cfg.envVariables) + } + ''; + + lessKey = pkgs.runCommand "lesskey" + { src = pkgs.writeText "lessconfig" configFile; } + "${pkgs.less}/bin/lesskey -o $out $src"; + +in + +{ + options = { + + programs.less = { + + enable = mkEnableOption "less"; + + commands = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { + "h" = "noaction 5\e("; + "l" = "noaction 5\e)"; + }; + description = "Defines new command keys."; + }; + + clearDefaultCommands = mkOption { + type = types.bool; + default = false; + description = '' + Clear all default commands. + You should remember to set the quit key. + Otherwise you will not be able to leave less without killing it. + ''; + }; + + lineEditingKeys = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { + "\e" = "abort"; + }; + description = "Defines new line-editing keys."; + }; + + envVariables = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { + LESS = "--quit-if-one-screen"; + }; + description = "Defines environment variables."; + }; + + lessopen = mkOption { + type = types.nullOr types.str; + default = "|${pkgs.lesspipe}/bin/lesspipe.sh %s"; + description = '' + Before less opens a file, it first gives your input preprocessor a chance to modify the way the contents of the file are displayed. + ''; + }; + + lessclose = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + When less closes a file opened in such a way, it will call another program, called the input postprocessor, which may perform any desired clean-up action (such as deleting the replacement file created by LESSOPEN). + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.less ]; + + environment.variables = { + "LESSKEY_SYSTEM" = toString lessKey; + } // optionalAttrs (cfg.lessopen != null) { + "LESSOPEN" = cfg.lessopen; + } // optionalAttrs (cfg.lessclose != null) { + "LESSCLOSE" = cfg.lessclose; + }; + + warnings = optional ( + cfg.clearDefaultCommands && (all (x: x != "quit") (attrValues cfg.commands)) + ) '' + config.programs.less.clearDefaultCommands clears all default commands of less but there is no alternative binding for exiting. + Consider adding a binding for 'quit'. + ''; + }; + + meta.maintainers = with maintainers; [ johnazoidberg ]; + +} diff --git a/nixos/modules/programs/plotinus.nix b/nixos/modules/programs/plotinus.nix new file mode 100644 index 000000000000..065e72d6c374 --- /dev/null +++ b/nixos/modules/programs/plotinus.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.plotinus; +in +{ + meta = { + maintainers = pkgs.plotinus.meta.maintainers; + doc = ./plotinus.xml; + }; + + ###### interface + + options = { + programs.plotinus = { + enable = mkOption { + default = false; + description = '' + Whether to enable the Plotinus GTK+3 plugin. Plotinus provides a + popup (triggered by Ctrl-Shift-P) to search the menus of a + compatible application. + ''; + type = types.bool; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + environment.variables.XDG_DATA_DIRS = [ "${pkgs.plotinus}/share/gsettings-schemas/${pkgs.plotinus.name}" ]; + environment.variables.GTK3_MODULES = [ "${pkgs.plotinus}/lib/libplotinus.so" ]; + }; +} diff --git a/nixos/modules/programs/plotinus.xml b/nixos/modules/programs/plotinus.xml new file mode 100644 index 000000000000..85b0e023e6c1 --- /dev/null +++ b/nixos/modules/programs/plotinus.xml @@ -0,0 +1,25 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-program-plotinus"> + +<title>Plotinus</title> + +<para><emphasis>Source:</emphasis> <filename>modules/programs/plotinus.nix</filename></para> + +<para><emphasis>Upstream documentation:</emphasis> <link xlink:href="https://github.com/p-e-w/plotinus"/></para> + +<para>Plotinus is a searchable command palette in every modern GTK+ application.</para> + +<para>When in a GTK+3 application and Plotinus is enabled, you can press <literal>Ctrl+Shift+P</literal> to open the command palette. The command palette provides a searchable list of of all menu items in the application.</para> + +<para>To enable Plotinus, add the following to your <filename>configuration.nix</filename>: + +<programlisting> +programs.plotinus.enable = true; +</programlisting> + +</para> + +</chapter> diff --git a/nixos/modules/programs/rootston.nix b/nixos/modules/programs/rootston.nix new file mode 100644 index 000000000000..1946b1db657b --- /dev/null +++ b/nixos/modules/programs/rootston.nix @@ -0,0 +1,103 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.rootston; + + rootstonWrapped = pkgs.writeScriptBin "rootston" '' + #! ${pkgs.stdenv.shell} + if [[ "$#" -ge 1 ]]; then + exec ${pkgs.rootston}/bin/rootston "$@" + else + ${cfg.extraSessionCommands} + exec ${pkgs.rootston}/bin/rootston -C ${cfg.configFile} + fi + ''; +in { + options.programs.rootston = { + enable = mkEnableOption '' + rootston, the reference compositor for wlroots. The purpose of rootston + is to test and demonstrate the features of wlroots (if you want a real + Wayland compositor you should e.g. use Sway instead). You can manually + start the compositor by running "rootston" from a terminal''; + + extraSessionCommands = mkOption { + type = types.lines; + default = ""; + example = '' + # Define a keymap (US QWERTY is the default) + export XKB_DEFAULT_LAYOUT=de,us + export XKB_DEFAULT_VARIANT=nodeadkeys + export XKB_DEFAULT_OPTIONS=grp:alt_shift_toggle,caps:escape + ''; + description = '' + Shell commands executed just before rootston is started. + ''; + }; + + extraPackages = mkOption { + type = with types; listOf package; + default = with pkgs; [ + westonLite xwayland rofi + ]; + defaultText = literalExample '' + with pkgs; [ + westonLite xwayland rofi + ] + ''; + example = literalExample "[ ]"; + description = '' + Extra packages to be installed system wide. + ''; + }; + + config = mkOption { + type = types.str; + default = '' + [keyboard] + meta-key = Logo + + # Sway/i3 like Keybindings + # Maps key combinations with commands to execute + # Commands include: + # - "exit" to stop the compositor + # - "exec" to execute a shell command + # - "close" to close the current view + # - "next_window" to cycle through windows + [bindings] + Logo+Shift+e = exit + Logo+q = close + Logo+m = maximize + Alt+Tab = next_window + Logo+Return = exec weston-terminal + Logo+d = exec rofi -show run + ''; + description = '' + Default configuration for rootston (used when called without any + parameters). + ''; + }; + + configFile = mkOption { + type = types.path; + default = "/etc/rootston.ini"; + example = literalExample "${pkgs.rootston}/etc/rootston.ini"; + description = '' + Path to the default rootston configuration file (the "config" option + will have no effect if you change the path). + ''; + }; + }; + + config = mkIf cfg.enable { + environment.etc."rootston.ini".text = cfg.config; + environment.systemPackages = [ rootstonWrapped ] ++ cfg.extraPackages; + + hardware.opengl.enable = mkDefault true; + fonts.enableDefaultFonts = mkDefault true; + programs.dconf.enable = mkDefault true; + }; + + meta.maintainers = with lib.maintainers; [ primeos gnidorah ]; +} diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index 0f3f42901bab..8ec4169207db 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -26,8 +26,9 @@ let # Ensure privacy for newly created home directories. UMASK 077 - # Uncomment this to allow non-root users to change their account - #information. This should be made configurable. + # Uncomment this and install chfn SUID to allow non-root + # users to change their account GECOS information. + # This should be made configurable. #CHFN_RESTRICT frwh ''; @@ -103,13 +104,12 @@ in security.wrappers = { su.source = "${pkgs.shadow.su}/bin/su"; - chfn.source = "${pkgs.shadow.out}/bin/chfn"; + sg.source = "${pkgs.shadow.out}/bin/sg"; + newgrp.source = "${pkgs.shadow.out}/bin/newgrp"; newuidmap.source = "${pkgs.shadow.out}/bin/newuidmap"; newgidmap.source = "${pkgs.shadow.out}/bin/newgidmap"; } // (if config.users.mutableUsers then { passwd.source = "${pkgs.shadow.out}/bin/passwd"; - sg.source = "${pkgs.shadow.out}/bin/sg"; - newgrp.source = "${pkgs.shadow.out}/bin/newgrp"; } else {}); }; } diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix index 5d13b90daace..d9503d6004ff 100644 --- a/nixos/modules/programs/sway.nix +++ b/nixos/modules/programs/sway.nix @@ -4,36 +4,42 @@ with lib; let cfg = config.programs.sway; - sway = pkgs.sway; + swayPackage = pkgs.sway; - swayWrapped = pkgs.writeScriptBin "sway" '' - #! ${pkgs.stdenv.shell} - if [ "$1" != "" ]; then - sway-setcap "$@" - exit + swayWrapped = pkgs.writeShellScriptBin "sway" '' + if [[ "$#" -ge 1 ]]; then + exec sway-setcap "$@" + else + ${cfg.extraSessionCommands} + exec ${pkgs.dbus.dbus-launch} --exit-with-session sway-setcap fi - ${cfg.extraSessionCommands} - exec ${pkgs.dbus.dbus-launch} --exit-with-session sway-setcap ''; swayJoined = pkgs.symlinkJoin { - name = "sway-wrapped"; - paths = [ swayWrapped sway ]; + name = "sway-joined"; + paths = [ swayWrapped swayPackage ]; }; -in -{ +in { options.programs.sway = { - enable = mkEnableOption "sway"; + enable = mkEnableOption '' + the tiling Wayland compositor Sway. After adding yourself to the "sway" + group you can manually launch Sway by executing "sway" from a terminal. + If you call "sway" with any parameters the extraSessionCommands won't be + executed and Sway won't be launched with dbus-launch''; extraSessionCommands = mkOption { - default = ""; - type = types.lines; + type = types.lines; + default = ""; example = '' - export XKB_DEFAULT_LAYOUT=us,de - export XKB_DEFAULT_VARIANT=,nodeadkeys - export XKB_DEFAULT_OPTIONS=grp:alt_shift_toggle, + # Define a keymap (US QWERTY is the default) + export XKB_DEFAULT_LAYOUT=de,us + export XKB_DEFAULT_VARIANT=nodeadkeys + export XKB_DEFAULT_OPTIONS=grp:alt_shift_toggle,caps:escape + # Change the Keyboard repeat delay and rate + export WLC_REPEAT_DELAY=660 + export WLC_REPEAT_RATE=25 ''; description = '' - Shell commands executed just before sway is started. + Shell commands executed just before Sway is started. ''; }; @@ -42,9 +48,12 @@ in default = with pkgs; [ i3status xwayland rxvt_unicode dmenu ]; + defaultText = literalExample '' + with pkgs; [ i3status xwayland rxvt_unicode dmenu ]; + ''; example = literalExample '' with pkgs; [ - i3status xwayland rxvt_unicode dmenu + i3lock light termite ] ''; description = '' @@ -57,7 +66,7 @@ in environment.systemPackages = [ swayJoined ] ++ cfg.extraPackages; security.wrappers.sway = { program = "sway-setcap"; - source = "${sway}/bin/sway"; + source = "${swayPackage}/bin/sway"; capabilities = "cap_sys_ptrace,cap_sys_tty_config=eip"; owner = "root"; group = "sway"; @@ -65,8 +74,12 @@ in }; users.extraGroups.sway = {}; + security.pam.services.swaylock = {}; hardware.opengl.enable = mkDefault true; fonts.enableDefaultFonts = mkDefault true; + programs.dconf.enable = mkDefault true; }; + + meta.maintainers = with lib.maintainers; [ gnidorah primeos ]; } diff --git a/nixos/modules/programs/systemtap.nix b/nixos/modules/programs/systemtap.nix new file mode 100644 index 000000000000..fd84732cd412 --- /dev/null +++ b/nixos/modules/programs/systemtap.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.programs.systemtap; +in { + + options = { + programs.systemtap = { + enable = mkOption { + default = false; + description = '' + Install <command>systemtap</command> along with necessary kernel options. + ''; + }; + }; + }; + config = mkIf cfg.enable { + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isYes "DEBUG") + ]; + boot.kernel.features.debug = true; + environment.systemPackages = [ + config.boot.kernelPackages.systemtap + ]; + }; + +} diff --git a/nixos/modules/programs/tmux.nix b/nixos/modules/programs/tmux.nix index ed1d88a420a2..4a60403a2827 100644 --- a/nixos/modules/programs/tmux.nix +++ b/nixos/modules/programs/tmux.nix @@ -61,7 +61,12 @@ in { options = { programs.tmux = { - enable = mkEnableOption "<command>tmux</command> - a <command>screen</command> replacement."; + enable = mkOption { + type = types.bool; + default = false; + description = "Whenever to configure <command>tmux</command> system-wide."; + relatedPackages = [ "tmux" ]; + }; aggressiveResize = mkOption { default = false; @@ -151,6 +156,15 @@ in { type = types.str; description = "Set the $TERM variable."; }; + + secureSocket = mkOption { + default = true; + type = types.bool; + description = '' + Store tmux socket under /run, which is more secure than /tmp, but as a + downside it doesn't survive user logout. + ''; + }; }; }; @@ -163,7 +177,7 @@ in { systemPackages = [ pkgs.tmux ]; variables = { - TMUX_TMPDIR = ''''${XDG_RUNTIME_DIR:-"/run/user/\$(id -u)"}''; + TMUX_TMPDIR = lib.optional cfg.secureSocket ''''${XDG_RUNTIME_DIR:-"/run/user/\$(id -u)"}''; }; }; }; diff --git a/nixos/modules/programs/way-cooler.nix b/nixos/modules/programs/way-cooler.nix new file mode 100644 index 000000000000..633e959be9f3 --- /dev/null +++ b/nixos/modules/programs/way-cooler.nix @@ -0,0 +1,78 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.way-cooler; + way-cooler = pkgs.way-cooler; + + wcWrapped = pkgs.writeShellScriptBin "way-cooler" '' + ${cfg.extraSessionCommands} + exec ${pkgs.dbus.dbus-launch} --exit-with-session ${way-cooler}/bin/way-cooler + ''; + wcJoined = pkgs.symlinkJoin { + name = "way-cooler-wrapped"; + paths = [ wcWrapped way-cooler ]; + }; + configFile = readFile "${way-cooler}/etc/way-cooler/init.lua"; + spawnBar = '' + util.program.spawn_at_startup("lemonbar"); + ''; +in +{ + options.programs.way-cooler = { + enable = mkEnableOption "way-cooler"; + + extraSessionCommands = mkOption { + default = ""; + type = types.lines; + example = '' + export XKB_DEFAULT_LAYOUT=us,de + export XKB_DEFAULT_VARIANT=,nodeadkeys + export XKB_DEFAULT_OPTIONS=grp:caps_toggle, + ''; + description = '' + Shell commands executed just before way-cooler is started. + ''; + }; + + extraPackages = mkOption { + type = with types; listOf package; + default = with pkgs; [ + westonLite xwayland dmenu + ]; + example = literalExample '' + with pkgs; [ + westonLite xwayland dmenu + ] + ''; + description = '' + Extra packages to be installed system wide. + ''; + }; + + enableBar = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable an unofficial bar. + ''; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ wcJoined ] ++ cfg.extraPackages; + + security.pam.services.wc-lock = {}; + environment.etc."way-cooler/init.lua".text = '' + ${configFile} + ${optionalString cfg.enableBar spawnBar} + ''; + + hardware.opengl.enable = mkDefault true; + fonts.enableDefaultFonts = mkDefault true; + programs.dconf.enable = mkDefault true; + }; + + meta.maintainers = with maintainers; [ gnidorah ]; +} diff --git a/nixos/modules/programs/yabar.nix b/nixos/modules/programs/yabar.nix new file mode 100644 index 000000000000..a01083c3ace9 --- /dev/null +++ b/nixos/modules/programs/yabar.nix @@ -0,0 +1,149 @@ +{ lib, pkgs, config, ... }: + +with lib; + +let + cfg = config.programs.yabar; + + mapExtra = v: lib.concatStringsSep "\n" (mapAttrsToList ( + key: val: "${key} = ${if (isString val) then "\"${val}\"" else "${builtins.toString val}"};" + ) v); + + listKeys = r: concatStringsSep "," (map (n: "\"${n}\"") (attrNames r)); + + configFile = let + bars = mapAttrsToList ( + name: cfg: '' + ${name}: { + font: "${cfg.font}"; + position: "${cfg.position}"; + + ${mapExtra cfg.extra} + + block-list: [${listKeys cfg.indicators}] + + ${concatStringsSep "\n" (mapAttrsToList ( + name: cfg: '' + ${name}: { + exec: "${cfg.exec}"; + align: "${cfg.align}"; + ${mapExtra cfg.extra} + }; + '' + ) cfg.indicators)} + }; + '' + ) cfg.bars; + in pkgs.writeText "yabar.conf" '' + bar-list = [${listKeys cfg.bars}]; + ${concatStringsSep "\n" bars} + ''; +in + { + options.programs.yabar = { + enable = mkEnableOption "yabar"; + + package = mkOption { + default = pkgs.yabar; + example = literalExample "pkgs.yabar-unstable"; + type = types.package; + + description = '' + The package which contains the `yabar` binary. + + Nixpkgs provides the `yabar` and `yabar-unstable` + derivations since 18.03, so it's possible to choose. + ''; + }; + + bars = mkOption { + default = {}; + type = types.attrsOf(types.submodule { + options = { + font = mkOption { + default = "sans bold 9"; + example = "Droid Sans, FontAwesome Bold 9"; + type = types.string; + + description = '' + The font that will be used to draw the status bar. + ''; + }; + + position = mkOption { + default = "top"; + example = "bottom"; + type = types.enum [ "top" "bottom" ]; + + description = '' + The position where the bar will be rendered. + ''; + }; + + extra = mkOption { + default = {}; + type = types.attrsOf types.string; + + description = '' + An attribute set which contains further attributes of a bar. + ''; + }; + + indicators = mkOption { + default = {}; + type = types.attrsOf(types.submodule { + options.exec = mkOption { + example = "YABAR_DATE"; + type = types.string; + description = '' + The type of the indicator to be executed. + ''; + }; + + options.align = mkOption { + default = "left"; + example = "right"; + type = types.enum [ "left" "center" "right" ]; + + description = '' + Whether to align the indicator at the left or right of the bar. + ''; + }; + + options.extra = mkOption { + default = {}; + type = types.attrsOf (types.either types.string types.int); + + description = '' + An attribute set which contains further attributes of a indicator. + ''; + }; + }); + + description = '' + Indicators that should be rendered by yabar. + ''; + }; + }; + }); + + description = '' + List of bars that should be rendered by yabar. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.yabar = { + description = "yabar service"; + wantedBy = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + + script = '' + ${cfg.package}/bin/yabar -c ${configFile} + ''; + + serviceConfig.Restart = "always"; + }; + }; + } diff --git a/nixos/modules/programs/zsh/oh-my-zsh.nix b/nixos/modules/programs/zsh/oh-my-zsh.nix index 9077643c4440..b995d390b279 100644 --- a/nixos/modules/programs/zsh/oh-my-zsh.nix +++ b/nixos/modules/programs/zsh/oh-my-zsh.nix @@ -48,6 +48,15 @@ in Name of the theme to be used by oh-my-zsh. ''; }; + + cacheDir = mkOption { + default = "$HOME/.cache/oh-my-zsh"; + type = types.str; + description = '' + Cache directory to be used by `oh-my-zsh`. + Without this option it would default to the read-only nix store. + ''; + }; }; }; @@ -74,6 +83,13 @@ in "ZSH_THEME=\"${cfg.theme}\"" } + ${optionalString (cfg.cacheDir != null) '' + if [[ ! -d "${cfg.cacheDir}" ]]; then + mkdir -p "${cfg.cacheDir}" + fi + ZSH_CACHE_DIR=${cfg.cacheDir} + ''} + source $ZSH/oh-my-zsh.sh ''; }; diff --git a/nixos/modules/programs/zsh/zsh-autoenv.nix b/nixos/modules/programs/zsh/zsh-autoenv.nix new file mode 100644 index 000000000000..630114bcda9f --- /dev/null +++ b/nixos/modules/programs/zsh/zsh-autoenv.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.zsh.zsh-autoenv; +in { + options = { + programs.zsh.zsh-autoenv = { + enable = mkEnableOption "zsh-autoenv"; + package = mkOption { + default = pkgs.zsh-autoenv; + defaultText = "pkgs.zsh-autoenv"; + description = '' + Package to install for `zsh-autoenv` usage. + ''; + + type = types.package; + }; + }; + }; + + config = mkIf cfg.enable { + programs.zsh.interactiveShellInit = '' + source ${cfg.package}/share/zsh-autoenv/autoenv.zsh + ''; + }; +} diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix index 6fb1346bbb33..5102bfef0325 100644 --- a/nixos/modules/programs/zsh/zsh.nix +++ b/nixos/modules/programs/zsh/zsh.nix @@ -36,8 +36,9 @@ in shellAliases = mkOption { default = config.environment.shellAliases; description = '' - Set of aliases for zsh shell. See <option>environment.shellAliases</option> - for an option format description. + Set of aliases for zsh shell. Overrides the default value taken from + <option>environment.shellAliases</option>. + See <option>environment.shellAliases</option> for an option format description. ''; type = types.attrs; # types.attrsOf types.stringOrPath; }; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index f30cbe427f09..da83baed3719 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -48,6 +48,10 @@ with lib; (mkRemovedOptionModule [ "services" "rmilter" "bindInetSockets" ] "Use services.rmilter.bindSocket.* instead") (mkRemovedOptionModule [ "services" "rmilter" "bindUnixSockets" ] "Use services.rmilter.bindSocket.* instead") + # Xsession script + (mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logsXsession" ] [ "services" "xserver" "displayManager" "job" "logToFile" ]) + (mkRenamedOptionModule [ "services" "xserver" "displayManager" "logToJournal" ] [ "services" "xserver" "displayManager" "job" "logToJournal" ]) + # Old Grub-related options. (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]) (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]) @@ -78,6 +82,10 @@ with lib; (mkRenamedOptionModule [ "services" "virtualboxHost" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ]) (mkRenamedOptionModule [ "services" "virtualboxHost" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ]) + # libvirtd + (mkRemovedOptionModule [ "virtualisation" "libvirtd" "enableKVM" ] + "Set the option `virtualisation.libvirtd.qemuPackage' instead.") + # Tarsnap (mkRenamedOptionModule [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ]) @@ -178,6 +186,17 @@ with lib; (mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "config" "fonts" "fontconfig" "forceAutohint" ]) (mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "config" "fonts" "fontconfig" "renderMonoTTFAsBitmap" ]) + # Profile splitting + (mkRenamedOptionModule [ "virtualization" "growPartition" ] [ "boot" "growPartition" ]) + + # misc/version.nix + (mkRenamedOptionModule [ "config" "system" "nixosVersion" ] [ "config" "system" "nixos" "version" ]) + (mkRenamedOptionModule [ "config" "system" "nixosRelease" ] [ "config" "system" "nixos" "release" ]) + (mkRenamedOptionModule [ "config" "system" "nixosVersionSuffix" ] [ "config" "system" "nixos" "versionSuffix" ]) + (mkRenamedOptionModule [ "config" "system" "nixosRevision" ] [ "config" "system" "nixos" "revision" ]) + (mkRenamedOptionModule [ "config" "system" "nixosCodeName" ] [ "config" "system" "nixos" "codeName" ]) + (mkRenamedOptionModule [ "config" "system" "nixosLabel" ] [ "config" "system" "nixos" "label" ]) + # Options that are obsolete and have no replacement. (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "") (mkRemovedOptionModule [ "programs" "bash" "enable" ] "") @@ -194,11 +213,14 @@ with lib; "See the 16.09 release notes for more information.") (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ] "") (mkRemovedOptionModule [ "services" "dovecot2" "package" ] "") + (mkRemovedOptionModule [ "services" "firefox" "syncserver" "user" ] "") + (mkRemovedOptionModule [ "services" "firefox" "syncserver" "group" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "hinting" "style" ] "") (mkRemovedOptionModule [ "services" "xserver" "displayManager" "sddm" "themes" ] "Set the option `services.xserver.displayManager.sddm.package' instead.") (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "") + (mkRemovedOptionModule [ "virtualisation" "xen" "qemu" ] "You don't need this option anymore, it will work without it.") # ZSH (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) @@ -209,5 +231,8 @@ with lib; (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "theme" ] [ "programs" "zsh" "ohMyZsh" "theme" ]) (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "custom" ] [ "programs" "zsh" "ohMyZsh" "custom" ]) (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "plugins" ] [ "programs" "zsh" "ohMyZsh" "plugins" ]) + + # Xen + (mkRenamedOptionModule [ "virtualisation" "xen" "qemu-package" ] [ "virtualisation" "xen" "package-qemu" ]) ]; } diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index fb011019f7f5..0736239ed2cf 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -6,10 +6,11 @@ let cfg = config.security.acme; - certOpts = { ... }: { + certOpts = { name, ... }: { options = { webroot = mkOption { type = types.str; + example = "/var/lib/acme/acme-challenges"; description = '' Where the webroot of the HTTP vhost is located. <filename>.well-known/acme-challenge/</filename> directory @@ -20,8 +21,8 @@ let }; domain = mkOption { - type = types.nullOr types.str; - default = null; + type = types.str; + default = name; description = "Domain to fetch certificate for (defaults to the entry name)"; }; @@ -48,7 +49,7 @@ let default = false; description = '' Give read permissions to the specified group - (<option>security.acme.group</option>) to read SSL private certificates. + (<option>security.acme.cert.<name>.group</option>) to read SSL private certificates. ''; }; @@ -87,7 +88,7 @@ let } ''; description = '' - Extra domain names for which certificates are to be issued, with their + A list of extra domain names, which are included in the one certificate to be issued, with their own server roots if needed. ''; }; @@ -139,6 +140,14 @@ in ''; }; + tosHash = mkOption { + type = types.string; + default = "cc88d8d9517f490191401e7b54e9ffd12a2b9082ec7a1d4cec6101f9f1647e7b"; + description = '' + SHA256 of the Terms of Services document. This changes once in a while. + ''; + }; + production = mkOption { type = types.bool; default = true; @@ -185,10 +194,9 @@ in servicesLists = mapAttrsToList certToServices cfg.certs; certToServices = cert: data: let - domain = if data.domain != null then data.domain else cert; cpath = "${cfg.directory}/${cert}"; rights = if data.allowKeysForGroup then "750" else "700"; - cmdline = [ "-v" "-d" domain "--default_root" data.webroot "--valid_min" cfg.validMin ] + cmdline = [ "-v" "-d" data.domain "--default_root" data.webroot "--valid_min" cfg.validMin "--tos_sha256" cfg.tosHash ] ++ optionals (data.email != null) [ "--email" data.email ] ++ concatMap (p: [ "-f" p ]) data.plugins ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 2d6713311a45..f39f64033ca7 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -46,6 +46,18 @@ let ''; }; + googleAuthenticator = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + If set, users with enabled Google Authenticator (created + <filename>~/.google_authenticator</filename>) will be required + to provide Google Authenticator token to log in. + ''; + }; + }; + usbAuth = mkOption { default = config.security.pam.usb.enable; type = types.bool; @@ -223,6 +235,17 @@ let ''; }; + enableGnomeKeyring = mkOption { + default = false; + type = types.bool; + description = '' + If enabled, pam_gnome_keyring will attempt to automatically unlock the + user's default Gnome keyring upon login. If the user login password does + not match their keyring password, Gnome Keyring will prompt separately + after login. + ''; + }; + text = mkOption { type = types.nullOr types.lines; description = "Contents of the PAM service file."; @@ -273,7 +296,12 @@ let # prompts the user for password so we run it once with 'required' at an # earlier point and it will run again with 'sufficient' further down. # We use try_first_pass the second time to avoid prompting password twice - (optionalString (cfg.unixAuth && (config.security.pam.enableEcryptfs || cfg.pamMount || cfg.enableKwallet)) '' + (optionalString (cfg.unixAuth && + (config.security.pam.enableEcryptfs + || cfg.pamMount + || cfg.enableKwallet + || cfg.enableGnomeKeyring + || cfg.googleAuthenticator.enable)) '' auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth ${optionalString config.security.pam.enableEcryptfs "auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} @@ -282,6 +310,10 @@ let ${optionalString cfg.enableKwallet ("auth optional ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so" + " kwalletd=${pkgs.libsForQt5.kwallet.bin}/bin/kwalletd5")} + ${optionalString cfg.enableGnomeKeyring + ("auth optional ${pkgs.gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so")} + ${optionalString cfg.googleAuthenticator.enable + "auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp"} '') + '' ${optionalString cfg.unixAuth "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth try_first_pass"} @@ -351,6 +383,10 @@ let ${optionalString (cfg.enableKwallet) ("session optional ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so" + " kwalletd=${pkgs.libsForQt5.kwallet.bin}/bin/kwalletd5")} + ${optionalString (cfg.enableGnomeKeyring) + "session optional ${pkgs.gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start"} + ${optionalString (config.virtualisation.lxc.lxcfs.enable) + "session optional ${pkgs.lxcfs}/lib/security/pam_cgfs.so -c freezer,memory,name=systemd,unified,cpuset"} ''); }; @@ -519,7 +555,6 @@ in ftp = {}; i3lock = {}; i3lock-color = {}; - swaylock = {}; screen = {}; vlock = {}; xlock = {}; diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index cfd0595e63b7..a57f14bb5ae1 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -8,6 +8,22 @@ let inherit (pkgs) sudo; + toUserString = user: if (isInt user) then "#${toString user}" else "${user}"; + toGroupString = group: if (isInt group) then "%#${toString group}" else "%${group}"; + + toCommandOptionsString = options: + "${concatStringsSep ":" options}${optionalString (length options != 0) ":"} "; + + toCommandsString = commands: + concatStringsSep ", " ( + map (command: + if (isString command) then + command + else + "${toCommandOptionsString command.options}${command.command}" + ) commands + ); + in { @@ -47,6 +63,97 @@ in ''; }; + security.sudo.extraRules = mkOption { + description = '' + Define specific rules to be in the <filename>sudoers</filename> file. + ''; + default = []; + example = [ + # Allow execution of any command by all users in group sudo, + # requiring a password. + { groups = [ "sudo" ]; commands = [ "ALL" ]; } + + # Allow execution of "/home/root/secret.sh" by user `backup`, `database` + # and the group with GID `1006` without a password. + { users = [ "backup" ]; groups = [ 1006 ]; + commands = [ { command = "/home/root/secret.sh"; options = [ "SETENV" "NOPASSWD" ]; } ]; } + + # Allow all users of group `bar` to run two executables as user `foo` + # with arguments being pre-set. + { groups = [ "bar" ]; runAs = "foo"; + commands = + [ "/home/baz/cmd1.sh hello-sudo" + { command = ''/home/baz/cmd2.sh ""''; options = [ "SETENV" ]; } ]; } + ]; + type = with types; listOf (submodule { + options = { + users = mkOption { + type = with types; listOf (either string int); + description = '' + The usernames / UIDs this rule should apply for. + ''; + default = []; + }; + + groups = mkOption { + type = with types; listOf (either string int); + description = '' + The groups / GIDs this rule should apply for. + ''; + default = []; + }; + + host = mkOption { + type = types.string; + default = "ALL"; + description = '' + For what host this rule should apply. + ''; + }; + + runAs = mkOption { + type = with types; string; + default = "ALL:ALL"; + description = '' + Under which user/group the specified command is allowed to run. + + A user can be specified using just the username: <code>"foo"</code>. + It is also possible to specify a user/group combination using <code>"foo:bar"</code> + or to only allow running as a specific group with <code>":bar"</code>. + ''; + }; + + commands = mkOption { + description = '' + The commands for which the rule should apply. + ''; + type = with types; listOf (either string (submodule { + + options = { + command = mkOption { + type = with types; string; + description = '' + A command being either just a path to a binary to allow any arguments, + the full command with arguments pre-set or with <code>""</code> used as the argument, + not allowing arguments to the command at all. + ''; + }; + + options = mkOption { + type = with types; listOf (enum [ "NOPASSWD" "PASSWD" "NOEXEC" "EXEC" "SETENV" "NOSETENV" "LOG_INPUT" "NOLOG_INPUT" "LOG_OUTPUT" "NOLOG_OUTPUT" ]); + description = '' + Options for running the command. Refer to the <a href="https://www.sudo.ws/man/1.7.10/sudoers.man.html">sudo manual</a>. + ''; + default = []; + }; + }; + + })); + }; + }; + }); + }; + security.sudo.extraConfig = mkOption { type = types.lines; default = ""; @@ -61,10 +168,16 @@ in config = mkIf cfg.enable { + security.sudo.extraRules = [ + { groups = [ "wheel" ]; + commands = [ { command = "ALL"; options = (if cfg.wheelNeedsPassword then [ "SETENV" ] else [ "NOPASSWD" "SETENV" ]); } ]; + } + ]; + security.sudo.configFile = '' # Don't edit this file. Set the NixOS options ‘security.sudo.configFile’ - # or ‘security.sudo.extraConfig’ instead. + # or ‘security.sudo.extraRules’ instead. # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic. Defaults env_keep+=SSH_AUTH_SOCK @@ -72,8 +185,18 @@ in # "root" is allowed to do anything. root ALL=(ALL:ALL) SETENV: ALL - # Users in the "wheel" group can do anything. - %wheel ALL=(ALL:ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL + # extraRules + ${concatStringsSep "\n" ( + lists.flatten ( + map ( + rule: if (length rule.commands != 0) then [ + (map (user: "${toUserString user} ${rule.host}=(${rule.runAs}) ${toCommandsString rule.commands}") rule.users) + (map (group: "${toGroupString group} ${rule.host}=(${rule.runAs}) ${toCommandsString rule.commands}") rule.groups) + ] else [] + ) cfg.extraRules + ) + )} + ${cfg.extraConfig} ''; diff --git a/nixos/modules/security/wrappers/default.nix b/nixos/modules/security/wrappers/default.nix index 1f64213accd4..77e4b2a616d8 100644 --- a/nixos/modules/security/wrappers/default.nix +++ b/nixos/modules/security/wrappers/default.nix @@ -17,7 +17,7 @@ let hardeningEnable = [ "pie" ]; installPhase = '' mkdir -p $out/bin - gcc -Wall -O2 -DWRAPPER_DIR=\"${parentWrapperDir}\" \ + $CC -Wall -O2 -DWRAPPER_DIR=\"${parentWrapperDir}\" \ -lcap-ng -lcap ${./wrapper.c} -o $out/bin/security-wrapper ''; }; @@ -79,7 +79,7 @@ let ({ owner = "root"; group = "root"; } // s) - else if + else if (s ? "setuid" && s.setuid) || (s ? "setgid" && s.setgid) || (s ? "permissions") diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix index c0a0f0374294..52613d450b51 100644 --- a/nixos/modules/services/audio/mopidy.nix +++ b/nixos/modules/services/audio/mopidy.nix @@ -4,17 +4,22 @@ with pkgs; with lib; let - uid = config.ids.uids.mopidy; gid = config.ids.gids.mopidy; cfg = config.services.mopidy; mopidyConf = writeText "mopidy.conf" cfg.configuration; - mopidyEnv = python.buildEnv.override { - extraLibs = [ mopidy ] ++ cfg.extensionPackages; + mopidyEnv = buildEnv { + name = "mopidy-with-extensions-${mopidy.version}"; + paths = closePropagation cfg.extensionPackages; + pathsToLink = [ "/${python.sitePackages}" ]; + buildInputs = [ makeWrapper ]; + postBuild = '' + makeWrapper ${mopidy}/bin/mopidy $out/bin/mopidy \ + --prefix PYTHONPATH : $out/${python.sitePackages} + ''; }; - in { options = { @@ -61,7 +66,6 @@ in { }; - ###### implementation config = mkIf cfg.enable { diff --git a/nixos/modules/services/backup/crashplan-small-business.nix b/nixos/modules/services/backup/crashplan-small-business.nix new file mode 100644 index 000000000000..c6002b6a3f6b --- /dev/null +++ b/nixos/modules/services/backup/crashplan-small-business.nix @@ -0,0 +1,89 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.crashplansb; + crashplansb = pkgs.crashplansb.override { maxRam = cfg.maxRam; }; + varDir = "/var/lib/crashplan"; +in + +with lib; + +{ + options = { + services.crashplansb = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Starts crashplan for small business background service. + ''; + }; + maxRam = mkOption { + default = "1024m"; + example = "2G"; + type = types.str; + description = '' + Maximum amount of that the crashplan engine should use. + ''; + }; + openPorts = mkOption { + description = "Open ports in the firewall for crashplan."; + default = true; + type = types.bool; + }; + ports = mkOption { + # https://support.code42.com/Administrator/6/Planning_and_installing/TCP_and_UDP_ports_used_by_the_Code42_platform + # used ports can also be checked in the desktop app console using the command connection.info + description = "which ports to open."; + default = [ 4242 4243 4244 4247 ]; + type = types.listOf types.int; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ crashplansb ]; + networking.firewall.allowedTCPPorts = mkIf cfg.openPorts cfg.ports; + + systemd.services.crashplansb = { + description = "CrashPlan Backup Engine"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "local-fs.target" ]; + + preStart = '' + ensureDir() { + dir=$1 + mode=$2 + + if ! test -e $dir; then + ${pkgs.coreutils}/bin/mkdir -m $mode -p $dir + elif [ "$(${pkgs.coreutils}/bin/stat -c %a $dir)" != "$mode" ]; then + ${pkgs.coreutils}/bin/chmod $mode $dir + fi + } + + ensureDir ${crashplansb.vardir} 755 + ensureDir ${crashplansb.vardir}/conf 700 + ensureDir ${crashplansb.manifestdir} 700 + ensureDir ${crashplansb.vardir}/cache 700 + ensureDir ${crashplansb.vardir}/backupArchives 700 + ensureDir ${crashplansb.vardir}/log 777 + cp -avn ${crashplansb}/conf.template/* ${crashplansb.vardir}/conf + #for x in bin install.vars lang lib libc42archive64.so libc42core.so libjniwrap64.so libjtux64.so libleveldb64.so libnetty-tcnative.so share upgrade; do + # rm -f ${crashplansb.vardir}/$x; + # ln -sf ${crashplansb}/$x ${crashplansb.vardir}/$x; + #done + ''; + + serviceConfig = { + Type = "forking"; + EnvironmentFile = "${crashplansb}/bin/run.conf"; + ExecStart = "${crashplansb}/bin/CrashPlanEngine start"; + ExecStop = "${crashplansb}/bin/CrashPlanEngine stop"; + PIDFile = "${crashplansb.vardir}/CrashPlanEngine.pid"; + WorkingDirectory = crashplansb; + }; + }; + }; +} diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix index 7c9dedb67ad2..59e9d122fb50 100644 --- a/nixos/modules/services/backup/tarsnap.nix +++ b/nixos/modules/services/backup/tarsnap.nix @@ -115,7 +115,7 @@ in description = '' Print global archive statistics upon completion. The output is available via - <command>systemctl status tarsnap@archive-name</command>. + <command>systemctl status tarsnap-archive-name</command>. ''; }; diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix index baf99930e3eb..762bb4b38675 100644 --- a/nixos/modules/services/backup/znapzend.nix +++ b/nixos/modules/services/backup/znapzend.nix @@ -1,39 +1,372 @@ { config, lib, pkgs, ... }: with lib; +with types; let + + # Converts a plan like + # { "1d" = "1h"; "1w" = "1d"; } + # into + # "1d=>1h,1w=>1d" + attrToPlan = attrs: concatStringsSep "," (builtins.attrValues ( + mapAttrs (n: v: "${n}=>${v}") attrs)); + + planDescription = '' + The znapzend backup plan to use for the source. + </para> + <para> + The plan specifies how often to backup and for how long to keep the + backups. It consists of a series of retention periodes to interval + associations: + </para> + <para> + <literal> + retA=>intA,retB=>intB,... + </literal> + </para> + <para> + Both intervals and retention periods are expressed in standard units + of time or multiples of them. You can use both the full name or a + shortcut according to the following listing: + </para> + <para> + <literal> + second|sec|s, minute|min, hour|h, day|d, week|w, month|mon|m, year|y + </literal> + </para> + <para> + See <citerefentry><refentrytitle>znapzendzetup</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more info. + ''; + planExample = "1h=>10min,1d=>1h,1w=>1d,1m=>1w,1y=>1m"; + + # A type for a string of the form number{b|k|M|G} + mbufferSizeType = str // { + check = x: str.check x && builtins.isList (builtins.match "^[0-9]+[bkMG]$" x); + description = "string of the form number{b|k|M|G}"; + }; + + # Type for a string that must contain certain other strings (the list parameter). + # Note that these would need regex escaping. + stringContainingStrings = list: let + matching = s: map (str: builtins.match ".*${str}.*" s) list; + in str // { + check = x: str.check x && all isList (matching x); + description = "string containing all of the characters ${concatStringsSep ", " list}"; + }; + + timestampType = stringContainingStrings [ "%Y" "%m" "%d" "%H" "%M" "%S" ]; + + destType = srcConfig: submodule ({ name, ... }: { + options = { + + label = mkOption { + type = str; + description = "Label for this destination. Defaults to the attribute name."; + }; + + plan = mkOption { + type = str; + description = planDescription; + example = planExample; + }; + + dataset = mkOption { + type = str; + description = "Dataset name to send snapshots to."; + example = "tank/main"; + }; + + host = mkOption { + type = nullOr str; + description = '' + Host to use for the destination dataset. Can be prefixed with + <literal>user@</literal> to specify the ssh user. + ''; + default = null; + example = "john@example.com"; + }; + + presend = mkOption { + type = nullOr str; + description = '' + Command to run before sending the snapshot to the destination. + Intended to run a remote script via <command>ssh</command> on the + destination, e.g. to bring up a backup disk or server or to put a + zpool online/offline. See also <option>postsend</option>. + ''; + default = null; + example = "ssh root@bserv zpool import -Nf tank"; + }; + + postsend = mkOption { + type = nullOr str; + description = '' + Command to run after sending the snapshot to the destination. + Intended to run a remote script via <command>ssh</command> on the + destination, e.g. to bring up a backup disk or server or to put a + zpool online/offline. See also <option>presend</option>. + ''; + default = null; + example = "ssh root@bserv zpool export tank"; + }; + }; + + config = { + label = mkDefault name; + plan = mkDefault srcConfig.plan; + }; + }); + + + + srcType = submodule ({ name, config, ... }: { + options = { + + enable = mkOption { + type = bool; + description = "Whether to enable this source."; + default = true; + }; + + recursive = mkOption { + type = bool; + description = "Whether to do recursive snapshots."; + default = false; + }; + + mbuffer = { + enable = mkOption { + type = bool; + description = "Whether to use <command>mbuffer</command>."; + default = false; + }; + + port = mkOption { + type = nullOr ints.u16; + description = '' + Port to use for <command>mbuffer</command>. + </para> + <para> + If this is null, it will run <command>mbuffer</command> through + ssh. + </para> + <para> + If this is not null, it will run <command>mbuffer</command> + directly through TCP, which is not encrypted but faster. In that + case the given port needs to be open on the destination host. + ''; + default = null; + }; + + size = mkOption { + type = mbufferSizeType; + description = '' + The size for <command>mbuffer</command>. + Supports the units b, k, M, G. + ''; + default = "1G"; + example = "128M"; + }; + }; + + presnap = mkOption { + type = nullOr str; + description = '' + Command to run before snapshots are taken on the source dataset, + e.g. for database locking/flushing. See also + <option>postsnap</option>. + ''; + default = null; + example = literalExample '' + ''${pkgs.mariadb}/bin/mysql -e "set autocommit=0;flush tables with read lock;\\! ''${pkgs.coreutils}/bin/sleep 600" & ''${pkgs.coreutils}/bin/echo $! > /tmp/mariadblock.pid ; sleep 10 + ''; + }; + + postsnap = mkOption { + type = nullOr str; + description = '' + Command to run after snapshots are taken on the source dataset, + e.g. for database unlocking. See also <option>presnap</option>. + ''; + default = null; + example = literalExample '' + ''${pkgs.coreutils}/bin/kill `''${pkgs.coreutils}/bin/cat /tmp/mariadblock.pid`;''${pkgs.coreutils}/bin/rm /tmp/mariadblock.pid + ''; + }; + + timestampFormat = mkOption { + type = timestampType; + description = '' + The timestamp format to use for constructing snapshot names. + The syntax is <literal>strftime</literal>-like. The string must + consist of the mandatory <literal>%Y %m %d %H %M %S</literal>. + Optionally <literal>- _ . :</literal> characters as well as any + alphanumeric character are allowed. If suffixed by a + <literal>Z</literal>, times will be in UTC. + ''; + default = "%Y-%m-%d-%H%M%S"; + example = "znapzend-%m.%d.%Y-%H%M%SZ"; + }; + + sendDelay = mkOption { + type = int; + description = '' + Specify delay (in seconds) before sending snaps to the destination. + May be useful if you want to control sending time. + ''; + default = 0; + example = 60; + }; + + plan = mkOption { + type = str; + description = planDescription; + example = planExample; + }; + + dataset = mkOption { + type = str; + description = "The dataset to use for this source."; + example = "tank/home"; + }; + + destinations = mkOption { + type = loaOf (destType config); + description = "Additional destinations."; + default = {}; + example = literalExample '' + { + local = { + dataset = "btank/backup"; + presend = "zpool import -N btank"; + postsend = "zpool export btank"; + }; + remote = { + host = "john@example.com"; + dataset = "tank/john"; + }; + }; + ''; + }; + }; + + config = { + dataset = mkDefault name; + }; + + }); + + ### Generating the configuration from here + cfg = config.services.znapzend; + + onOff = b: if b then "on" else "off"; + nullOff = b: if isNull b then "off" else toString b; + stripSlashes = replaceStrings [ "/" ] [ "." ]; + + attrsToFile = config: concatStringsSep "\n" (builtins.attrValues ( + mapAttrs (n: v: "${n}=${v}") config)); + + mkDestAttrs = dst: with dst; + mapAttrs' (n: v: nameValuePair "dst_${label}${n}" v) ({ + "" = optionalString (! isNull host) "${host}:" + dataset; + _plan = plan; + } // optionalAttrs (presend != null) { + _precmd = presend; + } // optionalAttrs (postsend != null) { + _pstcmd = postsend; + }); + + mkSrcAttrs = srcCfg: with srcCfg; { + enabled = onOff enable; + mbuffer = with mbuffer; if enable then "${pkgs.mbuffer}/bin/mbuffer" + + optionalString (port != null) ":${toString port}" else "off"; + mbuffer_size = mbuffer.size; + post_znap_cmd = nullOff postsnap; + pre_znap_cmd = nullOff presnap; + recursive = onOff recursive; + src = dataset; + src_plan = plan; + tsformat = timestampFormat; + zend_delay = toString sendDelay; + } // fold (a: b: a // b) {} ( + map mkDestAttrs (builtins.attrValues destinations) + ); + + files = mapAttrs' (n: srcCfg: let + fileText = attrsToFile (mkSrcAttrs srcCfg); + in { + name = srcCfg.dataset; + value = pkgs.writeText (stripSlashes srcCfg.dataset) fileText; + }) cfg.zetup; + in { options = { services.znapzend = { - enable = mkEnableOption "ZnapZend daemon"; + enable = mkEnableOption "ZnapZend ZFS backup daemon"; logLevel = mkOption { default = "debug"; example = "warning"; - type = lib.types.enum ["debug" "info" "warning" "err" "alert"]; - description = "The log level when logging to file. Any of debug, info, warning, err, alert. Default in daemonized form is debug."; + type = enum ["debug" "info" "warning" "err" "alert"]; + description = '' + The log level when logging to file. Any of debug, info, warning, err, + alert. Default in daemonized form is debug. + ''; }; logTo = mkOption { - type = types.str; + type = str; default = "syslog::daemon"; example = "/var/log/znapzend.log"; - description = "Where to log to (syslog::<facility> or <filepath>)."; + description = '' + Where to log to (syslog::<facility> or <filepath>). + ''; }; noDestroy = mkOption { - type = types.bool; + type = bool; default = false; description = "Does all changes to the filesystem except destroy."; }; autoCreation = mkOption { - type = types.bool; + type = bool; + default = false; + description = "Automatically create the destination dataset if it does not exists."; + }; + + zetup = mkOption { + type = loaOf srcType; + description = "Znapzend configuration."; + default = {}; + example = literalExample '' + { + "tank/home" = { + # Make snapshots of tank/home every hour, keep those for 1 day, + # keep every days snapshot for 1 month, etc. + plan = "1d=>1h,1m=>1d,1y=>1m"; + recursive = true; + # Send all those snapshots to john@example.com:rtank/john as well + destinations.remote = { + host = "john@example.com"; + dataset = "rtank/john"; + }; + }; + }; + ''; + }; + + pure = mkOption { + type = bool; + description = '' + Do not persist any stateful znapzend setups. If this option is + enabled, your previously set znapzend setups will be cleared and only + the ones defined with this module will be applied. + ''; default = false; - description = "Automatically create the dataset on dest if it does not exists."; }; }; }; @@ -49,12 +382,30 @@ in path = with pkgs; [ zfs mbuffer openssh ]; + preStart = optionalString cfg.pure '' + echo Resetting znapzend zetups + ${pkgs.znapzend}/bin/znapzendzetup list \ + | grep -oP '(?<=\*\*\* backup plan: ).*(?= \*\*\*)' \ + | xargs ${pkgs.znapzend}/bin/znapzendzetup delete + '' + concatStringsSep "\n" (mapAttrsToList (dataset: config: '' + echo Importing znapzend zetup ${config} for dataset ${dataset} + ${pkgs.znapzend}/bin/znapzendzetup import --write ${dataset} ${config} + '') files); + serviceConfig = { - ExecStart = "${pkgs.znapzend}/bin/znapzend --logto=${cfg.logTo} --loglevel=${cfg.logLevel} ${optionalString cfg.noDestroy "--nodestroy"} ${optionalString cfg.autoCreation "--autoCreation"}"; + ExecStart = let + args = concatStringsSep " " [ + "--logto=${cfg.logTo}" + "--loglevel=${cfg.logLevel}" + (optionalString cfg.noDestroy "--nodestroy") + (optionalString cfg.autoCreation "--autoCreation") + ]; in "${pkgs.znapzend}/bin/znapzend ${args}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; }; }; }; }; + + meta.maintainers = with maintainers; [ infinisil ]; } diff --git a/nixos/modules/services/cluster/kubernetes/dashboard.nix b/nixos/modules/services/cluster/kubernetes/dashboard.nix index 75d71fccfda4..e331889b9dd5 100644 --- a/nixos/modules/services/cluster/kubernetes/dashboard.nix +++ b/nixos/modules/services/cluster/kubernetes/dashboard.nix @@ -6,12 +6,12 @@ let cfg = config.services.kubernetes.addons.dashboard; name = "gcr.io/google_containers/kubernetes-dashboard-amd64"; - version = "v1.6.3"; + version = "v1.8.2"; image = pkgs.dockerTools.pullImage { imageName = name; imageTag = version; - sha256 = "1sf54d96nkgic9hir9c6p14gw24ns1k5d5a0r1sg414kjrvic0b4"; + sha256 = "11h0fz3wxp0f10fsyqaxjm7l2qg7xws50dv5iwlck5gb1fjmajad"; }; in { options.services.kubernetes.addons.dashboard = { diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix index 077953e4d4f8..4a2c6f0833eb 100644 --- a/nixos/modules/services/cluster/kubernetes/default.nix +++ b/nixos/modules/services/cluster/kubernetes/default.nix @@ -301,8 +301,8 @@ in { Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC/RBAC). See <link xlink:href="http://kubernetes.io/docs/admin/authorization.html"/> ''; - default = ["RBAC"]; - type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "RBAC"]); + default = ["RBAC" "Node"]; + type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "RBAC" "Node"]); }; authorizationPolicy = mkOption { @@ -344,7 +344,7 @@ in { Kubernetes admission control plugins to use. See <link xlink:href="http://kubernetes.io/docs/admin/admission-controllers/"/> ''; - default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota" "DefaultStorageClass" "DefaultTolerationSeconds"]; + default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota" "DefaultStorageClass" "DefaultTolerationSeconds" "NodeRestriction"]; example = [ "NamespaceLifecycle" "NamespaceExists" "LimitRanger" "SecurityContextDeny" "ServiceAccount" "ResourceQuota" diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix index fb91a29a4000..45d34f5b76f5 100644 --- a/nixos/modules/services/computing/slurm/slurm.nix +++ b/nixos/modules/services/computing/slurm/slurm.nix @@ -6,14 +6,20 @@ let cfg = config.services.slurm; # configuration file can be generated by http://slurm.schedmd.com/configurator.html - configFile = pkgs.writeText "slurm.conf" + configFile = pkgs.writeText "slurm.conf" '' ${optionalString (cfg.controlMachine != null) ''controlMachine=${cfg.controlMachine}''} ${optionalString (cfg.controlAddr != null) ''controlAddr=${cfg.controlAddr}''} ${optionalString (cfg.nodeName != null) ''nodeName=${cfg.nodeName}''} ${optionalString (cfg.partitionName != null) ''partitionName=${cfg.partitionName}''} + PlugStackConfig=${plugStackConfig} ${cfg.extraConfig} ''; + + plugStackConfig = pkgs.writeText "plugstack.conf" + '' + ${optionalString cfg.enableSrunX11 ''optional ${pkgs.slurm-spank-x11}/lib/x11.so''} + ''; in { @@ -28,7 +34,7 @@ in enable = mkEnableOption "slurm control daemon"; }; - + client = { enable = mkEnableOption "slurm rlient daemon"; @@ -86,8 +92,19 @@ in ''; }; + enableSrunX11 = mkOption { + default = false; + type = types.bool; + description = '' + If enabled srun will accept the option "--x11" to allow for X11 forwarding + from within an interactive session or a batch job. This activates the + slurm-spank-x11 module. Note that this requires 'services.openssh.forwardX11' + to be enabled on the compute nodes. + ''; + }; + extraConfig = mkOption { - default = ""; + default = ""; type = types.lines; description = '' Extra configuration options that will be added verbatim at @@ -134,7 +151,8 @@ in environment.systemPackages = [ wrappedSlurm ]; systemd.services.slurmd = mkIf (cfg.client.enable) { - path = with pkgs; [ wrappedSlurm coreutils ]; + path = with pkgs; [ wrappedSlurm coreutils ] + ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; wantedBy = [ "multi-user.target" ]; after = [ "systemd-tmpfiles-clean.service" ]; @@ -152,8 +170,9 @@ in }; systemd.services.slurmctld = mkIf (cfg.server.enable) { - path = with pkgs; [ wrappedSlurm munge coreutils ]; - + path = with pkgs; [ wrappedSlurm munge coreutils ] + ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; + wantedBy = [ "multi-user.target" ]; after = [ "network.target" "munged.service" ]; requires = [ "munged.service" ]; diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix index dcc5e7174601..0a0c9f665d25 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agent.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix @@ -4,6 +4,31 @@ with lib; let cfg = config.services.buildkite-agent; + + mkHookOption = { name, description, example ? null }: { + inherit name; + value = mkOption { + default = null; + inherit description; + type = types.nullOr types.lines; + } // (if example == null then {} else { inherit example; }); + }; + mkHookOptions = hooks: listToAttrs (map mkHookOption hooks); + + hooksDir = let + mkHookEntry = name: value: '' + cat > $out/${name} <<EOF + #! ${pkgs.stdenv.shell} + set -e + ${value} + EOF + chmod 755 $out/${name} + ''; + in pkgs.runCommand "buildkite-agent-hooks" {} '' + mkdir $out + ${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))} + ''; + in { @@ -43,6 +68,7 @@ in name = mkOption { type = types.str; + default = "%hostname-%n"; description = '' The name of the agent. ''; @@ -51,8 +77,19 @@ in meta-data = mkOption { type = types.str; default = ""; + example = "queue=default,docker=true,ruby2=true"; + description = '' + Meta data for the agent. This is a comma-separated list of + <code>key=value</code> pairs. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = "debug=true"; description = '' - Meta data for the agent. + Extra lines to be added verbatim to the configuration file. ''; }; @@ -76,6 +113,74 @@ in ''; }; }; + + hooks = mkHookOptions [ + { name = "checkout"; + description = '' + The `checkout` hook script will replace the default checkout routine of the + bootstrap.sh script. You can use this hook to do your own SCM checkout + behaviour + ''; } + { name = "command"; + description = '' + The `command` hook script will replace the default implementation of running + the build command. + ''; } + { name = "environment"; + description = '' + The `environment` hook will run before all other commands, and can be used + to set up secrets, data, etc. Anything exported in hooks will be available + to the build script. + + Note: the contents of this file will be copied to the world-readable + Nix store. + ''; + example = '' + export SECRET_VAR=`head -1 /run/keys/secret` + ''; } + { name = "post-artifact"; + description = '' + The `post-artifact` hook will run just after artifacts are uploaded + ''; } + { name = "post-checkout"; + description = '' + The `post-checkout` hook will run after the bootstrap script has checked out + your projects source code. + ''; } + { name = "post-command"; + description = '' + The `post-command` hook will run after the bootstrap script has run your + build commands + ''; } + { name = "pre-artifact"; + description = '' + The `pre-artifact` hook will run just before artifacts are uploaded + ''; } + { name = "pre-checkout"; + description = '' + The `pre-checkout` hook will run just before your projects source code is + checked out from your SCM provider + ''; } + { name = "pre-command"; + description = '' + The `pre-command` hook will run just before your build command runs + ''; } + { name = "pre-exit"; + description = '' + The `pre-exit` hook will run just before your build job finishes + ''; } + ]; + + hooksPath = mkOption { + type = types.path; + default = hooksDir; + defaultText = "generated from services.buildkite-agent.hooks"; + description = '' + Path to the directory storing the hooks. + Consider using <option>services.buildkite-agent.hooks.<name></option> + instead. + ''; + }; }; }; @@ -91,13 +196,10 @@ in environment.systemPackages = [ cfg.package ]; systemd.services.buildkite-agent = - let copy = x: target: perms: - "cp -f ${x} ${target}; ${pkgs.coreutils}/bin/chmod ${toString perms} ${target}; "; - in { description = "Buildkite Agent"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - path = cfg.runtimePackages; + path = cfg.runtimePackages ++ [ pkgs.coreutils ]; environment = config.networking.proxy.envVars // { HOME = cfg.dataDir; NIX_REMOTE = "daemon"; @@ -105,18 +207,22 @@ in ## NB: maximum care is taken so that secrets (ssh keys and the CI token) ## don't end up in the Nix store. - preStart = '' - ${pkgs.coreutils}/bin/mkdir -m 0700 -p ${cfg.dataDir}/.ssh - ${copy (toString cfg.openssh.privateKeyPath) "${cfg.dataDir}/.ssh/id_rsa" 600} - ${copy (toString cfg.openssh.publicKeyPath) "${cfg.dataDir}/.ssh/id_rsa.pub" 600} + preStart = let + sshDir = "${cfg.dataDir}/.ssh"; + in + '' + mkdir -m 0700 -p "${sshDir}" + cp -f "${toString cfg.openssh.privateKeyPath}" "${sshDir}/id_rsa" + cp -f "${toString cfg.openssh.publicKeyPath}" "${sshDir}/id_rsa.pub" + chmod 600 "${sshDir}"/id_rsa* cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF token="$(cat ${toString cfg.tokenPath})" name="${cfg.name}" meta-data="${cfg.meta-data}" - hooks-path="${pkgs.buildkite-agent}/share/hooks" build-path="${cfg.dataDir}/builds" - bootstrap-script="${pkgs.buildkite-agent}/share/bootstrap.sh" + hooks-path="${cfg.hooksPath}" + ${cfg.extraConfig} EOF ''; @@ -128,6 +234,15 @@ in TimeoutSec = 10; }; }; + + assertions = [ + { assertion = cfg.hooksPath == hooksDir || all isNull (attrValues cfg.hooks); + message = '' + Options `services.buildkite-agent.hooksPath' and + `services.buildkite-agent.hooks.<name>' are mutually exclusive. + ''; + } + ]; }; imports = [ (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ]) diff --git a/nixos/modules/services/databases/memcached.nix b/nixos/modules/services/databases/memcached.nix index c6875af506d3..46bc6fc5c132 100644 --- a/nixos/modules/services/databases/memcached.nix +++ b/nixos/modules/services/databases/memcached.nix @@ -40,11 +40,7 @@ in description = "The port to bind to"; }; - socket = mkOption { - default = ""; - description = "Unix socket path to listen on. Setting this will disable network support"; - example = "/var/run/memcached"; - }; + enableUnixSocket = mkEnableOption "unix socket at /run/memcached/memcached.sock"; maxMemory = mkOption { default = 64; @@ -68,31 +64,40 @@ in config = mkIf config.services.memcached.enable { - users.extraUsers.memcached = - { name = cfg.user; - uid = config.ids.uids.memcached; - description = "Memcached server user"; - }; + users.extraUsers = optional (cfg.user == "memcached") { + name = "memcached"; + description = "Memcached server user"; + }; environment.systemPackages = [ memcached ]; - systemd.services.memcached = - { description = "Memcached server"; - - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - serviceConfig = { - ExecStart = - let - networking = if cfg.socket != "" - then "-s ${cfg.socket}" - else "-l ${cfg.listen} -p ${toString cfg.port}"; - in "${memcached}/bin/memcached ${networking} -m ${toString cfg.maxMemory} -c ${toString cfg.maxConnections} ${concatStringsSep " " cfg.extraOptions}"; - - User = cfg.user; - }; + systemd.services.memcached = { + description = "Memcached server"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + PermissionsStartOnly = true; + ExecStartPre = optionals cfg.enableUnixSocket [ + "${pkgs.coreutils}/bin/install -d -o ${cfg.user} /run/memcached/" + "${pkgs.coreutils}/bin/chown -R ${cfg.user} /run/memcached/" + ]; + ExecStart = + let + networking = if cfg.enableUnixSocket + then "-s /run/memcached/memcached.sock" + else "-l ${cfg.listen} -p ${toString cfg.port}"; + in "${memcached}/bin/memcached ${networking} -m ${toString cfg.maxMemory} -c ${toString cfg.maxConnections} ${concatStringsSep " " cfg.extraOptions}"; + + User = cfg.user; }; + }; }; + imports = [ + (mkRemovedOptionModule ["services" "memcached" "socket"] '' + This option was replaced by a fixed unix socket path at /run/memcached/memcached.sock enabled using services.memached.enableUnixSocket. + '') + ]; } diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index a3bf4f9ba925..5b7390503552 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -7,14 +7,12 @@ let cfg = config.services.mysql; mysql = cfg.package; - - isMariaDB = + + isMariaDB = let pName = _p: (builtins.parseDrvName (_p.name)).name; in pName mysql == pName pkgs.mariadb; - atLeast55 = versionAtLeast mysql.mysqlVersion "5.5"; - pidFile = "${cfg.pidDir}/mysqld.pid"; mysqldOptions = @@ -28,13 +26,6 @@ let ${optionalString (cfg.bind != null) "bind-address = ${cfg.bind}" } ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "log-bin=mysql-bin"} ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "server-id = ${toString cfg.replication.serverId}"} - ${optionalString (cfg.replication.role == "slave" && !atLeast55) - '' - master-host = ${cfg.replication.masterHost} - master-user = ${cfg.replication.masterUser} - master-password = ${cfg.replication.masterPassword} - master-port = ${toString cfg.replication.masterPort} - ''} ${optionalString (cfg.ensureUsers != []) '' plugin-load-add = auth_socket.so @@ -298,10 +289,10 @@ in # Create initial databases if ! test -e "${cfg.dataDir}/${database.name}"; then echo "Creating initial database: ${database.name}" - ( echo "create database ${database.name};" + ( echo "create database `${database.name}`;" ${optionalString (database ? "schema") '' - echo "use ${database.name};" + echo "use `${database.name}`;" if [ -f "${database.schema}" ] then @@ -315,7 +306,7 @@ in fi '') cfg.initialDatabases} - ${optionalString (cfg.replication.role == "master" && atLeast55) + ${optionalString (cfg.replication.role == "master") '' # Set up the replication master @@ -326,7 +317,7 @@ in ) | ${mysql}/bin/mysql -u root -N ''} - ${optionalString (cfg.replication.role == "slave" && atLeast55) + ${optionalString (cfg.replication.role == "slave") '' # Set up the replication slave diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index a039ad138f6f..e4e38a4364a0 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -219,7 +219,6 @@ in users.extraUsers.redis = { name = cfg.user; - uid = config.ids.uids.redis; description = "Redis database user"; }; diff --git a/nixos/modules/services/desktops/gnome3/at-spi2-core.nix b/nixos/modules/services/desktops/gnome3/at-spi2-core.nix index 55ed2d9ee21b..9e382241348b 100644 --- a/nixos/modules/services/desktops/gnome3/at-spi2-core.nix +++ b/nixos/modules/services/desktops/gnome3/at-spi2-core.nix @@ -28,14 +28,15 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.at-spi2-core.enable { - - environment.systemPackages = [ pkgs.at_spi2_core ]; - - services.dbus.packages = [ pkgs.at_spi2_core ]; - - systemd.packages = [ pkgs.at_spi2_core ]; - - }; - + config = mkMerge [ + (mkIf config.services.gnome3.at-spi2-core.enable { + environment.systemPackages = [ pkgs.at_spi2_core ]; + services.dbus.packages = [ pkgs.at_spi2_core ]; + systemd.packages = [ pkgs.at_spi2_core ]; + }) + + (mkIf (!config.services.gnome3.at-spi2-core.enable) { + environment.variables.NO_AT_BRIDGE = "1"; + }) + ]; } diff --git a/nixos/modules/services/desktops/gnome3/chrome-gnome-shell.nix b/nixos/modules/services/desktops/gnome3/chrome-gnome-shell.nix new file mode 100644 index 000000000000..2740a22c7ca0 --- /dev/null +++ b/nixos/modules/services/desktops/gnome3/chrome-gnome-shell.nix @@ -0,0 +1,27 @@ +# Chrome GNOME Shell native host connector. +{ config, lib, pkgs, ... }: + +with lib; + +{ + ###### interface + options = { + services.gnome3.chrome-gnome-shell.enable = mkEnableOption '' + Chrome GNOME Shell native host connector, a DBus service + allowing to install GNOME Shell extensions from a web browser. + ''; + }; + + + ###### implementation + config = mkIf config.services.gnome3.chrome-gnome-shell.enable { + environment.etc = { + "chromium/native-messaging-hosts/org.gnome.chrome_gnome_shell.json".source = "${pkgs.chrome-gnome-shell}/etc/chromium/native-messaging-hosts/org.gnome.chrome_gnome_shell.json"; + "opt/chrome/native-messaging-hosts/org.gnome.chrome_gnome_shell.json".source = "${pkgs.chrome-gnome-shell}/etc/opt/chrome/native-messaging-hosts/org.gnome.chrome_gnome_shell.json"; + }; + + environment.systemPackages = [ pkgs.chrome-gnome-shell ]; + + services.dbus.packages = [ pkgs.chrome-gnome-shell ]; + }; +} diff --git a/nixos/modules/services/desktops/gnome3/tracker-miners.nix b/nixos/modules/services/desktops/gnome3/tracker-miners.nix new file mode 100644 index 000000000000..20154fc2fed3 --- /dev/null +++ b/nixos/modules/services/desktops/gnome3/tracker-miners.nix @@ -0,0 +1,41 @@ +# Tracker Miners daemons. + +{ config, pkgs, lib, ... }: + +with lib; + +{ + + ###### interface + + options = { + + services.gnome3.tracker-miners = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable Tracker miners, indexing services for Tracker + search engine and metadata storage system. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.gnome3.tracker-miners.enable { + + environment.systemPackages = [ pkgs.gnome3.tracker-miners ]; + + services.dbus.packages = [ pkgs.gnome3.tracker-miners ]; + + systemd.packages = [ pkgs.gnome3.tracker-miners ]; + + }; + +} diff --git a/nixos/modules/services/desktops/pipewire.nix b/nixos/modules/services/desktops/pipewire.nix new file mode 100644 index 000000000000..263a06156f84 --- /dev/null +++ b/nixos/modules/services/desktops/pipewire.nix @@ -0,0 +1,23 @@ +# pipewire service. +{ config, lib, pkgs, ... }: + +with lib; + +{ + ###### interface + options = { + services.pipewire = { + enable = mkEnableOption "pipewire service"; + }; + }; + + + ###### implementation + config = mkIf config.services.pipewire.enable { + environment.systemPackages = [ pkgs.pipewire ]; + + systemd.packages = [ pkgs.pipewire ]; + }; + + meta.maintainers = with lib.maintainers; [ jtojnar ]; +} diff --git a/nixos/modules/services/games/factorio.nix b/nixos/modules/services/games/factorio.nix index 1dc8ce93a0e5..3f6bf9de8931 100644 --- a/nixos/modules/services/games/factorio.nix +++ b/nixos/modules/services/games/factorio.nix @@ -6,7 +6,7 @@ let cfg = config.services.factorio; factorio = pkgs.factorio-headless; name = "Factorio"; - stateDir = "/var/lib/factorio"; + stateDir = cfg.stateDir; mkSavePath = name: "${stateDir}/saves/${name}.zip"; configFile = pkgs.writeText "factorio.conf" '' use-system-read-write-data-directories=true @@ -25,7 +25,7 @@ let password = cfg.password; token = cfg.token; game_password = cfg.game-password; - require_user_verification = true; + require_user_verification = cfg.requireUserVerification; max_upload_in_kilobytes_per_second = 0; minimum_latency_in_ticks = 0; ignore_player_limit_for_returning_players = false; @@ -80,6 +80,15 @@ in customizations. ''; }; + stateDir = mkOption { + type = types.path; + default = "/var/lib/factorio"; + description = '' + The server's data directory. + + The configuration and map will be stored here. + ''; + }; mods = mkOption { type = types.listOf types.package; default = []; @@ -148,6 +157,13 @@ in Game password. ''; }; + requireUserVerification = mkOption { + type = types.bool; + default = true; + description = '' + When set to true, the server will only allow clients that have a valid factorio.com account. + ''; + }; autosave-interval = mkOption { type = types.nullOr types.int; default = null; diff --git a/nixos/modules/services/games/ghost-one.nix b/nixos/modules/services/games/ghost-one.nix deleted file mode 100644 index 71ff6bb2f3f0..000000000000 --- a/nixos/modules/services/games/ghost-one.nix +++ /dev/null @@ -1,105 +0,0 @@ -{ config, lib, pkgs, ... }: -with lib; -let - - cfg = config.services.ghostOne; - ghostUser = "ghostone"; - stateDir = "/var/lib/ghost-one"; - -in -{ - - ###### interface - - options = { - services.ghostOne = { - - enable = mkOption { - default = false; - description = "Enable Ghost-One Warcraft3 game hosting server."; - }; - - language = mkOption { - default = "English"; - type = types.enum [ "English" "Spanish" "Russian" "Serbian" "Turkish" ]; - description = "The language of bot messages: English, Spanish, Russian, Serbian or Turkish."; - }; - - war3path = mkOption { - default = ""; - description = '' - The path to your local Warcraft III directory, which must contain war3.exe, storm.dll, and game.dll. - ''; - }; - - mappath = mkOption { - default = ""; - description = '' - The path to the directory where you keep your map files. GHost One doesn't require - map files but if it has access to them it can send them to players and automatically - calculate most map config values. GHost One will search [bot_mappath + map_localpath] - for the map file (map_localpath is set in each map's config file). - ''; - }; - - config = mkOption { - default = ""; - description = "Extra configuration options."; - }; - - }; - }; - - ###### implementation - - config = mkIf cfg.enable { - - users.extraUsers = singleton - { name = ghostUser; - uid = config.ids.uids.ghostone; - description = "Ghost One game server user"; - home = stateDir; - }; - - users.extraGroups = singleton - { name = ghostUser; - gid = config.ids.gids.ghostone; - }; - - services.ghostOne.config = '' -# bot_log = /dev/stderr - bot_language = ${pkgs.ghostOne}/share/ghost-one/languages/${cfg.language}.cfg - bot_war3path = ${cfg.war3path} - - bot_mapcfgpath = mapcfgs - bot_savegamepath = savegames - bot_mappath = ${cfg.mappath} - bot_replaypath = replays - ''; - - systemd.services."ghost-one" = { - wantedBy = [ "multi-user.target" ]; - script = '' - mkdir -p ${stateDir} - cd ${stateDir} - chown ${ghostUser}:${ghostUser} . - - mkdir -p mapcfgs - chown ${ghostUser}:${ghostUser} mapcfgs - - mkdir -p replays - chown ${ghostUser}:${ghostUser} replays - - mkdir -p savegames - chown ${ghostUser}:${ghostUser} savegames - - ln -sf ${pkgs.writeText "ghost.cfg" cfg.config} ghost.cfg - ln -sf ${pkgs.ghostOne}/share/ghost-one/ip-to-country.csv - ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${ghostUser} \ - -c "LANG=C ${pkgs.ghostOne}/bin/ghost++" - ''; - }; - - }; - -} diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix index bb17c8859d84..f69706ebff34 100644 --- a/nixos/modules/services/hardware/acpid.nix +++ b/nixos/modules/services/hardware/acpid.nix @@ -31,7 +31,7 @@ let '' fn=$out/${name} echo "event=${handler.event}" > $fn - echo "action=${pkgs.writeScript "${name}.sh" (concatStringsSep "\n" [ "#! ${pkgs.bash}/bin/sh" handler.action ])}" >> $fn + echo "action=${pkgs.writeShellScriptBin "${name}.sh" handler.action }/bin/${name}.sh '%e'" >> $fn ''; in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // config.services.acpid.handlers)) } @@ -69,11 +69,33 @@ in }; }); - description = "Event handlers."; - default = {}; - example = { mute = { event = "button/mute.*"; action = "amixer set Master toggle"; }; }; - + description = '' + Event handlers. + <note><para> + Handler can be a single command. + </para></note> + ''; + default = {}; + example = { + ac-power = { + event = "ac_adapter/*"; + action = '' + vals=($1) # space separated string to array of multiple values + case ''${vals[3]} in + 00000000) + echo unplugged >> /tmp/acpi.log + ;; + 00000001) + echo plugged in >> /tmp/acpi.log + ;; + *) + echo unknown >> /tmp/acpi.log + ;; + esac + ''; + }; + }; }; powerEventCommands = mkOption { diff --git a/nixos/modules/services/hardware/amd-hybrid-graphics.nix b/nixos/modules/services/hardware/amd-hybrid-graphics.nix deleted file mode 100644 index b0f9ff56d1b2..000000000000 --- a/nixos/modules/services/hardware/amd-hybrid-graphics.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ config, pkgs, lib, ... }: - -{ - - ###### interface - - options = { - - hardware.amdHybridGraphics.disable = lib.mkOption { - default = false; - type = lib.types.bool; - description = '' - Completely disable the AMD graphics card and use the - integrated graphics processor instead. - ''; - }; - - }; - - - ###### implementation - - config = lib.mkIf config.hardware.amdHybridGraphics.disable { - systemd.services."amd-hybrid-graphics" = { - path = [ pkgs.bash ]; - description = "Disable AMD Card"; - after = [ "sys-kernel-debug.mount" ]; - before = [ "systemd-vconsole-setup.service" "display-manager.service" ]; - requires = [ "sys-kernel-debug.mount" "vgaswitcheroo.path" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${pkgs.bash}/bin/sh -c 'echo -e \"IGD\\nOFF\" > /sys/kernel/debug/vgaswitcheroo/switch'"; - ExecStop = "${pkgs.bash}/bin/sh -c 'echo ON >/sys/kernel/debug/vgaswitcheroo/switch'"; - }; - }; - systemd.paths."vgaswitcheroo" = { - pathConfig = { - PathExists = "/sys/kernel/debug/vgaswitcheroo/switch"; - Unit = "amd-hybrid-graphics.service"; - }; - wantedBy = ["multi-user.target"]; - }; - }; - -} diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix index 14113fe01bb4..1f4acd21eccf 100644 --- a/nixos/modules/services/hardware/fwupd.nix +++ b/nixos/modules/services/hardware/fwupd.nix @@ -87,4 +87,8 @@ in { "d /var/lib/fwupd 0755 root root -" ]; }; + + meta = { + maintainers = pkgs.fwupd.maintainers; + }; } diff --git a/nixos/modules/services/hardware/nvidia-optimus.nix b/nixos/modules/services/hardware/nvidia-optimus.nix index 9fe4021c4247..eb1713baa140 100644 --- a/nixos/modules/services/hardware/nvidia-optimus.nix +++ b/nixos/modules/services/hardware/nvidia-optimus.nix @@ -23,7 +23,7 @@ let kernel = config.boot.kernelPackages; in ###### implementation config = lib.mkIf config.hardware.nvidiaOptimus.disable { - boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb"]; + boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb" "nvidia-drm"]; boot.kernelModules = [ "bbswitch" ]; boot.extraModulePackages = [ kernel.bbswitch ]; diff --git a/nixos/modules/services/hardware/thinkfan.nix b/nixos/modules/services/hardware/thinkfan.nix index 018e82e58a3d..5a898631e090 100644 --- a/nixos/modules/services/hardware/thinkfan.nix +++ b/nixos/modules/services/hardware/thinkfan.nix @@ -55,7 +55,7 @@ in { enable = mkOption { default = false; description = '' - Whether to enable thinkfan, fan controller for ibm/lenovo thinkpads. + Whether to enable thinkfan, fan controller for IBM/Lenovo ThinkPads. ''; }; diff --git a/nixos/modules/services/hardware/u2f.nix b/nixos/modules/services/hardware/u2f.nix new file mode 100644 index 000000000000..bb4b2f05f890 --- /dev/null +++ b/nixos/modules/services/hardware/u2f.nix @@ -0,0 +1,23 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.hardware.u2f; +in { + options = { + hardware.u2f = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable U2F hardware support. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + services.udev.packages = [ pkgs.libu2f-host ]; + }; +} + diff --git a/nixos/modules/services/hardware/usbmuxd.nix b/nixos/modules/services/hardware/usbmuxd.nix new file mode 100644 index 000000000000..7ebd49fa01c2 --- /dev/null +++ b/nixos/modules/services/hardware/usbmuxd.nix @@ -0,0 +1,74 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + defaultUserGroup = "usbmux"; + apple = "05ac"; + + cfg = config.services.usbmuxd; + +in + +{ + options.services.usbmuxd = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the usbmuxd ("USB multiplexing daemon") service. This daemon is + in charge of multiplexing connections over USB to an iOS device. This is + needed for transferring data from and to iOS devices (see ifuse). Also + this may enable plug-n-play tethering for iPhones. + ''; + }; + + user = mkOption { + type = types.str; + default = defaultUserGroup; + description = '' + The user usbmuxd should use to run after startup. + ''; + }; + + group = mkOption { + type = types.str; + default = defaultUserGroup; + description = '' + The group usbmuxd should use to run after startup. + ''; + }; + }; + + config = mkIf cfg.enable { + + users.extraUsers = optional (cfg.user == defaultUserGroup) { + name = cfg.user; + description = "usbmuxd user"; + group = cfg.group; + }; + + users.extraGroups = optional (cfg.group == defaultUserGroup) { + name = cfg.group; + }; + + # Give usbmuxd permission for Apple devices + services.udev.extraRules = '' + SUBSYSTEM=="usb", ATTR{idVendor}=="${apple}", GROUP="${cfg.group}" + ''; + + systemd.services.usbmuxd = { + description = "usbmuxd"; + wantedBy = [ "multi-user.target" ]; + unitConfig.Documentation = "man:usbmuxd(8)"; + serviceConfig = { + # Trigger the udev rule manually. This doesn't require replugging the + # device when first enabling the option to get it to work + ExecStartPre = "${pkgs.libudev}/bin/udevadm trigger -s usb -a idVendor=${apple}"; + ExecStart = "${pkgs.usbmuxd}/bin/usbmuxd -U ${cfg.user} -f"; + }; + }; + + }; +} diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix index 2a8ac414720b..a4cab0c94cdc 100644 --- a/nixos/modules/services/logging/logcheck.nix +++ b/nixos/modules/services/logging/logcheck.nix @@ -8,7 +8,7 @@ let defaultRules = pkgs.runCommand "logcheck-default-rules" {} '' cp -prd ${pkgs.logcheck}/etc/logcheck $out chmod u+w $out - rm $out/logcheck.* + rm -r $out/logcheck.* ''; rulesDir = pkgs.symlinkJoin diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix index b4abd2cd7e5e..28d89a7463ab 100644 --- a/nixos/modules/services/logging/logstash.nix +++ b/nixos/modules/services/logging/logstash.nix @@ -103,7 +103,7 @@ in listenAddress = mkOption { type = types.str; - default = "0.0.0.0"; + default = "127.0.0.1"; description = "Address on which to start webserver."; }; diff --git a/nixos/modules/services/mail/clamsmtp.nix b/nixos/modules/services/mail/clamsmtp.nix new file mode 100644 index 000000000000..8f4f39aa7288 --- /dev/null +++ b/nixos/modules/services/mail/clamsmtp.nix @@ -0,0 +1,179 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.clamsmtp; + clamdSocket = "/run/clamav/clamd.ctl"; # See services/security/clamav.nix +in +{ + ##### interface + options = { + services.clamsmtp = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable clamsmtp."; + }; + + instances = mkOption { + description = "Instances of clamsmtp to run."; + type = types.listOf (types.submodule { options = { + action = mkOption { + type = types.enum [ "bounce" "drop" "pass" ]; + default = "drop"; + description = + '' + Action to take when a virus is detected. + + Note that viruses often spoof sender addresses, so bouncing is + in most cases not a good idea. + ''; + }; + + header = mkOption { + type = types.str; + default = ""; + example = "X-Virus-Scanned: ClamAV using ClamSMTP"; + description = + '' + A header to add to scanned messages. See clamsmtpd.conf(5) for + more details. Empty means no header. + ''; + }; + + keepAlives = mkOption { + type = types.int; + default = 0; + description = + '' + Number of seconds to wait between each NOOP sent to the sending + server. 0 to disable. + + This is meant for slow servers where the sending MTA times out + waiting for clamd to scan the file. + ''; + }; + + listen = mkOption { + type = types.str; + example = "127.0.0.1:10025"; + description = + '' + Address to wait for incoming SMTP connections on. See + clamsmtpd.conf(5) for more details. + ''; + }; + + quarantine = mkOption { + type = types.bool; + default = false; + description = + '' + Whether to quarantine files that contain viruses by leaving them + in the temporary directory. + ''; + }; + + maxConnections = mkOption { + type = types.int; + default = 64; + description = "Maximum number of connections to accept at once."; + }; + + outAddress = mkOption { + type = types.str; + description = + '' + Address of the SMTP server to send email to once it has been + scanned. + ''; + }; + + tempDirectory = mkOption { + type = types.str; + default = "/tmp"; + description = + '' + Temporary directory that needs to be accessible to both clamd + and clamsmtpd. + ''; + }; + + timeout = mkOption { + type = types.int; + default = 180; + description = "Time-out for network connections."; + }; + + transparentProxy = mkOption { + type = types.bool; + default = false; + description = "Enable clamsmtp's transparent proxy support."; + }; + + virusAction = mkOption { + type = with types; nullOr path; + default = null; + description = + '' + Command to run when a virus is found. Please see VIRUS ACTION in + clamsmtpd(8) for a discussion of this option and its safe use. + ''; + }; + + xClient = mkOption { + type = types.bool; + default = false; + description = + '' + Send the XCLIENT command to the receiving server, for forwarding + client addresses and connection information if the receiving + server supports this feature. + ''; + }; + };}); + }; + }; + }; + + ##### implementation + config = let + configfile = conf: pkgs.writeText "clamsmtpd.conf" + '' + Action: ${conf.action} + ClamAddress: ${clamdSocket} + Header: ${conf.header} + KeepAlives: ${toString conf.keepAlives} + Listen: ${conf.listen} + Quarantine: ${if conf.quarantine then "on" else "off"} + MaxConnections: ${toString conf.maxConnections} + OutAddress: ${conf.outAddress} + TempDirectory: ${conf.tempDirectory} + TimeOut: ${toString conf.timeout} + TransparentProxy: ${if conf.transparentProxy then "on" else "off"} + User: clamav + ${optionalString (conf.virusAction != null) "VirusAction: ${conf.virusAction}"} + XClient: ${if conf.xClient then "on" else "off"} + ''; + in + mkIf cfg.enable { + assertions = [ + { assertion = config.services.clamav.daemon.enable; + message = "clamsmtp requires clamav to be enabled"; + } + ]; + + systemd.services = listToAttrs (imap1 (i: conf: + nameValuePair "clamsmtp-${toString i}" { + description = "ClamSMTP instance ${toString i}"; + wantedBy = [ "multi-user.target" ]; + script = "exec ${pkgs.clamsmtp}/bin/clamsmtpd -f ${configfile conf}"; + after = [ "clamav-daemon.service" ]; + requires = [ "clamav-daemon.service" ]; + serviceConfig.Type = "forking"; + serviceConfig.PrivateTmp = "yes"; + unitConfig.JoinsNamespaceOf = "clamav-daemon.service"; + } + ) cfg.instances); + }; +} diff --git a/nixos/modules/services/mail/dkimproxy-out.nix b/nixos/modules/services/mail/dkimproxy-out.nix new file mode 100644 index 000000000000..894b88e25c1b --- /dev/null +++ b/nixos/modules/services/mail/dkimproxy-out.nix @@ -0,0 +1,118 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.dkimproxy-out; + keydir = "/var/lib/dkimproxy-out"; + privkey = "${keydir}/private.key"; + pubkey = "${keydir}/public.key"; +in +{ + ##### interface + options = { + services.dkimproxy-out = { + enable = mkOption { + type = types.bool; + default = false; + description = + '' + Whether to enable dkimproxy_out. + + Note that a key will be auto-generated, and can be found in + ${keydir}. + ''; + }; + + listen = mkOption { + type = types.str; + example = "127.0.0.1:10027"; + description = "Address:port DKIMproxy should listen on."; + }; + + relay = mkOption { + type = types.str; + example = "127.0.0.1:10028"; + description = "Address:port DKIMproxy should forward mail to."; + }; + + domains = mkOption { + type = with types; listOf str; + example = [ "example.org" "example.com" ]; + description = "List of domains DKIMproxy can sign for."; + }; + + selector = mkOption { + type = types.str; + example = "selector1"; + description = + '' + The selector to use for DKIM key identification. + + For example, if 'selector1' is used here, then for each domain + 'example.org' given in `domain`, 'selector1._domainkey.example.org' + should contain the TXT record indicating the public key is the one + in ${pubkey}: "v=DKIM1; t=s; p=[THE PUBLIC KEY]". + ''; + }; + + keySize = mkOption { + type = types.int; + default = 2048; + description = + '' + Size of the RSA key to use to sign outgoing emails. Note that the + maximum mandatorily verified as per RFC6376 is 2048. + ''; + }; + + # TODO: allow signature for other schemes than dkim(c=relaxed/relaxed)? + # This being the scheme used by gmail, maybe nothing more is needed for + # reasonable use. + }; + }; + + ##### implementation + config = let + configfile = pkgs.writeText "dkimproxy_out.conf" + '' + listen ${cfg.listen} + relay ${cfg.relay} + + domain ${concatStringsSep "," cfg.domains} + selector ${cfg.selector} + + signature dkim(c=relaxed/relaxed) + + keyfile ${privkey} + ''; + in + mkIf cfg.enable { + users.groups.dkimproxy-out = {}; + users.users.dkimproxy-out = { + description = "DKIMproxy_out daemon"; + group = "dkimproxy-out"; + isSystemUser = true; + }; + + systemd.services.dkimproxy-out = { + description = "DKIMproxy_out"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + if [ ! -d "${keydir}" ]; then + mkdir -p "${keydir}" + chmod 0700 "${keydir}" + ${pkgs.openssl}/bin/openssl genrsa -out "${privkey}" ${toString cfg.keySize} + ${pkgs.openssl}/bin/openssl rsa -in "${privkey}" -pubout -out "${pubkey}" + chown -R dkimproxy-out:dkimproxy-out "${keydir}" + fi + ''; + script = '' + exec ${pkgs.dkimproxy}/bin/dkimproxy.out --conf_file=${configfile} + ''; + serviceConfig = { + User = "dkimproxy-out"; + PermissionsStartOnly = true; + }; + }; + }; +} diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index 18101a312254..b42c73b86668 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -104,7 +104,7 @@ let }; mailboxConfig = mailbox: '' - mailbox ${mailbox.name} { + mailbox "${mailbox.name}" { auto = ${toString mailbox.auto} '' + optionalString (mailbox.specialUse != null) '' special_use = \${toString mailbox.specialUse} @@ -113,7 +113,7 @@ let mailboxes = { lib, pkgs, ... }: { options = { name = mkOption { - type = types.str; + type = types.strMatching ''[^"]+''; example = "Spam"; description = "The name of the mailbox."; }; diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index 867c0ea6761c..5ab331ac067f 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -15,20 +15,18 @@ let haveVirtual = cfg.virtual != ""; clientAccess = - if (cfg.dnsBlacklistOverrides != "") - then [ "check_client_access hash:/etc/postfix/client_access" ] - else []; + optional (cfg.dnsBlacklistOverrides != "") + "check_client_access hash:/etc/postfix/client_access"; dnsBl = - if (cfg.dnsBlacklists != []) - then [ (concatStringsSep ", " (map (s: "reject_rbl_client " + s) cfg.dnsBlacklists)) ] - else []; + optionals (cfg.dnsBlacklists != []) + (map (s: "reject_rbl_client " + s) cfg.dnsBlacklists); clientRestrictions = concatStringsSep ", " (clientAccess ++ dnsBl); mainCf = let escape = replaceStrings ["$"] ["$$"]; - mkList = items: "\n " + concatStringsSep "\n " items; + mkList = items: "\n " + concatStringsSep ",\n " items; mkVal = value: if isList value then mkList value else " " + (if value == true then "yes" @@ -36,72 +34,9 @@ let else toString value); mkEntry = name: value: "${escape name} =${mkVal value}"; in - concatStringsSep "\n" (mapAttrsToList mkEntry (recursiveUpdate defaultConf cfg.config)) + concatStringsSep "\n" (mapAttrsToList mkEntry cfg.config) + "\n" + cfg.extraConfig; - defaultConf = { - compatibility_level = "9999"; - mail_owner = user; - default_privs = "nobody"; - - # NixOS specific locations - data_directory = "/var/lib/postfix/data"; - queue_directory = "/var/lib/postfix/queue"; - - # Default location of everything in package - meta_directory = "${pkgs.postfix}/etc/postfix"; - command_directory = "${pkgs.postfix}/bin"; - sample_directory = "/etc/postfix"; - newaliases_path = "${pkgs.postfix}/bin/newaliases"; - mailq_path = "${pkgs.postfix}/bin/mailq"; - readme_directory = false; - sendmail_path = "${pkgs.postfix}/bin/sendmail"; - daemon_directory = "${pkgs.postfix}/libexec/postfix"; - manpage_directory = "${pkgs.postfix}/share/man"; - html_directory = "${pkgs.postfix}/share/postfix/doc/html"; - shlib_directory = false; - relayhost = if cfg.relayHost == "" then "" else - if cfg.lookupMX - then "${cfg.relayHost}:${toString cfg.relayPort}" - else "[${cfg.relayHost}]:${toString cfg.relayPort}"; - - mail_spool_directory = "/var/spool/mail/"; - setgid_group = setgidGroup; - } - // optionalAttrs config.networking.enableIPv6 { inet_protocols = "all"; } - // optionalAttrs (cfg.networks != null) { mynetworks = cfg.networks; } - // optionalAttrs (cfg.networksStyle != "") { mynetworks_style = cfg.networksStyle; } - // optionalAttrs (cfg.hostname != "") { myhostname = cfg.hostname; } - // optionalAttrs (cfg.domain != "") { mydomain = cfg.domain; } - // optionalAttrs (cfg.origin != "") { myorigin = cfg.origin; } - // optionalAttrs (cfg.destination != null) { mydestination = cfg.destination; } - // optionalAttrs (cfg.relayDomains != null) { relay_domains = cfg.relayDomains; } - // optionalAttrs (cfg.recipientDelimiter != "") { recipient_delimiter = cfg.recipientDelimiter; } - // optionalAttrs haveAliases { alias_maps = "${cfg.aliasMapType}:/etc/postfix/aliases"; } - // optionalAttrs haveTransport { transport_maps = "hash:/etc/postfix/transport"; } - // optionalAttrs haveVirtual { virtual_alias_maps = "${cfg.virtualMapType}:/etc/postfix/virtual"; } - // optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; } - // optionalAttrs cfg.useSrs { - sender_canonical_maps = "tcp:127.0.0.1:10001"; - sender_canonical_classes = "envelope_sender"; - recipient_canonical_maps = "tcp:127.0.0.1:10002"; - recipient_canonical_classes= "envelope_recipient"; - } - // optionalAttrs cfg.enableHeaderChecks { header_checks = "regexp:/etc/postfix/header_checks"; } - // optionalAttrs (cfg.sslCert != "") { - smtp_tls_CAfile = cfg.sslCACert; - smtp_tls_cert_file = cfg.sslCert; - smtp_tls_key_file = cfg.sslKey; - - smtp_use_tls = true; - - smtpd_tls_CAfile = cfg.sslCACert; - smtpd_tls_cert_file = cfg.sslCert; - smtpd_tls_key_file = cfg.sslKey; - - smtpd_use_tls = true; - }; - masterCfOptions = { options, config, name, ... }: { options = { name = mkOption { @@ -479,7 +414,10 @@ in postmasterAlias = mkOption { type = types.str; default = "root"; - description = "Who should receive postmaster e-mail."; + description = " + Who should receive postmaster e-mail. Multiple values can be added by + separating values with comma. + "; }; rootAlias = mkOption { @@ -487,6 +425,7 @@ in default = ""; description = " Who should receive root e-mail. Blank for no redirection. + Multiple values can be added by separating values with comma. "; }; @@ -507,7 +446,6 @@ in config = mkOption { type = with types; attrsOf (either bool (either str (listOf str))); - default = defaultConf; description = '' The main.cf configuration file as key value set. ''; @@ -749,6 +687,67 @@ in ''; }; + services.postfix.config = (mapAttrs (_: v: mkDefault v) { + compatibility_level = "9999"; + mail_owner = cfg.user; + default_privs = "nobody"; + + # NixOS specific locations + data_directory = "/var/lib/postfix/data"; + queue_directory = "/var/lib/postfix/queue"; + + # Default location of everything in package + meta_directory = "${pkgs.postfix}/etc/postfix"; + command_directory = "${pkgs.postfix}/bin"; + sample_directory = "/etc/postfix"; + newaliases_path = "${pkgs.postfix}/bin/newaliases"; + mailq_path = "${pkgs.postfix}/bin/mailq"; + readme_directory = false; + sendmail_path = "${pkgs.postfix}/bin/sendmail"; + daemon_directory = "${pkgs.postfix}/libexec/postfix"; + manpage_directory = "${pkgs.postfix}/share/man"; + html_directory = "${pkgs.postfix}/share/postfix/doc/html"; + shlib_directory = false; + mail_spool_directory = "/var/spool/mail/"; + setgid_group = cfg.setgidGroup; + }) + // optionalAttrs (cfg.relayHost != "") { relayhost = if cfg.lookupMX + then "${cfg.relayHost}:${toString cfg.relayPort}" + else "[${cfg.relayHost}]:${toString cfg.relayPort}"; } + // optionalAttrs config.networking.enableIPv6 { inet_protocols = mkDefault "all"; } + // optionalAttrs (cfg.networks != null) { mynetworks = cfg.networks; } + // optionalAttrs (cfg.networksStyle != "") { mynetworks_style = cfg.networksStyle; } + // optionalAttrs (cfg.hostname != "") { myhostname = cfg.hostname; } + // optionalAttrs (cfg.domain != "") { mydomain = cfg.domain; } + // optionalAttrs (cfg.origin != "") { myorigin = cfg.origin; } + // optionalAttrs (cfg.destination != null) { mydestination = cfg.destination; } + // optionalAttrs (cfg.relayDomains != null) { relay_domains = cfg.relayDomains; } + // optionalAttrs (cfg.recipientDelimiter != "") { recipient_delimiter = cfg.recipientDelimiter; } + // optionalAttrs haveAliases { alias_maps = [ "${cfg.aliasMapType}:/etc/postfix/aliases" ]; } + // optionalAttrs haveTransport { transport_maps = [ "hash:/etc/postfix/transport" ]; } + // optionalAttrs haveVirtual { virtual_alias_maps = [ "${cfg.virtualMapType}:/etc/postfix/virtual" ]; } + // optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; } + // optionalAttrs cfg.useSrs { + sender_canonical_maps = [ "tcp:127.0.0.1:10001" ]; + sender_canonical_classes = [ "envelope_sender" ]; + recipient_canonical_maps = [ "tcp:127.0.0.1:10002" ]; + recipient_canonical_classes = [ "envelope_recipient" ]; + } + // optionalAttrs cfg.enableHeaderChecks { header_checks = [ "regexp:/etc/postfix/header_checks" ]; } + // optionalAttrs (cfg.sslCert != "") { + smtp_tls_CAfile = cfg.sslCACert; + smtp_tls_cert_file = cfg.sslCert; + smtp_tls_key_file = cfg.sslKey; + + smtp_use_tls = true; + + smtpd_tls_CAfile = cfg.sslCACert; + smtpd_tls_cert_file = cfg.sslCert; + smtpd_tls_key_file = cfg.sslKey; + + smtpd_use_tls = true; + }; + services.postfix.masterConfig = { smtp_inet = { name = "smtp"; diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix index 6d403e448e04..09fb587e74b5 100644 --- a/nixos/modules/services/mail/rspamd.nix +++ b/nixos/modules/services/mail/rspamd.nix @@ -1,14 +1,152 @@ -{ config, lib, pkgs, ... }: +{ config, options, pkgs, lib, ... }: with lib; let cfg = config.services.rspamd; + opts = options.services.rspamd; - mkBindSockets = socks: concatStringsSep "\n" (map (each: " bind_socket = \"${each}\"") socks); + bindSocketOpts = {options, config, ... }: { + options = { + socket = mkOption { + type = types.str; + example = "localhost:11333"; + description = '' + Socket for this worker to listen on in a format acceptable by rspamd. + ''; + }; + mode = mkOption { + type = types.str; + default = "0644"; + description = "Mode to set on unix socket"; + }; + owner = mkOption { + type = types.str; + default = "${cfg.user}"; + description = "Owner to set on unix socket"; + }; + group = mkOption { + type = types.str; + default = "${cfg.group}"; + description = "Group to set on unix socket"; + }; + rawEntry = mkOption { + type = types.str; + internal = true; + }; + }; + config.rawEntry = let + maybeOption = option: + optionalString options.${option}.isDefined " ${option}=${config.${option}}"; + in + if (!(hasPrefix "/" config.socket)) then "${config.socket}" + else "${config.socket}${maybeOption "mode"}${maybeOption "owner"}${maybeOption "group"}"; + }; - rspamdConfFile = pkgs.writeText "rspamd.conf" + workerOpts = { name, ... }: { + options = { + enable = mkOption { + type = types.nullOr types.bool; + default = null; + description = "Whether to run the rspamd worker."; + }; + name = mkOption { + type = types.nullOr types.str; + default = name; + description = "Name of the worker"; + }; + type = mkOption { + type = types.nullOr (types.enum [ + "normal" "controller" "fuzzy_storage" "proxy" "lua" + ]); + description = "The type of this worker"; + }; + bindSockets = mkOption { + type = types.listOf (types.either types.str (types.submodule bindSocketOpts)); + default = []; + description = '' + List of sockets to listen, in format acceptable by rspamd + ''; + example = [{ + socket = "/run/rspamd.sock"; + mode = "0666"; + owner = "rspamd"; + } "*:11333"]; + apply = value: map (each: if (isString each) + then if (isUnixSocket each) + then {socket = each; owner = cfg.user; group = cfg.group; mode = "0644"; rawEntry = "${each}";} + else {socket = each; rawEntry = "${each}";} + else each) value; + }; + count = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Number of worker instances to run + ''; + }; + includes = mkOption { + type = types.listOf types.str; + default = []; + description = '' + List of files to include in configuration + ''; + }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = "Additional entries to put verbatim into worker section of rspamd config file."; + }; + }; + config = mkIf (name == "normal" || name == "controller" || name == "fuzzy") { + type = mkDefault name; + includes = mkDefault [ "$CONFDIR/worker-${name}.inc" ]; + bindSockets = mkDefault (if name == "normal" + then [{ + socket = "/run/rspamd/rspamd.sock"; + mode = "0660"; + owner = cfg.user; + group = cfg.group; + }] + else if name == "controller" + then [ "localhost:11334" ] + else [] ); + }; + }; + + indexOf = default: start: list: e: + if list == [] + then default + else if (head list) == e then start + else (indexOf default (start + (length (listenStreams (head list).socket))) (tail list) e); + + systemdSocket = indexOf (abort "Socket not found") 0 allSockets; + + isUnixSocket = socket: hasPrefix "/" (if (isString socket) then socket else socket.socket); + isPort = hasPrefix "*:"; + isIPv4Socket = hasPrefix "*v4:"; + isIPv6Socket = hasPrefix "*v6:"; + isLocalHost = hasPrefix "localhost:"; + listenStreams = socket: + if (isLocalHost socket) then + let port = (removePrefix "localhost:" socket); + in [ "127.0.0.1:${port}" ] ++ (if config.networking.enableIPv6 then ["[::1]:${port}"] else []) + else if (isIPv6Socket socket) then [removePrefix "*v6:" socket] + else if (isPort socket) then [removePrefix "*:" socket] + else if (isIPv4Socket socket) then + throw "error: IPv4 only socket not supported in rspamd with socket activation" + else if (length (splitString " " socket)) != 1 then + throw "error: string options not supported in rspamd with socket activation" + else [socket]; + + mkBindSockets = enabled: socks: concatStringsSep "\n " (flatten (map (each: + if cfg.socketActivation && enabled != false then + let systemd = (systemdSocket each); + in (imap (idx: e: "bind_socket = \"systemd:${toString (systemd + idx - 1)}\";") (listenStreams each.socket)) + else "bind_socket = \"${each.rawEntry}\";") socks)); + + rspamdConfFile = pkgs.writeText "rspamd.conf" '' .include "$CONFDIR/common.conf" @@ -22,17 +160,33 @@ let .include "$CONFDIR/logging.inc" } - worker { - ${mkBindSockets cfg.bindSocket} - .include "$CONFDIR/worker-normal.inc" - } + ${concatStringsSep "\n" (mapAttrsToList (name: value: '' + worker ${optionalString (value.name != "normal" && value.name != "controller") "${value.name}"} { + type = "${value.type}"; + ${optionalString (value.enable != null) + "enabled = ${if value.enable != false then "yes" else "no"};"} + ${mkBindSockets value.enable value.bindSockets} + ${optionalString (value.count != null) "count = ${toString value.count};"} + ${concatStringsSep "\n " (map (each: ".include \"${each}\"") value.includes)} + ${value.extraConfig} + } + '') cfg.workers)} - worker { - ${mkBindSockets cfg.bindUISocket} - .include "$CONFDIR/worker-controller.inc" - } + ${cfg.extraConfig} ''; + allMappedSockets = flatten (mapAttrsToList (name: value: + if value.enable != false + then imap (idx: each: { + name = "${name}"; + index = idx; + value = each; + }) value.bindSockets + else []) cfg.workers); + allSockets = map (e: e.value) allMappedSockets; + + allSocketNames = map (each: "rspamd-${each.name}-${toString each.index}.socket") allMappedSockets; + in { @@ -46,36 +200,52 @@ in enable = mkEnableOption "Whether to run the rspamd daemon."; debug = mkOption { + type = types.bool; default = false; description = "Whether to run the rspamd daemon in debug mode."; }; - bindSocket = mkOption { - type = types.listOf types.str; - default = [ - "/run/rspamd/rspamd.sock mode=0660 owner=${cfg.user} group=${cfg.group}" - ]; - defaultText = ''[ - "/run/rspamd/rspamd.sock mode=0660 owner=${cfg.user} group=${cfg.group}" - ]''; + socketActivation = mkOption { + type = types.bool; description = '' - List of sockets to listen, in format acceptable by rspamd + Enable systemd socket activation for rspamd. ''; - example = '' - bindSocket = [ - "/run/rspamd.sock mode=0666 owner=rspamd" - "*:11333" - ]; + }; + + workers = mkOption { + type = with types; attrsOf (submodule workerOpts); + description = '' + Attribute set of workers to start. + ''; + default = { + normal = {}; + controller = {}; + }; + example = literalExample '' + { + normal = { + includes = [ "$CONFDIR/worker-normal.inc" ]; + bindSockets = [{ + socket = "/run/rspamd/rspamd.sock"; + mode = "0660"; + owner = "${cfg.user}"; + group = "${cfg.group}"; + }]; + }; + controller = { + includes = [ "$CONFDIR/worker-controller.inc" ]; + bindSockets = [ "[::1]:11334" ]; + }; + } ''; }; - bindUISocket = mkOption { - type = types.listOf types.str; - default = [ - "localhost:11334" - ]; + extraConfig = mkOption { + type = types.lines; + default = ""; description = '' - List of sockets for web interface, in format acceptable by rspamd + Extra configuration to add at the end of the rspamd configuration + file. ''; }; @@ -102,6 +272,13 @@ in config = mkIf cfg.enable { + services.rspamd.socketActivation = mkDefault (!opts.bindSocket.isDefined && !opts.bindUISocket.isDefined); + + assertions = [ { + assertion = !cfg.socketActivation || !(opts.bindSocket.isDefined || opts.bindUISocket.isDefined); + message = "Can't use socketActivation for rspamd when using renamed bind socket options"; + } ]; + # Allow users to run 'rspamc' and 'rspamadm'. environment.systemPackages = [ pkgs.rspamd ]; @@ -117,17 +294,22 @@ in gid = config.ids.gids.rspamd; }; + environment.etc."rspamd.conf".source = rspamdConfFile; + systemd.services.rspamd = { description = "Rspamd Service"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + wantedBy = mkIf (!cfg.socketActivation) [ "multi-user.target" ]; + after = [ "network.target" ] ++ + (if cfg.socketActivation then allSocketNames else []); + requires = mkIf cfg.socketActivation allSocketNames; serviceConfig = { ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c ${rspamdConfFile} -f"; Restart = "always"; RuntimeDirectory = "rspamd"; PrivateTmp = true; + Sockets = mkIf cfg.socketActivation (concatStringsSep " " allSocketNames); }; preStart = '' @@ -135,5 +317,25 @@ in ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd ''; }; + systemd.sockets = mkIf cfg.socketActivation + (listToAttrs (map (each: { + name = "rspamd-${each.name}-${toString each.index}"; + value = { + description = "Rspamd socket ${toString each.index} for worker ${each.name}"; + wantedBy = [ "sockets.target" ]; + listenStreams = (listenStreams each.value.socket); + socketConfig = { + BindIPv6Only = mkIf (isIPv6Socket each.value.socket) "ipv6-only"; + Service = "rspamd.service"; + SocketUser = mkIf (isUnixSocket each.value.socket) each.value.owner; + SocketGroup = mkIf (isUnixSocket each.value.socket) each.value.group; + SocketMode = mkIf (isUnixSocket each.value.socket) each.value.mode; + }; + }; + }) allMappedSockets)); }; + imports = [ + (mkRenamedOptionModule [ "services" "rspamd" "bindSocket" ] [ "services" "rspamd" "workers" "normal" "bindSockets" ]) + (mkRenamedOptionModule [ "services" "rspamd" "bindUISocket" ] [ "services" "rspamd" "workers" "controller" "bindSockets" ]) + ]; } diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix index df44d0a54866..c5c41ad296da 100644 --- a/nixos/modules/services/misc/dysnomia.nix +++ b/nixos/modules/services/misc/dysnomia.nix @@ -192,9 +192,11 @@ in mysqlPassword = builtins.readFile (config.services.mysql.rootPassword); }; } - // lib.optionalAttrs (config.services.postgresql.enable && cfg.enableAuthentication) { postgresql-database = { - postgresqlUsername = "root"; - }; } + // lib.optionalAttrs (config.services.postgresql.enable) { postgresql-database = { + } // lib.optionalAttrs (cfg.enableAuthentication) { + postgresqlUsername = "postgres"; + }; + } // lib.optionalAttrs (config.services.tomcat.enable) { tomcat-webapplication = { tomcatPort = 8080; }; } diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 7b2b40e59232..9ed5875a0191 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -29,8 +29,12 @@ let gitalyToml = pkgs.writeText "gitaly.toml" '' socket_path = "${lib.escape ["\""] gitalySocket}" + bin_dir = "${cfg.packages.gitaly}/bin" prometheus_listen_addr = "localhost:9236" + [git] + bin_path = "${pkgs.git}/bin/git" + [gitaly-ruby] dir = "${cfg.packages.gitaly.ruby}" @@ -70,7 +74,7 @@ let secret_key_base: ${cfg.secrets.secret} otp_key_base: ${cfg.secrets.otp} db_key_base: ${cfg.secrets.db} - jws_private_key: ${builtins.toJSON cfg.secrets.jws} + openid_connect_signing_key: ${builtins.toJSON cfg.secrets.jws} ''; gitlabConfig = { @@ -104,6 +108,7 @@ let ldap.enabled = false; omniauth.enabled = false; shared.path = "${cfg.statePath}/shared"; + gitaly.client_path = "${cfg.packages.gitaly}/bin"; backup.path = "${cfg.backupPath}"; gitlab_shell = { path = "${cfg.packages.gitlab-shell}"; @@ -117,8 +122,6 @@ let }; git = { bin_path = "git"; - max_size = 20971520; # 20MB - timeout = 10; }; monitoring = { ip_whitelist = [ "127.0.0.0/8" "::1/128" ]; @@ -248,7 +251,6 @@ in { databasePassword = mkOption { type = types.str; - default = ""; description = "Gitlab database user password."; }; @@ -440,12 +442,6 @@ in { environment.systemPackages = [ pkgs.git gitlab-rake cfg.packages.gitlab-shell ]; - assertions = [ - { assertion = cfg.databasePassword != ""; - message = "databasePassword must be set"; - } - ]; - # Redis is required for the sidekiq queue runner. services.redis.enable = mkDefault true; # We use postgres as the main data store. @@ -496,7 +492,9 @@ in { after = [ "network.target" "gitlab.service" ]; wantedBy = [ "multi-user.target" ]; environment.HOME = gitlabEnv.HOME; - path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv ]; + environment.GEM_HOME = "${cfg.packages.gitaly.rubyEnv}/${ruby.gemPath}"; + environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH; + path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv ruby ]; serviceConfig = { #PermissionsStartOnly = true; # preStart must be run as root Type = "simple"; diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix index f395b9558b5a..6e60316d000c 100644 --- a/nixos/modules/services/misc/gitolite.nix +++ b/nixos/modules/services/misc/gitolite.nix @@ -207,7 +207,7 @@ in gitolite setup -pk ${pubkeyFile} fi if [ -n "${hooks}" ]; then - cp ${hooks} .gitolite/hooks/common/ + cp -f ${hooks} .gitolite/hooks/common/ chmod +x .gitolite/hooks/common/* fi gitolite setup # Upgrade if needed diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix index 81fb024f9094..0888221ab62f 100644 --- a/nixos/modules/services/misc/gollum.nix +++ b/nixos/modules/services/misc/gollum.nix @@ -32,6 +32,24 @@ in description = "Content of the configuration file"; }; + mathjax = mkOption { + type = types.bool; + default = false; + description = "Enable support for math rendering using MathJax"; + }; + + allowUploads = mkOption { + type = types.nullOr (types.enum [ "dir" "page" ]); + default = null; + description = "Enable uploads of external files"; + }; + + emoji = mkOption { + type = types.bool; + default = false; + description = "Parse and interpret emoji tags"; + }; + branch = mkOption { type = types.str; default = "master"; @@ -84,6 +102,9 @@ in --host ${cfg.address} \ --config ${builtins.toFile "gollum-config.rb" cfg.extraConfig} \ --ref ${cfg.branch} \ + ${optionalString cfg.mathjax "--mathjax"} \ + ${optionalString cfg.emoji "--emoji"} \ + ${optionalString (cfg.allowUploads != null) "--allow-uploads ${cfg.allowUploads}"} \ ${cfg.stateDir} ''; }; diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix new file mode 100644 index 000000000000..cc60a143fa6c --- /dev/null +++ b/nixos/modules/services/misc/home-assistant.nix @@ -0,0 +1,135 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.home-assistant; + + configFile = pkgs.writeText "configuration.yaml" (builtins.toJSON cfg.config); + + availableComponents = pkgs.home-assistant.availableComponents; + + # Given component "parentConfig.platform", returns whether config.parentConfig + # is a list containing a set with set.platform == "platform". + # + # For example, the component sensor.luftdaten is used as follows: + # config.sensor = [ { + # platform = "luftdaten"; + # ... + # } ]; + useComponentPlatform = component: + let + path = splitString "." component; + parentConfig = attrByPath (init path) null cfg.config; + platform = last path; + in isList parentConfig && any + (item: item.platform or null == platform) + parentConfig; + + # Returns whether component is used in config + useComponent = component: + hasAttrByPath (splitString "." component) cfg.config + || useComponentPlatform component; + + # List of components used in config + extraComponents = filter useComponent availableComponents; + + package = if cfg.autoExtraComponents + then (cfg.package.override { inherit extraComponents; }) + else cfg.package; + +in { + meta.maintainers = with maintainers; [ dotlambda ]; + + options.services.home-assistant = { + enable = mkEnableOption "Home Assistant"; + + configDir = mkOption { + default = "/var/lib/hass"; + type = types.path; + description = "The config directory, where your <filename>configuration.yaml</filename> is located."; + }; + + config = mkOption { + default = null; + type = with types; nullOr attrs; + example = literalExample '' + { + homeassistant = { + name = "Home"; + time_zone = "UTC"; + }; + frontend = { }; + http = { }; + feedreader.urls = [ "https://nixos.org/blogs.xml" ]; + } + ''; + description = '' + Your <filename>configuration.yaml</filename> as a Nix attribute set. + Beware that setting this option will delete your previous <filename>configuration.yaml</filename>. + ''; + }; + + package = mkOption { + default = pkgs.home-assistant; + defaultText = "pkgs.home-assistant"; + type = types.package; + example = literalExample '' + pkgs.home-assistant.override { + extraPackages = ps: with ps; [ colorlog ]; + } + ''; + description = '' + Home Assistant package to use. + Override <literal>extraPackages</literal> in order to add additional dependencies. + ''; + }; + + autoExtraComponents = mkOption { + default = true; + type = types.bool; + description = '' + If set to <literal>true</literal>, the components used in <literal>config</literal> + are set as the specified package's <literal>extraComponents</literal>. + This in turn adds all packaged dependencies to the derivation. + You might still see import errors in your log. + In this case, you will need to package the necessary dependencies yourself + or ask for someone else to package them. + If a dependency is packaged but not automatically added to this list, + you might need to specify it in <literal>extraPackages</literal>. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.home-assistant = { + description = "Home Assistant"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + preStart = lib.optionalString (cfg.config != null) '' + rm -f ${cfg.configDir}/configuration.yaml + ln -s ${configFile} ${cfg.configDir}/configuration.yaml + ''; + serviceConfig = { + ExecStart = '' + ${package}/bin/hass --config "${cfg.configDir}" + ''; + User = "hass"; + Group = "hass"; + Restart = "on-failure"; + ProtectSystem = "strict"; + ReadWritePaths = "${cfg.configDir}"; + PrivateTmp = true; + }; + }; + + users.extraUsers.hass = { + home = cfg.configDir; + createHome = true; + group = "hass"; + uid = config.ids.uids.hass; + }; + + users.extraGroups.hass.gid = config.ids.gids.hass; + }; +} diff --git a/nixos/modules/services/misc/logkeys.nix b/nixos/modules/services/misc/logkeys.nix index 6051c884465d..df0b3ae24c90 100644 --- a/nixos/modules/services/misc/logkeys.nix +++ b/nixos/modules/services/misc/logkeys.nix @@ -1,4 +1,4 @@ -{ config, lib, ... }: +{ config, lib, pkgs, ... }: with lib; diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix index 11463cf4500a..7e880ad09b89 100644 --- a/nixos/modules/services/misc/matrix-synapse.nix +++ b/nixos/modules/services/misc/matrix-synapse.nix @@ -4,6 +4,8 @@ with lib; let cfg = config.services.matrix-synapse; + pg = config.services.postgresql; + usePostgresql = cfg.database_type == "psycopg2"; logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig; mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${boolToString r.compress}}''; mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${boolToString l.tls}, x_forwarded: ${boolToString l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}''; @@ -38,7 +40,7 @@ database: { name: "${cfg.database_type}", args: { ${concatStringsSep ",\n " ( - mapAttrsToList (n: v: "\"${n}\": ${v}") cfg.database_args + mapAttrsToList (n: v: "\"${n}\": ${builtins.toJSON v}") cfg.database_args )} } } @@ -155,7 +157,7 @@ in { tls_certificate_path = mkOption { type = types.nullOr types.str; default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.crt"; + example = "${cfg.dataDir}/homeserver.tls.crt"; description = '' PEM encoded X509 certificate for TLS. You can replace the self-signed certificate that synapse @@ -167,7 +169,7 @@ in { tls_private_key_path = mkOption { type = types.nullOr types.str; default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.key"; + example = "${cfg.dataDir}/homeserver.tls.key"; description = '' PEM encoded private key for TLS. Specify null if synapse is not speaking TLS directly. @@ -176,7 +178,7 @@ in { tls_dh_params_path = mkOption { type = types.nullOr types.str; default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.dh"; + example = "${cfg.dataDir}/homeserver.tls.dh"; description = '' PEM dh parameters for ephemeral keys ''; @@ -184,6 +186,7 @@ in { server_name = mkOption { type = types.str; example = "example.com"; + default = config.networking.hostName; description = '' The domain name of the server, with optional explicit port. This is used by remote servers to connect to this server, @@ -339,16 +342,39 @@ in { }; database_type = mkOption { type = types.enum [ "sqlite3" "psycopg2" ]; - default = "sqlite3"; + default = if versionAtLeast config.system.stateVersion "18.03" + then "psycopg2" + else "sqlite3"; description = '' The database engine name. Can be sqlite or psycopg2. ''; }; + create_local_database = mkOption { + type = types.bool; + default = true; + description = '' + Whether to create a local database automatically. + ''; + }; + database_name = mkOption { + type = types.str; + default = "matrix-synapse"; + description = "Database name."; + }; + database_user = mkOption { + type = types.str; + default = "matrix-synapse"; + description = "Database user name."; + }; database_args = mkOption { type = types.attrs; default = { - database = "${cfg.dataDir}/homeserver.db"; - }; + sqlite3 = { database = "${cfg.dataDir}/homeserver.db"; }; + psycopg2 = { + user = cfg.database_user; + database = cfg.database_name; + }; + }."${cfg.database_type}"; description = '' Arguments to pass to the engine. ''; @@ -578,6 +604,18 @@ in { Extra config options for matrix-synapse. ''; }; + extraConfigFiles = mkOption { + type = types.listOf types.path; + default = []; + description = '' + Extra config files to include. + + The configuration files will be included based on the command line + argument --config-path. This allows to configure secrets without + having to go through the Nix store, e.g. based on deployment keys if + NixOPS is in use. + ''; + }; logConfig = mkOption { type = types.lines; default = readFile ./matrix-synapse-log_config.yaml; @@ -611,15 +649,36 @@ in { gid = config.ids.gids.matrix-synapse; } ]; + services.postgresql.enable = mkIf usePostgresql (mkDefault true); + systemd.services.matrix-synapse = { description = "Synapse Matrix homeserver"; - after = [ "network.target" ]; + after = [ "network.target" "postgresql.service" ]; wantedBy = [ "multi-user.target" ]; preStart = '' ${cfg.package}/bin/homeserver \ --config-path ${configFile} \ --keys-directory ${cfg.dataDir} \ --generate-keys + '' + optionalString (usePostgresql && cfg.create_local_database) '' + if ! test -e "${cfg.dataDir}/db-created"; then + ${pkgs.sudo}/bin/sudo -u ${pg.superUser} \ + ${pg.package}/bin/createuser \ + --login \ + --no-createdb \ + --no-createrole \ + --encrypted \ + ${cfg.database_user} + ${pkgs.sudo}/bin/sudo -u ${pg.superUser} \ + ${pg.package}/bin/createdb \ + --owner=${cfg.database_user} \ + --encoding=UTF8 \ + --lc-collate=C \ + --lc-ctype=C \ + --template=template0 \ + ${cfg.database_name} + touch "${cfg.dataDir}/db-created" + fi ''; serviceConfig = { Type = "simple"; @@ -627,7 +686,11 @@ in { Group = "matrix-synapse"; WorkingDirectory = cfg.dataDir; PermissionsStartOnly = true; - ExecStart = "${cfg.package}/bin/homeserver --config-path ${configFile} --keys-directory ${cfg.dataDir}"; + ExecStart = '' + ${cfg.package}/bin/homeserver \ + ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } + --keys-directory ${cfg.dataDir} + ''; Restart = "on-failure"; }; }; diff --git a/nixos/modules/services/misc/mbpfan.nix b/nixos/modules/services/misc/mbpfan.nix index 972d8b572d36..50f6f80ad00c 100644 --- a/nixos/modules/services/misc/mbpfan.nix +++ b/nixos/modules/services/misc/mbpfan.nix @@ -8,13 +8,7 @@ let in { options.services.mbpfan = { - enable = mkOption { - default = false; - type = types.bool; - description = '' - Whether to enable the mbpfan daemon. - ''; - }; + enable = mkEnableOption "mbpfan, fan controller daemon for Apple Macs and MacBooks"; package = mkOption { type = types.package; diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index beca820d2d60..a169b0f2c784 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -8,7 +8,7 @@ let nix = cfg.package.out; - isNix112 = versionAtLeast (getVersion nix) "1.12pre"; + isNix20 = versionAtLeast (getVersion nix) "2.0pre"; makeNixBuildUser = nr: { name = "nixbld${toString nr}"; @@ -26,32 +26,40 @@ let nixConf = let - # If we're using sandbox for builds, then provide /bin/sh in - # the sandbox as a bind-mount to bash. This means we also need to - # include the entire closure of bash. + # In Nix < 2.0, If we're using sandbox for builds, then provide + # /bin/sh in the sandbox as a bind-mount to bash. This means we + # also need to include the entire closure of bash. Nix >= 2.0 + # provides a /bin/sh by default. sh = pkgs.stdenv.shell; binshDeps = pkgs.writeReferencesToFile sh; in - pkgs.runCommand "nix.conf" {extraOptions = cfg.extraOptions; } '' - extraPaths=$(for i in $(cat ${binshDeps}); do if test -d $i; then echo $i; fi; done) + pkgs.runCommand "nix.conf" { extraOptions = cfg.extraOptions; inherit binshDeps; } '' + ${optionalString (!isNix20) '' + extraPaths=$(for i in $(cat binshDeps); do if test -d $i; then echo $i; fi; done) + ''} cat > $out <<END # WARNING: this file is generated from the nix.* options in # your NixOS configuration, typically # /etc/nixos/configuration.nix. Do not edit it! build-users-group = nixbld - build-max-jobs = ${toString (cfg.maxJobs)} - build-cores = ${toString (cfg.buildCores)} - build-use-sandbox = ${if (builtins.isBool cfg.useSandbox) then boolToString cfg.useSandbox else cfg.useSandbox} - build-sandbox-paths = ${toString cfg.sandboxPaths} /bin/sh=${sh} $(echo $extraPaths) - binary-caches = ${toString cfg.binaryCaches} - trusted-binary-caches = ${toString cfg.trustedBinaryCaches} - binary-cache-public-keys = ${toString cfg.binaryCachePublicKeys} + ${if isNix20 then "max-jobs" else "build-max-jobs"} = ${toString (cfg.maxJobs)} + ${if isNix20 then "cores" else "build-cores"} = ${toString (cfg.buildCores)} + ${if isNix20 then "sandbox" else "build-use-sandbox"} = ${if (builtins.isBool cfg.useSandbox) then boolToString cfg.useSandbox else cfg.useSandbox} + ${if isNix20 then "extra-sandbox-paths" else "build-sandbox-paths"} = ${toString cfg.sandboxPaths} ${optionalString (!isNix20) "/bin/sh=${sh} $(echo $extraPaths)"} + ${if isNix20 then "substituters" else "binary-caches"} = ${toString cfg.binaryCaches} + ${if isNix20 then "trusted-substituters" else "trusted-binary-caches"} = ${toString cfg.trustedBinaryCaches} + ${if isNix20 then "trusted-public-keys" else "binary-cache-public-keys"} = ${toString cfg.binaryCachePublicKeys} auto-optimise-store = ${boolToString cfg.autoOptimiseStore} - ${optionalString cfg.requireSignedBinaryCaches '' - signed-binary-caches = * + ${if isNix20 then '' + require-sigs = ${if cfg.requireSignedBinaryCaches then "true" else "false"} + '' else '' + signed-binary-caches = ${if cfg.requireSignedBinaryCaches then "*" else ""} ''} trusted-users = ${toString cfg.trustedUsers} allowed-users = ${toString cfg.allowedUsers} + ${optionalString (isNix20 && !cfg.distributedBuilds) '' + builders = + ''} $extraOptions END ''; @@ -377,8 +385,9 @@ in systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ]; systemd.services.nix-daemon = - { path = [ nix pkgs.openssl.bin pkgs.utillinux config.programs.ssh.package ] - ++ optionals cfg.distributedBuilds [ pkgs.gzip ]; + { path = [ nix pkgs.utillinux ] + ++ optionals cfg.distributedBuilds [ config.programs.ssh.package pkgs.gzip ] + ++ optionals (!isNix20) [ pkgs.openssl.bin ]; environment = cfg.envVars // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; } @@ -396,10 +405,9 @@ in }; nix.envVars = - { NIX_CONF_DIR = "/etc/nix"; - } + optionalAttrs (!isNix20) { + NIX_CONF_DIR = "/etc/nix"; - // optionalAttrs (!isNix112) { # Enable the copy-from-other-stores substituter, which allows # builds to be sped up by copying build results from remote # Nix stores. To do this, mount the remote file system on a @@ -407,12 +415,8 @@ in NIX_OTHER_STORES = "/run/nix/remote-stores/*/nix"; } - // optionalAttrs cfg.distributedBuilds { - NIX_BUILD_HOOK = - if isNix112 then - "${nix}/libexec/nix/build-remote" - else - "${nix}/libexec/nix/build-remote.pl"; + // optionalAttrs (cfg.distributedBuilds && !isNix20) { + NIX_BUILD_HOOK = "${nix}/libexec/nix/build-remote.pl"; }; # Set up the environment variables for running Nix. @@ -420,7 +424,7 @@ in { NIX_PATH = concatStringsSep ":" cfg.nixPath; }; - environment.extraInit = + environment.extraInit = optionalString (!isNix20) '' # Set up secure multi-user builds: non-root users build through the # Nix daemon. diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 41cadb4a6de0..5d0f2abd13a9 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -16,10 +16,10 @@ let It isn't perfect, but it seems to cover a vast majority of use cases. Caveat: even if the package is reached by a different means, the path above will be shown and not e.g. `${config.services.foo.package}`. */ - manual = import ../../../doc/manual { + manual = import ../../../doc/manual rec { inherit pkgs config; - version = config.system.nixosRelease; - revision = "release-${config.system.nixosRelease}"; + version = config.system.nixos.release; + revision = "release-${version}"; options = let scrubbedEval = evalModules { diff --git a/nixos/modules/services/misc/osrm.nix b/nixos/modules/services/misc/osrm.nix new file mode 100644 index 000000000000..7ec8b15906fc --- /dev/null +++ b/nixos/modules/services/misc/osrm.nix @@ -0,0 +1,85 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.osrm; +in + +{ + options.services.osrm = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable the OSRM service."; + }; + + address = mkOption { + type = types.str; + default = "0.0.0.0"; + description = "IP address on which the web server will listen."; + }; + + port = mkOption { + type = types.int; + default = 5000; + description = "Port on which the web server will run."; + }; + + threads = mkOption { + type = types.int; + default = 4; + description = "Number of threads to use."; + }; + + algorithm = mkOption { + type = types.enum [ "CH" "CoreCH" "MLD" ]; + default = "MLD"; + description = "Algorithm to use for the data. Must be one of CH, CoreCH, MLD"; + }; + + extraFlags = mkOption { + type = types.listOf types.str; + default = []; + example = [ "--max-table-size 1000" "--max-matching-size 1000" ]; + description = "Extra command line arguments passed to osrm-routed"; + }; + + dataFile = mkOption { + type = types.path; + example = "/var/lib/osrm/berlin-latest.osrm"; + description = "Data file location"; + }; + + }; + + config = mkIf cfg.enable { + + users.users.osrm = { + group = config.users.users.osrm.name; + description = "OSRM user"; + createHome = false; + }; + + users.groups.osrm = { }; + + systemd.services.osrm = { + description = "OSRM service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = config.users.extraUsers.osrm.name; + ExecStart = '' + ${pkgs.osrm-backend}/bin/osrm-routed \ + --ip ${cfg.address} \ + --port ${toString cfg.port} \ + --threads ${toString cfg.threads} \ + --algorithm ${cfg.algorithm} \ + ${toString cfg.extraFlags} \ + ${cfg.dataFile} + ''; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/ssm-agent.nix b/nixos/modules/services/misc/ssm-agent.nix index c1e1f0903539..a57fbca86fb6 100644 --- a/nixos/modules/services/misc/ssm-agent.nix +++ b/nixos/modules/services/misc/ssm-agent.nix @@ -12,7 +12,7 @@ let case "$1" in -i) echo "nixos";; - -r) echo "${config.system.nixosVersion}";; + -r) echo "${config.system.nixos.version}";; esac ''; in { diff --git a/nixos/modules/services/misc/xmr-stak.nix b/nixos/modules/services/misc/xmr-stak.nix new file mode 100644 index 000000000000..57f439365471 --- /dev/null +++ b/nixos/modules/services/misc/xmr-stak.nix @@ -0,0 +1,73 @@ +{ lib, config, pkgs, ... }: + +with lib; + +let + + cfg = config.services.xmr-stak; + + pkg = pkgs.xmr-stak.override { + inherit (cfg) openclSupport cudaSupport; + }; + + xmrConfArg = optionalString (cfg.configText != "") ("-c " + + pkgs.writeText "xmr-stak-config.txt" cfg.configText); + +in + +{ + options = { + services.xmr-stak = { + enable = mkEnableOption "xmr-stak miner"; + openclSupport = mkEnableOption "support for OpenCL (AMD/ATI graphics cards)"; + cudaSupport = mkEnableOption "support for CUDA (NVidia graphics cards)"; + + extraArgs = mkOption { + type = types.listOf types.str; + default = []; + example = [ "--noCPU" "--currency monero" ]; + description = "List of parameters to pass to xmr-stak."; + }; + + configText = mkOption { + type = types.lines; + default = ""; + example = '' + "currency" : "monero", + "pool_list" : + [ { "pool_address" : "pool.supportxmr.com:5555", + "wallet_address" : "<long-hash>", + "pool_password" : "minername", + "pool_weight" : 1, + }, + ], + ''; + description = '' + Verbatim xmr-stak config.txt. If empty, the <literal>-c</literal> + parameter will not be added to the xmr-stak command. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.xmr-stak = { + wantedBy = [ "multi-user.target" ]; + bindsTo = [ "network-online.target" ]; + after = [ "network-online.target" ]; + environment = mkIf cfg.cudaSupport { + LD_LIBRARY_PATH = "${pkgs.linuxPackages_latest.nvidia_x11}/lib"; + }; + script = '' + exec ${pkg}/bin/xmr-stak ${xmrConfArg} ${concatStringsSep " " cfg.extraArgs} + ''; + serviceConfig = let rootRequired = cfg.openclSupport || cfg.cudaSupport; in { + # xmr-stak generates cpu and/or gpu configuration files + WorkingDirectory = "/tmp"; + PrivateTmp = true; + DynamicUser = !rootRequired; + LimitMEMLOCK = toString (1024*1024); + }; + }; + }; +} diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix index d85b5e4ec507..91539592511c 100644 --- a/nixos/modules/services/misc/zookeeper.nix +++ b/nixos/modules/services/misc/zookeeper.nix @@ -106,10 +106,19 @@ in { ''; }; + package = mkOption { + description = "The zookeeper package to use"; + default = pkgs.zookeeper; + defaultText = "pkgs.zookeeper"; + type = types.package; + }; + }; config = mkIf cfg.enable { + environment.systemPackages = [cfg.package]; + systemd.services.zookeeper = { description = "Zookeeper Daemon"; wantedBy = [ "multi-user.target" ]; @@ -118,7 +127,7 @@ in { serviceConfig = { ExecStart = '' ${pkgs.jre}/bin/java \ - -cp "${pkgs.zookeeper}/lib/*:${pkgs.zookeeper}/${pkgs.zookeeper.name}.jar:${configDir}" \ + -cp "${cfg.package}/lib/*:${cfg.package}/${cfg.package.name}.jar:${configDir}" \ ${escapeShellArgs cfg.extraCmdLineOptions} \ -Dzookeeper.datadir.autocreate=false \ ${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \ diff --git a/nixos/modules/services/monitoring/fusion-inventory.nix b/nixos/modules/services/monitoring/fusion-inventory.nix index 1c00f3c299e9..c3b869e00880 100644 --- a/nixos/modules/services/monitoring/fusion-inventory.nix +++ b/nixos/modules/services/monitoring/fusion-inventory.nix @@ -55,9 +55,6 @@ in { description = "Fusion Inventory Agent"; wantedBy = [ "multi-user.target" ]; - environment = { - OPTIONS = "--no-category=software"; - }; serviceConfig = { ExecStart = "${pkgs.fusionInventory}/bin/fusioninventory-agent --conf-file=${configFile} --daemon --no-fork"; }; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 4fbacef788f9..d48b78ae6d02 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -111,7 +111,7 @@ in { type = mkOption { description = "Database type."; default = "sqlite3"; - type = types.enum ["mysql" "sqlite3" "postgresql"]; + type = types.enum ["mysql" "sqlite3" "postgres"]; }; host = mkOption { diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix index e1fde4fc9500..d23b329eeb25 100644 --- a/nixos/modules/services/monitoring/netdata.nix +++ b/nixos/modules/services/monitoring/netdata.nix @@ -5,18 +5,25 @@ with lib; let cfg = config.services.netdata; - configFile = pkgs.writeText "netdata.conf" cfg.configText; + wrappedPlugins = pkgs.runCommand "wrapped-plugins" {} '' + mkdir -p $out/libexec/netdata/plugins.d + ln -s /run/wrappers/bin/apps.plugin $out/libexec/netdata/plugins.d/apps.plugin + ''; + + localConfig = { + global = { + "plugins directory" = "${wrappedPlugins}/libexec/netdata/plugins.d ${pkgs.netdata}/libexec/netdata/plugins.d"; + }; + }; + mkConfig = generators.toINI {} (recursiveUpdate localConfig cfg.config); + configFile = pkgs.writeText "netdata.conf" (if cfg.configText != null then cfg.configText else mkConfig); defaultUser = "netdata"; in { options = { services.netdata = { - enable = mkOption { - default = false; - type = types.bool; - description = "Whether to enable netdata monitoring."; - }; + enable = mkEnableOption "netdata"; user = mkOption { type = types.str; @@ -31,9 +38,9 @@ in { }; configText = mkOption { - type = types.lines; - default = ""; - description = "netdata.conf configuration."; + type = types.nullOr types.lines; + description = "Verbatim netdata.conf, cannot be combined with config."; + default = null; example = '' [global] debug log = syslog @@ -42,11 +49,29 @@ in { ''; }; + config = mkOption { + type = types.attrsOf types.attrs; + default = {}; + description = "netdata.conf configuration as nix attributes. cannot be combined with configText."; + example = literalExample '' + global = { + "debug log" = "syslog"; + "access log" = "syslog"; + "error log" = "syslog"; + }; + ''; + }; + }; }; - }; config = mkIf cfg.enable { + assertions = + [ { assertion = cfg.config != {} -> cfg.configText == null ; + message = "Cannot specify both config and configText"; + } + ]; systemd.services.netdata = { + path = with pkgs; [ gawk curl ]; description = "Real time performance monitoring"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; @@ -66,6 +91,15 @@ in { }; }; + security.wrappers."apps.plugin" = { + source = "${pkgs.netdata}/libexec/netdata/plugins.d/apps.plugin"; + capabilities = "cap_dac_read_search,cap_sys_ptrace+ep"; + owner = cfg.user; + group = cfg.group; + permissions = "u+rx,g+rx,o-rwx"; + }; + + users.extraUsers = optional (cfg.user == defaultUser) { name = defaultUser; }; diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix index cf761edad926..8a47c9f1e7d8 100644 --- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix +++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix @@ -111,11 +111,11 @@ in { after = [ "network.target" ]; script = '' ${pkgs.prometheus-alertmanager.bin}/bin/alertmanager \ - -config.file ${alertmanagerYml} \ - -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ - -log.level ${cfg.logLevel} \ - ${optionalString (cfg.webExternalUrl != null) ''-web.external-url ${cfg.webExternalUrl} \''} - ${optionalString (cfg.logFormat != null) "-log.format ${cfg.logFormat}"} + --config.file ${alertmanagerYml} \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --log.level ${cfg.logLevel} \ + ${optionalString (cfg.webExternalUrl != null) ''--web.external-url ${cfg.webExternalUrl} \''} + ${optionalString (cfg.logFormat != null) "--log.format ${cfg.logFormat}"} ''; serviceConfig = { diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index 1d6940c516a9..b8d9e58a5a82 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -64,7 +64,7 @@ let "DEVICESCAN ${notifyOpts}${cfg.defaults.autodetected}"} ''; - smartdOpts = { name, ... }: { + smartdDeviceOpts = { name, ... }: { options = { @@ -108,6 +108,18 @@ in ''; }; + extraOptions = mkOption { + default = []; + type = types.listOf types.str; + example = ["-A /var/log/smartd/" "--interval=3600"]; + description = '' + Extra command-line options passed to the <literal>smartd</literal> + daemon on startup. + + (See <literal>man 8 smartd</literal>.) + ''; + }; + notifications = { mail = { @@ -197,7 +209,7 @@ in devices = mkOption { default = []; example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ]; - type = with types; listOf (submodule smartdOpts); + type = with types; listOf (submodule smartdDeviceOpts); description = "List of devices to monitor."; }; @@ -222,7 +234,7 @@ in path = [ pkgs.nettools ]; # for hostname and dnsdomanname calls in smartd - serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork --configfile=${smartdConf}"; + serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}"; }; }; diff --git a/nixos/modules/services/monitoring/statsd.nix b/nixos/modules/services/monitoring/statsd.nix index df2adb9f2766..7b0e9981cbb1 100644 --- a/nixos/modules/services/monitoring/statsd.nix +++ b/nixos/modules/services/monitoring/statsd.nix @@ -9,6 +9,12 @@ let isBuiltinBackend = name: builtins.elem name [ "graphite" "console" "repeater" ]; + backendsToPackages = let + mkMap = list: name: + if isBuiltinBackend name then list + else list ++ [ pkgs.nodePackages.${name} ]; + in foldl mkMap []; + configFile = pkgs.writeText "statsd.conf" '' { address: "${cfg.listenAddress}", @@ -27,13 +33,21 @@ let prettyprint: false }, log: { - backend: "syslog" + backend: "stdout" }, automaticConfigReload: false${optionalString (cfg.extraConfig != null) ","} ${cfg.extraConfig} } ''; + deps = pkgs.buildEnv { + name = "statsd-runtime-deps"; + pathsToLink = [ "/lib" ]; + ignoreCollisions = true; + + paths = backendsToPackages cfg.backends; + }; + in { @@ -42,11 +56,7 @@ in options.services.statsd = { - enable = mkOption { - description = "Whether to enable statsd stats aggregation service"; - default = false; - type = types.bool; - }; + enable = mkEnableOption "statsd"; listenAddress = mkOption { description = "Address that statsd listens on over UDP"; @@ -110,6 +120,11 @@ in config = mkIf cfg.enable { + assertions = map (backend: { + assertion = !isBuiltinBackend backend -> hasAttrByPath [ backend ] pkgs.nodePackages; + message = "Only builtin backends (graphite, console, repeater) or backends enumerated in `pkgs.nodePackages` are allowed!"; + }) cfg.backends; + users.extraUsers = singleton { name = "statsd"; uid = config.ids.uids.statsd; @@ -120,9 +135,7 @@ in description = "Statsd Server"; wantedBy = [ "multi-user.target" ]; environment = { - NODE_PATH=concatMapStringsSep ":" - (pkg: "${builtins.getAttr pkg pkgs.statsd.nodePackages}/lib/node_modules") - (filter (name: !isBuiltinBackend name) cfg.backends); + NODE_PATH = "${deps}/lib/node_modules"; }; serviceConfig = { ExecStart = "${pkgs.statsd}/bin/statsd ${configFile}"; diff --git a/nixos/modules/services/network-filesystems/beegfs.nix b/nixos/modules/services/network-filesystems/beegfs.nix new file mode 100644 index 000000000000..a6a2ec6cbc36 --- /dev/null +++ b/nixos/modules/services/network-filesystems/beegfs.nix @@ -0,0 +1,343 @@ +{ config, lib, pkgs, ...} : + +with lib; + +let + cfg = config.services.beegfs; + + # functions for the generations of config files + + configMgmtd = name: cfg: pkgs.writeText "mgmt-${name}.conf" '' + storeMgmtdDirectory = ${cfg.mgmtd.storeDir} + storeAllowFirstRunInit = false + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + + ${cfg.mgmtd.extraConfig} + ''; + + configAdmon = name: cfg: pkgs.writeText "admon-${name}.conf" '' + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + + ${cfg.admon.extraConfig} + ''; + + configMeta = name: cfg: pkgs.writeText "meta-${name}.conf" '' + storeMetaDirectory = ${cfg.meta.storeDir} + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + storeAllowFirstRunInit = false + + ${cfg.mgmtd.extraConfig} + ''; + + configStorage = name: cfg: pkgs.writeText "storage-${name}.conf" '' + storeStorageDirectory = ${cfg.storage.storeDir} + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + storeAllowFirstRunInit = false + + ${cfg.storage.extraConfig} + ''; + + configHelperd = name: cfg: pkgs.writeText "helperd-${name}.conf" '' + connAuthFile = ${cfg.connAuthFile} + ${cfg.helperd.extraConfig} + ''; + + configClientFilename = name : "/etc/beegfs/client-${name}.conf"; + + configClient = name: cfg: '' + sysMgmtdHost = ${cfg.mgmtdHost} + connAuthFile = ${cfg.connAuthFile} + connPortShift = ${toString cfg.connPortShift} + + ${cfg.client.extraConfig} + ''; + + serviceList = [ + { service = "admon"; cfgFile = configAdmon; } + { service = "meta"; cfgFile = configMeta; } + { service = "mgmtd"; cfgFile = configMgmtd; } + { service = "storage"; cfgFile = configStorage; } + ]; + + # functions to generate systemd.service entries + + systemdEntry = service: cfgFile: (mapAttrs' ( name: cfg: + (nameValuePair "beegfs-${service}-${name}" (mkIf cfg."${service}".enable { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" ]; + after = [ "network-online.target" ]; + serviceConfig = rec { + ExecStart = '' + ${pkgs.beegfs}/bin/beegfs-${service} \ + cfgFile=${cfgFile name cfg} \ + pidFile=${PIDFile} + ''; + PIDFile = "/run/beegfs-${service}-${name}.pid"; + TimeoutStopSec = "300"; + }; + }))) cfg); + + systemdHelperd = mapAttrs' ( name: cfg: + (nameValuePair "beegfs-helperd-${name}" (mkIf cfg.client.enable { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" ]; + after = [ "network-online.target" ]; + serviceConfig = rec { + ExecStart = '' + ${pkgs.beegfs}/bin/beegfs-helperd \ + cfgFile=${configHelperd name cfg} \ + pidFile=${PIDFile} + ''; + PIDFile = "/run/beegfs-helperd-${name}.pid"; + TimeoutStopSec = "300"; + }; + }))) cfg; + + # wrappers to beegfs tools. Avoid typing path of config files + utilWrappers = mapAttrsToList ( name: cfg: + ( pkgs.runCommand "beegfs-utils-${name}" { nativeBuildInputs = [ pkgs.makeWrapper ]; } '' + mkdir -p $out/bin + + makeWrapper ${pkgs.beegfs}/bin/beegfs-check-servers \ + $out/bin/beegfs-check-servers-${name} \ + --add-flags "-c ${configClientFilename name}" \ + --prefix PATH : ${lib.makeBinPath [ pkgs.beegfs ]} + + makeWrapper ${pkgs.beegfs}/bin/beegfs-ctl \ + $out/bin/beegfs-ctl-${name} \ + --add-flags "--cfgFile=${configClientFilename name}" + + makeWrapper ${pkgs.beegfs}/bin/beegfs-ctl \ + $out/bin/beegfs-df-${name} \ + --add-flags "--cfgFile=${configClientFilename name}" \ + --add-flags --listtargets \ + --add-flags --hidenodeid \ + --add-flags --pools \ + --add-flags --spaceinfo + + makeWrapper ${pkgs.beegfs}/bin/beegfs-fsck \ + $out/bin/beegfs-fsck-${name} \ + --add-flags "--cfgFile=${configClientFilename name}" + '' + )) cfg; +in +{ + ###### interface + + options = { + services.beegfsEnable = mkEnableOption "BeeGFS"; + + services.beegfs = mkOption { + default = {}; + description = '' + BeeGFS configurations. Every mount point requires a separate configuration. + ''; + type = with types; attrsOf (submodule ({ config, ... } : { + options = { + mgmtdHost = mkOption { + type = types.str; + default = null; + example = "master"; + description = ''Hostname of managament host.''; + }; + + connAuthFile = mkOption { + type = types.str; + default = ""; + example = "/etc/my.key"; + description = "File containing shared secret authentication."; + }; + + connPortShift = mkOption { + type = types.int; + default = 0; + example = 5; + description = '' + For each additional beegfs configuration shift all + service TCP/UDP ports by at least 5. + ''; + }; + + client = { + enable = mkEnableOption "BeeGFS client"; + + mount = mkOption { + type = types.bool; + default = true; + description = "Create fstab entry automatically"; + }; + + mountPoint = mkOption { + type = types.str; + default = "/run/beegfs"; + description = '' + Mount point under which the beegfs filesytem should be mounted. + If mounted manually the mount option specifing the config file is needed: + cfgFile=/etc/beegfs/beegfs-client-<name>.conf + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-client.conf. + See documentation for further details. + ''; + }; + }; + + helperd = { + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-helperd.conf. See documentation + for further details. + ''; + }; + }; + + mgmtd = { + enable = mkEnableOption "BeeGFS mgmtd daemon"; + + storeDir = mkOption { + type = types.path; + default = null; + example = "/data/beegfs-mgmtd"; + description = '' + Data directory for mgmtd. + Must not be shared with other beegfs daemons. + This directory must exist and it must be initialized + with beegfs-setup-mgmtd, e.g. "beegfs-setup-mgmtd -C -p <storeDir>" + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-mgmtd.conf. See documentation + for further details. + ''; + }; + }; + + admon = { + enable = mkEnableOption "BeeGFS admon daemon"; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional lines for beegfs-admon.conf. See documentation + for further details. + ''; + }; + }; + + meta = { + enable = mkEnableOption "BeeGFS meta data daemon"; + + storeDir = mkOption { + type = types.path; + default = null; + example = "/data/beegfs-meta"; + description = '' + Data directory for meta data service. + Must not be shared with other beegfs daemons. + The underlying filesystem must be mounted with xattr turned on. + This directory must exist and it must be initialized + with beegfs-setup-meta, e.g. + "beegfs-setup-meta -C -s <serviceID> -p <storeDir>" + ''; + }; + + extraConfig = mkOption { + type = types.str; + default = ""; + description = '' + Additional lines for beegfs-meta.conf. See documentation + for further details. + ''; + }; + }; + + storage = { + enable = mkEnableOption "BeeGFS storage daemon"; + + storeDir = mkOption { + type = types.path; + default = null; + example = "/data/beegfs-storage"; + description = '' + Data directories for storage service. + Must not be shared with other beegfs daemons. + The underlying filesystem must be mounted with xattr turned on. + This directory must exist and it must be initialized + with beegfs-setup-storage, e.g. + "beegfs-setup-storage -C -s <serviceID> -i <storageTargetID> -p <storeDir>" + ''; + }; + + extraConfig = mkOption { + type = types.str; + default = ""; + description = '' + Addional lines for beegfs-storage.conf. See documentation + for further details. + ''; + }; + }; + }; + })); + }; + }; + + ###### implementation + + config = + mkIf config.services.beegfsEnable { + + environment.systemPackages = utilWrappers; + + # Put the client.conf files in /etc since they are needed + # by the commandline tools + environment.etc = mapAttrs' ( name: cfg: + (nameValuePair "beegfs/client-${name}.conf" (mkIf (cfg.client.enable) + { + enable = true; + text = configClient name cfg; + }))) cfg; + + # Kernel module, we need it only once per host. + boot = mkIf ( + foldr (a: b: a || b) false + (map (x: x.client.enable) (collect (x: x ? client) cfg))) + { + kernelModules = [ "beegfs" ]; + extraModulePackages = [ pkgs.linuxPackages.beegfs-module ]; + }; + + # generate fstab entries + fileSystems = mapAttrs' (name: cfg: + (nameValuePair cfg.client.mountPoint (optionalAttrs cfg.client.mount (mkIf cfg.client.enable { + device = "beegfs_nodev"; + fsType = "beegfs"; + mountPoint = cfg.client.mountPoint; + options = [ "cfgFile=${configClientFilename name}" "_netdev" ]; + })))) cfg; + + # generate systemd services + systemd.services = systemdHelperd // + foldr (a: b: a // b) {} + (map (x: systemdEntry x.service x.cfgFile) serviceList); + }; +} diff --git a/nixos/modules/services/network-filesystems/davfs2.nix b/nixos/modules/services/network-filesystems/davfs2.nix new file mode 100644 index 000000000000..6b2a770100c5 --- /dev/null +++ b/nixos/modules/services/network-filesystems/davfs2.nix @@ -0,0 +1,74 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.davfs2; + cfgFile = pkgs.writeText "davfs2.conf" '' + dav_user ${cfg.davUser} + dav_group ${cfg.davGroup} + ${cfg.extraConfig} + ''; +in +{ + options.services.davfs2 = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable davfs2. + ''; + }; + + davUser = mkOption { + type = types.string; + default = "davfs2"; + description = '' + When invoked by root the mount.davfs daemon will run as this user. + Value must be given as name, not as numerical id. + ''; + }; + + davGroup = mkOption { + type = types.string; + default = "davfs2"; + description = '' + The group of the running mount.davfs daemon. Ordinary users must be + member of this group in order to mount a davfs2 file system. Value must + be given as name, not as numerical id. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = '' + kernel_fs coda + proxy foo.bar:8080 + use_locks 0 + ''; + description = '' + Extra lines appended to the configuration of davfs2. + '' ; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.davfs2 ]; + environment.etc."davfs2/davfs2.conf".source = cfgFile; + + users.extraGroups = optionalAttrs (cfg.davGroup == "davfs2") (singleton { + name = "davfs2"; + gid = config.ids.gids.davfs2; + }); + + users.extraUsers = optionalAttrs (cfg.davUser == "davfs2") (singleton { + name = "davfs2"; + createHome = false; + group = cfg.davGroup; + uid = config.ids.uids.davfs2; + description = "davfs2 user"; + }); + }; + +} diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix index d4a695ef5880..39a4fd6beff8 100644 --- a/nixos/modules/services/network-filesystems/ipfs.nix +++ b/nixos/modules/services/network-filesystems/ipfs.nix @@ -39,8 +39,6 @@ let # NB: migration must be performed prior to pre-start, else we get the failure message! preStart = '' ipfs repo fsck # workaround for BUG #4212 (https://github.com/ipfs/go-ipfs/issues/4214) - ipfs --local config Addresses.API ${cfg.apiAddress} - ipfs --local config Addresses.Gateway ${cfg.gatewayAddress} '' + optionalString cfg.autoMount '' ipfs --local config Mounts.FuseAllowOther --json true ipfs --local config Mounts.IPFS ${cfg.ipfsMountDir} @@ -56,7 +54,11 @@ let EOF ipfs --local config --json "${concatStringsSep "." path}" "$value" '') - cfg.extraConfig) + ({ Addresses.API = cfg.apiAddress; + Addresses.Gateway = cfg.gatewayAddress; + Addresses.Swarm = cfg.swarmAddress; + } // + cfg.extraConfig)) ); serviceConfig = { ExecStart = "${wrapped}/bin/ipfs daemon ${ipfsFlags}"; @@ -140,6 +142,12 @@ in { description = "Where IPFS exposes its API to"; }; + swarmAddress = mkOption { + type = types.listOf types.str; + default = [ "/ip4/0.0.0.0/tcp/4001" "/ip6/::/tcp/4001" ]; + description = "Where IPFS listens for incoming p2p connections"; + }; + enableGC = mkOption { type = types.bool; default = false; diff --git a/nixos/modules/services/network-filesystems/openafs-client/default.nix b/nixos/modules/services/network-filesystems/openafs-client/default.nix deleted file mode 100644 index 0946e379e796..000000000000 --- a/nixos/modules/services/network-filesystems/openafs-client/default.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ config, pkgs, lib, ... }: - -let - inherit (lib) mkOption mkIf; - - cfg = config.services.openafsClient; - - cellServDB = pkgs.fetchurl { - url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14; - sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; - }; - - afsConfig = pkgs.runCommand "afsconfig" {} '' - mkdir -p $out - echo ${cfg.cellName} > $out/ThisCell - cp ${cellServDB} $out/CellServDB - echo "/afs:${cfg.cacheDirectory}:${cfg.cacheSize}" > $out/cacheinfo - ''; - - openafsPkgs = config.boot.kernelPackages.openafsClient; -in -{ - ###### interface - - options = { - - services.openafsClient = { - - enable = mkOption { - default = false; - description = "Whether to enable the OpenAFS client."; - }; - - cellName = mkOption { - default = "grand.central.org"; - description = "Cell name."; - }; - - cacheSize = mkOption { - default = "100000"; - description = "Cache size."; - }; - - cacheDirectory = mkOption { - default = "/var/cache/openafs"; - description = "Cache directory."; - }; - - crypt = mkOption { - default = false; - description = "Whether to enable (weak) protocol encryption."; - }; - - sparse = mkOption { - default = false; - description = "Minimal cell list in /afs."; - }; - - }; - }; - - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ openafsPkgs ]; - - environment.etc = [ - { source = afsConfig; - target = "openafs"; - } - ]; - - systemd.services.afsd = { - description = "AFS client"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - serviceConfig = { RemainAfterExit = true; }; - - preStart = '' - mkdir -p -m 0755 /afs - mkdir -m 0700 -p ${cfg.cacheDirectory} - ${pkgs.kmod}/bin/insmod ${openafsPkgs}/lib/openafs/libafs-*.ko || true - ${openafsPkgs}/sbin/afsd -confdir ${afsConfig} -cachedir ${cfg.cacheDirectory} ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} -fakestat -afsdb - ${openafsPkgs}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} - ''; - - # Doing this in preStop, because after these commands AFS is basically - # stopped, so systemd has nothing to do, just noticing it. If done in - # postStop, then we get a hang + kernel oops, because AFS can't be - # stopped simply by sending signals to processes. - preStop = '' - ${pkgs.utillinux}/bin/umount /afs - ${openafsPkgs}/sbin/afsd -shutdown - ''; - }; - }; -} diff --git a/nixos/modules/services/network-filesystems/openafs/client.nix b/nixos/modules/services/network-filesystems/openafs/client.nix new file mode 100644 index 000000000000..3826fe3edfd0 --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/client.nix @@ -0,0 +1,239 @@ +{ config, pkgs, lib, ... }: + +with import ./lib.nix { inherit lib; }; + +let + inherit (lib) getBin mkOption mkIf optionalString singleton types; + + cfg = config.services.openafsClient; + + cellServDB = pkgs.fetchurl { + url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14; + sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; + }; + + clientServDB = pkgs.writeText "client-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.cellServDB); + + afsConfig = pkgs.runCommand "afsconfig" {} '' + mkdir -p $out + echo ${cfg.cellName} > $out/ThisCell + cat ${cellServDB} ${clientServDB} > $out/CellServDB + echo "${cfg.mountPoint}:${cfg.cache.directory}:${toString cfg.cache.blocks}" > $out/cacheinfo + ''; + + openafsMod = config.boot.kernelPackages.openafs; + openafsBin = lib.getBin pkgs.openafs; +in +{ + ###### interface + + options = { + + services.openafsClient = { + + enable = mkOption { + default = false; + type = types.bool; + description = "Whether to enable the OpenAFS client."; + }; + + afsdb = mkOption { + default = true; + type = types.bool; + description = "Resolve cells via AFSDB DNS records."; + }; + + cellName = mkOption { + default = ""; + type = types.str; + description = "Cell name."; + example = "grand.central.org"; + }; + + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule { options = cellServDBConfig; }); + description = '' + This cell's database server records, added to the global + CellServDB. See CellServDB(5) man page for syntax. Ignored when + <literal>afsdb</literal> is set to <literal>true</literal>. + ''; + example = '' + [ { ip = "1.2.3.4"; dnsname = "first.afsdb.server.dns.fqdn.org"; } + { ip = "2.3.4.5"; dnsname = "second.afsdb.server.dns.fqdn.org"; } + ] + ''; + }; + + cache = { + blocks = mkOption { + default = 100000; + type = types.int; + description = "Cache size in 1KB blocks."; + }; + + chunksize = mkOption { + default = 0; + type = types.ints.between 0 30; + description = '' + Size of each cache chunk given in powers of + 2. <literal>0</literal> resets the chunk size to its default + values (13 (8 KB) for memcache, 18-20 (256 KB to 1 MB) for + diskcache). Maximum value is 30. Important performance + parameter. Set to higher values when dealing with large files. + ''; + }; + + directory = mkOption { + default = "/var/cache/openafs"; + type = types.str; + description = "Cache directory."; + }; + + diskless = mkOption { + default = false; + type = types.bool; + description = '' + Use in-memory cache for diskless machines. Has no real + performance benefit anymore. + ''; + }; + }; + + crypt = mkOption { + default = true; + type = types.bool; + description = "Whether to enable (weak) protocol encryption."; + }; + + daemons = mkOption { + default = 2; + type = types.int; + description = '' + Number of daemons to serve user requests. Numbers higher than 6 + usually do no increase performance. Default is sufficient for up + to five concurrent users. + ''; + }; + + fakestat = mkOption { + default = false; + type = types.bool; + description = '' + Return fake data on stat() calls. If <literal>true</literal>, + always do so. If <literal>false</literal>, only do so for + cross-cell mounts (as these are potentially expensive). + ''; + }; + + inumcalc = mkOption { + default = "compat"; + type = types.strMatching "compat|md5"; + description = '' + Inode calculation method. <literal>compat</literal> is + computationally less expensive, but <literal>md5</literal> greatly + reduces the likelihood of inode collisions in larger scenarios + involving multiple cells mounted into one AFS space. + ''; + }; + + mountPoint = mkOption { + default = "/afs"; + type = types.str; + description = '' + Mountpoint of the AFS file tree, conventionally + <literal>/afs</literal>. When set to a different value, only + cross-cells that use the same value can be accessed. + ''; + }; + + sparse = mkOption { + default = true; + type = types.bool; + description = "Minimal cell list in /afs."; + }; + + startDisconnected = mkOption { + default = false; + type = types.bool; + description = '' + Start up in disconnected mode. You need to execute + <literal>fs disco online</literal> (as root) to switch to + connected mode. Useful for roaming devices. + ''; + }; + + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + assertions = [ + { assertion = cfg.afsdb || cfg.cellServDB != []; + message = "You should specify all cell-local database servers in config.services.openafsClient.cellServDB or set config.services.openafsClient.afsdb."; + } + { assertion = cfg.cellName != ""; + message = "You must specify the local cell name in config.services.openafsClient.cellName."; + } + ]; + + environment.systemPackages = [ pkgs.openafs ]; + + environment.etc = { + clientCellServDB = { + source = pkgs.runCommand "CellServDB" {} '' + cat ${cellServDB} ${clientServDB} > $out + ''; + target = "openafs/CellServDB"; + mode = "0644"; + }; + clientCell = { + text = '' + ${cfg.cellName} + ''; + target = "openafs/ThisCell"; + mode = "0644"; + }; + }; + + systemd.services.afsd = { + description = "AFS client"; + wantedBy = [ "multi-user.target" ]; + after = singleton (if cfg.startDisconnected then "network.target" else "network-online.target"); + serviceConfig = { RemainAfterExit = true; }; + restartIfChanged = false; + + preStart = '' + mkdir -p -m 0755 ${cfg.mountPoint} + mkdir -m 0700 -p ${cfg.cache.directory} + ${pkgs.kmod}/bin/insmod ${openafsMod}/lib/modules/*/extra/openafs/libafs.ko.xz + ${openafsBin}/sbin/afsd \ + -mountdir ${cfg.mountPoint} \ + -confdir ${afsConfig} \ + ${optionalString (!cfg.cache.diskless) "-cachedir ${cfg.cache.directory}"} \ + -blocks ${toString cfg.cache.blocks} \ + -chunksize ${toString cfg.cache.chunksize} \ + ${optionalString cfg.cache.diskless "-memcache"} \ + -inumcalc ${cfg.inumcalc} \ + ${if cfg.fakestat then "-fakestat-all" else "-fakestat"} \ + ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} \ + ${optionalString cfg.afsdb "-afsdb"} + ${openafsBin}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} + ${optionalString cfg.startDisconnected "${openafsBin}/bin/fs discon offline"} + ''; + + # Doing this in preStop, because after these commands AFS is basically + # stopped, so systemd has nothing to do, just noticing it. If done in + # postStop, then we get a hang + kernel oops, because AFS can't be + # stopped simply by sending signals to processes. + preStop = '' + ${pkgs.utillinux}/bin/umount ${cfg.mountPoint} + ${openafsBin}/sbin/afsd -shutdown + ${pkgs.kmod}/sbin/rmmod libafs + ''; + }; + }; +} diff --git a/nixos/modules/services/network-filesystems/openafs/lib.nix b/nixos/modules/services/network-filesystems/openafs/lib.nix new file mode 100644 index 000000000000..ecfc72d2eaf9 --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/lib.nix @@ -0,0 +1,28 @@ +{ lib, ...}: + +let + inherit (lib) concatStringsSep mkOption types; + +in rec { + + mkCellServDB = cellName: db: '' + >${cellName} + '' + (concatStringsSep "\n" (map (dbm: if (dbm.ip != "" && dbm.dnsname != "") then dbm.ip + " #" + dbm.dnsname else "") + db)); + + # CellServDB configuration type + cellServDBConfig = { + ip = mkOption { + type = types.str; + default = ""; + example = "1.2.3.4"; + description = "IP Address of a database server"; + }; + dnsname = mkOption { + type = types.str; + default = ""; + example = "afs.example.org"; + description = "DNS full-qualified domain name of a database server"; + }; + }; +} diff --git a/nixos/modules/services/network-filesystems/openafs/server.nix b/nixos/modules/services/network-filesystems/openafs/server.nix new file mode 100644 index 000000000000..429eb945ac9e --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/server.nix @@ -0,0 +1,260 @@ +{ config, pkgs, lib, ... }: + +with import ./lib.nix { inherit lib; }; + +let + inherit (lib) concatStringsSep intersperse mapAttrsToList mkForce mkIf mkMerge mkOption optionalString types; + + bosConfig = pkgs.writeText "BosConfig" ('' + restrictmode 1 + restarttime 16 0 0 0 0 + checkbintime 3 0 5 0 0 + '' + (optionalString cfg.roles.database.enable '' + bnode simple vlserver 1 + parm ${openafsBin}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs} + end + bnode simple ptserver 1 + parm ${openafsBin}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs} + end + '') + (optionalString cfg.roles.fileserver.enable '' + bnode dafs dafs 1 + parm ${openafsBin}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs} + parm ${openafsBin}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs} + parm ${openafsBin}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs} + parm ${openafsBin}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs} + end + '') + (optionalString (cfg.roles.database.enable && cfg.roles.backup.enable) '' + bnode simple buserver 1 + parm ${openafsBin}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString (cfg.roles.backup.cellServDB != []) "-cellservdb /etc/openafs/backup/"} + end + '')); + + netInfo = if (cfg.advertisedAddresses != []) then + pkgs.writeText "NetInfo" ((concatStringsSep "\nf " cfg.advertisedAddresses) + "\n") + else null; + + buCellServDB = pkgs.writeText "backup-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.roles.backup.cellServDB); + + cfg = config.services.openafsServer; + + udpSizeStr = toString cfg.udpPacketSize; + + openafsBin = lib.getBin pkgs.openafs; + +in { + + options = { + + services.openafsServer = { + + enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable the OpenAFS server. An OpenAFS server needs a + complex setup. So, be aware that enabling this service and setting + some options does not give you a turn-key-ready solution. You need + at least a running Kerberos 5 setup, as OpenAFS relies on it for + authentication. See the Guide "QuickStartUnix" coming with + <literal>pkgs.openafs.doc</literal> for complete setup + instructions. + ''; + }; + + advertisedAddresses = mkOption { + default = []; + description = "List of IP addresses this server is advertised under. See NetInfo(5)"; + }; + + cellName = mkOption { + default = ""; + type = types.str; + description = "Cell name, this server will serve."; + example = "grand.central.org"; + }; + + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule [ { options = cellServDBConfig;} ]); + description = "Definition of all cell-local database server machines."; + }; + + roles = { + fileserver = { + enable = mkOption { + default = true; + type = types.bool; + description = "Fileserver role, serves files and volumes from its local storage."; + }; + + fileserverArgs = mkOption { + default = "-vattachpar 128 -vhashsize 11 -L -rxpck 400 -cb 1000000"; + type = types.str; + description = "Arguments to the dafileserver process. See its man page."; + }; + + volserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the davolserver process. See its man page."; + example = "-sync never"; + }; + + salvageserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the salvageserver process. See its man page."; + example = "-showlog"; + }; + + salvagerArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the dasalvager process. See its man page."; + example = "-showlog -showmounts"; + }; + }; + + database = { + enable = mkOption { + default = true; + type = types.bool; + description = '' + Database server role, maintains the Volume Location Database, + Protection Database (and Backup Database, see + <literal>backup</literal> role). There can be multiple + servers in the database role for replication, which then need + reliable network connection to each other. + + Servers in this role appear in AFSDB DNS records or the + CellServDB. + ''; + }; + + vlserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the vlserver process. See its man page."; + example = "-rxbind"; + }; + + ptserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the ptserver process. See its man page."; + example = "-restricted -default_access S---- S-M---"; + }; + }; + + backup = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Backup server role. Use in conjunction with the + <literal>database</literal> role to maintain the Backup + Database. Normally only used in conjunction with tape storage + or IBM's Tivoli Storage Manager. + ''; + }; + + buserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the buserver process. See its man page."; + example = "-p 8"; + }; + + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule [ { options = cellServDBConfig;} ]); + description = '' + Definition of all cell-local backup database server machines. + Use this when your cell uses less backup database servers than + other database server machines. + ''; + }; + }; + }; + + dottedPrincipals= mkOption { + default = false; + type = types.bool; + description = '' + If enabled, allow principal names containing (.) dots. Enabling + this has security implications! + ''; + }; + + udpPacketSize = mkOption { + default = 1310720; + type = types.int; + description = '' + UDP packet size to use in Bytes. Higher values can speed up + communications. The default of 1 MB is a sufficient in most + cases. Make sure to increase the kernel's UDP buffer size + accordingly via <literal>net.core(w|r|opt)mem_max</literal> + sysctl. + ''; + }; + + }; + + }; + + config = mkIf cfg.enable { + + assertions = [ + { assertion = cfg.cellServDB != []; + message = "You must specify all cell-local database servers in config.services.openafsServer.cellServDB."; + } + { assertion = cfg.cellName != ""; + message = "You must specify the local cell name in config.services.openafsServer.cellName."; + } + ]; + + environment.systemPackages = [ pkgs.openafs ]; + + environment.etc = { + bosConfig = { + source = bosConfig; + target = "openafs/BosConfig"; + mode = "0644"; + }; + cellServDB = { + text = mkCellServDB cfg.cellName cfg.cellServDB; + target = "openafs/server/CellServDB"; + mode = "0644"; + }; + thisCell = { + text = cfg.cellName; + target = "openafs/server/ThisCell"; + mode = "0644"; + }; + buCellServDB = { + enable = (cfg.roles.backup.cellServDB != []); + text = mkCellServDB cfg.cellName cfg.roles.backup.cellServDB; + target = "openafs/backup/CellServDB"; + }; + }; + + systemd.services = { + openafs-server = { + description = "OpenAFS server"; + after = [ "syslog.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartIfChanged = false; + unitConfig.ConditionPathExists = [ "/etc/openafs/server/rxkad.keytab" ]; + preStart = '' + mkdir -m 0755 -p /var/openafs + ${optionalString (netInfo != null) "cp ${netInfo} /var/openafs/netInfo"} + ${optionalString (cfg.roles.backup.cellServDB != []) "cp ${buCellServDB}"} + ''; + serviceConfig = { + ExecStart = "${openafsBin}/bin/bosserver -nofork"; + ExecStop = "${openafsBin}/bin/bos shutdown localhost -wait -localauth"; + }; + }; + }; + }; +} diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 9b9c91a4f167..b23266e8d43a 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -54,9 +54,12 @@ let }; serviceConfig = { - ExecStart = "${samba}/sbin/${appName} ${args}"; + ExecStart = "${samba}/sbin/${appName} --foreground --no-process-group ${args}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + LimitNOFILE = 16384; + PIDFile = "/run/${appName}.pid"; Type = "notify"; + NotifyAccess = "all"; #may not do anything... }; restartTriggers = [ configFile ]; @@ -230,11 +233,12 @@ in after = [ "samba-setup.service" "network.target" ]; wantedBy = [ "multi-user.target" ]; }; - + # Refer to https://github.com/samba-team/samba/tree/master/packaging/systemd + # for correct use with systemd services = { - "samba-smbd" = daemonService "smbd" "-F"; - "samba-nmbd" = mkIf cfg.enableNmbd (daemonService "nmbd" "-F"); - "samba-winbindd" = mkIf cfg.enableWinbindd (daemonService "winbindd" "-F"); + "samba-smbd" = daemonService "smbd" ""; + "samba-nmbd" = mkIf cfg.enableNmbd (daemonService "nmbd" ""); + "samba-winbindd" = mkIf cfg.enableWinbindd (daemonService "winbindd" ""); "samba-setup" = { description = "Samba Setup Task"; script = setupScript; diff --git a/nixos/modules/services/networking/aria2.nix b/nixos/modules/services/networking/aria2.nix index ad4ac9bf45e3..df9c92db2e54 100644 --- a/nixos/modules/services/networking/aria2.nix +++ b/nixos/modules/services/networking/aria2.nix @@ -10,9 +10,9 @@ let settingsDir = "${homeDir}"; sessionFile = "${homeDir}/aria2.session"; downloadDir = "${homeDir}/Downloads"; - + rangesToStringList = map (x: builtins.toString x.from +"-"+ builtins.toString x.to); - + settingsFile = pkgs.writeText "aria2.conf" '' dir=${cfg.downloadDir} @@ -110,12 +110,12 @@ in mkdir -m 0770 -p "${homeDir}" chown aria2:aria2 "${homeDir}" if [[ ! -d "${config.services.aria2.downloadDir}" ]] - then + then mkdir -m 0770 -p "${config.services.aria2.downloadDir}" chown aria2:aria2 "${config.services.aria2.downloadDir}" fi if [[ ! -e "${sessionFile}" ]] - then + then touch "${sessionFile}" chown aria2:aria2 "${sessionFile}" fi @@ -132,4 +132,4 @@ in }; }; }; -} \ No newline at end of file +} diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix index 1a7a1e24b702..c25bd0fdc541 100644 --- a/nixos/modules/services/networking/bird.nix +++ b/nixos/modules/services/networking/bird.nix @@ -7,21 +7,27 @@ let let cfg = config.services.${variant}; pkg = pkgs.${variant}; + birdBin = if variant == "bird6" then "bird6" else "bird"; birdc = if variant == "bird6" then "birdc6" else "birdc"; + descr = + { bird = "1.9.x with IPv4 suport"; + bird6 = "1.9.x with IPv6 suport"; + bird2 = "2.x"; + }.${variant}; configFile = pkgs.stdenv.mkDerivation { name = "${variant}.conf"; text = cfg.config; preferLocalBuild = true; buildCommand = '' echo -n "$text" > $out - ${pkg}/bin/${variant} -d -p -c $out + ${pkg}/bin/${birdBin} -d -p -c $out ''; }; in { ###### interface options = { services.${variant} = { - enable = mkEnableOption "BIRD Internet Routing Daemon"; + enable = mkEnableOption "BIRD Internet Routing Daemon (${descr})"; config = mkOption { type = types.lines; description = '' @@ -36,12 +42,12 @@ let config = mkIf cfg.enable { environment.systemPackages = [ pkg ]; systemd.services.${variant} = { - description = "BIRD Internet Routing Daemon"; + description = "BIRD Internet Routing Daemon (${descr})"; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "forking"; Restart = "on-failure"; - ExecStart = "${pkg}/bin/${variant} -c ${configFile} -u ${variant} -g ${variant}"; + ExecStart = "${pkg}/bin/${birdBin} -c ${configFile} -u ${variant} -g ${variant}"; ExecReload = "${pkg}/bin/${birdc} configure"; ExecStop = "${pkg}/bin/${birdc} down"; CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_SETUID" "CAP_SETGID" @@ -56,14 +62,15 @@ let users = { extraUsers.${variant} = { description = "BIRD Internet Routing Daemon user"; - group = "${variant}"; + group = variant; }; extraGroups.${variant} = {}; }; }; }; - inherit (config.services) bird bird6; -in { - imports = [(generic "bird") (generic "bird6")]; +in + +{ + imports = map generic [ "bird" "bird6" "bird2" ]; } diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix index 546d27069232..c3ca6fbe725e 100644 --- a/nixos/modules/services/networking/connman.nix +++ b/nixos/modules/services/networking/connman.nix @@ -52,6 +52,15 @@ in { ''; }; + extraFlags = mkOption { + type = with types; listOf string; + default = [ ]; + example = [ "--nodnsproxy" ]; + description = '' + Extra flags to pass to connmand + ''; + }; + }; }; @@ -81,7 +90,7 @@ in { Type = "dbus"; BusName = "net.connman"; Restart = "on-failure"; - ExecStart = "${pkgs.connman}/sbin/connmand --config=${configFile} --nodaemon"; + ExecStart = "${pkgs.connman}/sbin/connmand --config=${configFile} --nodaemon ${toString cfg.extraFlags}"; StandardOutput = "null"; }; }; diff --git a/nixos/modules/services/networking/dante.nix b/nixos/modules/services/networking/dante.nix index a9a77f3412af..32acce51e692 100644 --- a/nixos/modules/services/networking/dante.nix +++ b/nixos/modules/services/networking/dante.nix @@ -47,7 +47,7 @@ in systemd.services.dante = { description = "Dante SOCKS v4 and v5 compatible proxy server"; - after = [ "network.target" ]; + after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index d283c7624335..de0aa1a2c2c3 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -16,7 +16,7 @@ let # Don't start dhcpcd on explicitly configured interfaces or on # interfaces that are part of a bridge, bond or sit device. ignoredInterfaces = - map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ip4 != [ ] || i.ipAddress != null) interfaces) + map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ipv4.addresses != [ ]) interfaces) ++ mapAttrsToList (i: _: i) config.networking.sits ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.vswitches)) @@ -156,11 +156,11 @@ in systemd.services.dhcpcd = let cfgN = config.networking; hasDefaultGatewaySet = (cfgN.defaultGateway != null && cfgN.defaultGateway.address != "") - || (cfgN.defaultGateway6 != null && cfgN.defaultGateway6.address != ""); + && (!cfgN.enableIPv6 || (cfgN.defaultGateway6 != null && cfgN.defaultGateway6.address != "")); in { description = "DHCP Client"; - wantedBy = optional (!hasDefaultGatewaySet) "network-online.target"; + wantedBy = [ "multi-user.target" ] ++ optional (!hasDefaultGatewaySet) "network-online.target"; after = [ "network.target" ]; wants = [ "network.target" ]; diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index ed658258c7f9..857657eea4db 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -10,7 +10,7 @@ let # This is somewhat more flexible than preloading the key as an # embedded string. upstreamResolverListPubKey = pkgs.fetchurl { - url = https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/minisign.pub; + url = https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/minisign.pub; sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh"; }; @@ -258,9 +258,9 @@ in domain=raw.githubusercontent.com get="curl -fSs --resolve $domain:443:$(hostip -r 8.8.8.8 $domain | head -1)" $get -o dnscrypt-resolvers.csv.tmp \ - https://$domain/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv + https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv $get -o dnscrypt-resolvers.csv.minisig.tmp \ - https://$domain/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv.minisig + https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv.minisig mv dnscrypt-resolvers.csv.minisig{.tmp,} if ! minisign -q -V -p ${upstreamResolverListPubKey} \ -m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig ; then diff --git a/nixos/modules/services/networking/dnscrypt-wrapper.nix b/nixos/modules/services/networking/dnscrypt-wrapper.nix index 23cc92946e41..bf13d5c6f5fe 100644 --- a/nixos/modules/services/networking/dnscrypt-wrapper.nix +++ b/nixos/modules/services/networking/dnscrypt-wrapper.nix @@ -145,6 +145,16 @@ in { }; users.groups.dnscrypt-wrapper = { }; + security.polkit.extraConfig = '' + // Allow dnscrypt-wrapper user to restart dnscrypt-wrapper.service + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.systemd1.manage-units" && + action.lookup("unit") == "dnscrypt-wrapper.service" && + subject.user == "dnscrypt-wrapper") { + return polkit.Result.YES; + } + }); + ''; systemd.services.dnscrypt-wrapper = { description = "dnscrypt-wrapper daemon"; diff --git a/nixos/modules/services/networking/firefox/sync-server.nix b/nixos/modules/services/networking/firefox/sync-server.nix index a9f3fd65d76b..97d223a56cab 100644 --- a/nixos/modules/services/networking/firefox/sync-server.nix +++ b/nixos/modules/services/networking/firefox/sync-server.nix @@ -33,6 +33,8 @@ let in { + meta.maintainers = with lib.maintainers; [ nadrieril ]; + options = { services.firefox.syncserver = { enable = mkOption { @@ -70,18 +72,6 @@ in ''; }; - user = mkOption { - type = types.str; - default = "syncserver"; - description = "User account under which syncserver runs."; - }; - - group = mkOption { - type = types.str; - default = "syncserver"; - description = "Group account under which syncserver runs."; - }; - publicUrl = mkOption { type = types.str; default = "http://localhost:5000/"; @@ -137,7 +127,9 @@ in config = mkIf cfg.enable { systemd.services.syncserver = let - syncServerEnv = pkgs.python.withPackages(ps: with ps; [ syncserver pasteScript ]); + syncServerEnv = pkgs.python.withPackages(ps: with ps; [ syncserver pasteScript requests ]); + user = "syncserver"; + group = "syncserver"; in { after = [ "network.target" ]; description = "Firefox Sync Server"; @@ -145,43 +137,43 @@ in path = [ pkgs.coreutils syncServerEnv ]; serviceConfig = { - User = cfg.user; - Group = cfg.group; + User = user; + Group = group; PermissionsStartOnly = true; }; preStart = '' if ! test -e ${cfg.privateConfig}; then - mkdir -m 700 -p $(dirname ${cfg.privateConfig}) + mkdir -p $(dirname ${cfg.privateConfig}) echo > ${cfg.privateConfig} '[syncserver]' + chmod 600 ${cfg.privateConfig} echo >> ${cfg.privateConfig} "secret = $(head -c 20 /dev/urandom | sha1sum | tr -d ' -')" fi - chown ${cfg.user}:${cfg.group} ${cfg.privateConfig} + chmod 600 ${cfg.privateConfig} + chmod 755 $(dirname ${cfg.privateConfig}) + chown ${user}:${group} ${cfg.privateConfig} + '' + optionalString (cfg.sqlUri == defaultSqlUri) '' if ! test -e $(dirname ${defaultDbLocation}); then mkdir -m 700 -p $(dirname ${defaultDbLocation}) - chown ${cfg.user}:${cfg.group} $(dirname ${defaultDbLocation}) + chown ${user}:${group} $(dirname ${defaultDbLocation}) fi + # Move previous database file if it exists oldDb="/var/db/firefox-sync-server.db" if test -f $oldDb; then mv $oldDb ${defaultDbLocation} - chown ${cfg.user}:${cfg.group} ${defaultDbLocation} + chown ${user}:${group} ${defaultDbLocation} fi ''; serviceConfig.ExecStart = "${syncServerEnv}/bin/paster serve ${syncServerIni}"; }; - users.extraUsers = optionalAttrs (cfg.user == "syncserver") - (singleton { - name = "syncserver"; - group = cfg.group; - isSystemUser = true; - }); - - users.extraGroups = optionalAttrs (cfg.group == "syncserver") - (singleton { - name = "syncserver"; - }); + users.users.syncserver = { + group = "syncserver"; + isSystemUser = true; + }; + + users.groups.syncserver = {}; }; } diff --git a/nixos/modules/services/networking/freeradius.nix b/nixos/modules/services/networking/freeradius.nix new file mode 100644 index 000000000000..45cba1ce2770 --- /dev/null +++ b/nixos/modules/services/networking/freeradius.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.freeradius; + + freeradiusService = cfg: + { + description = "FreeRadius server"; + wantedBy = ["multi-user.target"]; + after = ["network-online.target"]; + wants = ["network-online.target"]; + preStart = '' + ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout + ''; + + serviceConfig = { + ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout -xx"; + ExecReload = [ + "${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" + "${pkgs.coreutils}/bin/kill -HUP $MAINPID" + ]; + User = "radius"; + ProtectSystem = "full"; + ProtectHome = "on"; + Restart = "on-failure"; + RestartSec = 2; + }; + }; + + freeradiusConfig = { + enable = mkEnableOption "the freeradius server"; + + configDir = mkOption { + type = types.path; + default = "/etc/raddb"; + description = '' + The path of the freeradius server configuration directory. + ''; + }; + + }; + +in + +{ + + ###### interface + + options = { + services.freeradius = freeradiusConfig; + }; + + + ###### implementation + + config = mkIf (cfg.enable) { + + users = { + extraUsers.radius = { + /*uid = config.ids.uids.radius;*/ + description = "Radius daemon user"; + }; + }; + + systemd.services.freeradius = freeradiusService cfg; + + }; + +} diff --git a/nixos/modules/services/networking/gnunet.nix b/nixos/modules/services/networking/gnunet.nix index 03ee54af4334..02cd53c6fa38 100644 --- a/nixos/modules/services/networking/gnunet.nix +++ b/nixos/modules/services/networking/gnunet.nix @@ -137,6 +137,8 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; path = [ pkgs.gnunet pkgs.miniupnpc ]; + environment.TMPDIR = "/tmp"; + serviceConfig.PrivateTemp = true; serviceConfig.ExecStart = "${pkgs.gnunet}/lib/gnunet/libexec/gnunet-service-arm -c ${configFile}"; serviceConfig.User = "gnunet"; serviceConfig.UMask = "0007"; diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix index ca2e2a065dcf..8f5aeee4a16b 100644 --- a/nixos/modules/services/networking/i2pd.nix +++ b/nixos/modules/services/networking/i2pd.nix @@ -126,6 +126,7 @@ let [${tun.name}] type = client destination = ${tun.destination} + destinationport = ${toString tun.destinationPort} keys = ${tun.keys} address = ${tun.address} port = ${toString tun.port} @@ -137,15 +138,15 @@ let '') } ${flip concatMapStrings - (collect (tun: tun ? port && tun ? host) cfg.inTunnels) - (tun: let portStr = toString tun.port; in '' + (collect (tun: tun ? port && tun ? address) cfg.inTunnels) + (tun: '' [${tun.name}] type = server destination = ${tun.destination} keys = ${tun.keys} host = ${tun.address} - port = ${tun.port} - inport = ${tun.inPort} + port = ${toString tun.port} + inport = ${toString tun.inPort} accesslist = ${builtins.concatStringsSep "," tun.accessList} '') } @@ -405,7 +406,13 @@ in default = {}; type = with types; loaOf (submodule ( { name, config, ... }: { - options = commonTunOpts name; + options = { + destinationPort = mkOption { + type = types.int; + default = 0; + description = "Connect to particular port at destination."; + }; + } // commonTunOpts name; config = { name = mkDefault name; }; diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix index 18e2ab9aebf1..aac02b811d71 100644 --- a/nixos/modules/services/networking/kresd.nix +++ b/nixos/modules/services/networking/kresd.nix @@ -43,7 +43,16 @@ in type = with types; listOf str; default = [ "::1" "127.0.0.1" ]; description = '' - What addresses the server should listen on. + What addresses the server should listen on. (UDP+TCP 53) + ''; + }; + listenTLS = mkOption { + type = with types; listOf str; + default = []; + example = [ "198.51.100.1:853" "[2001:db8::1]:853" "853" ]; + description = '' + Addresses on which kresd should provide DNS over TLS (see RFC 7858). + For detailed syntax see ListenStream in man systemd.socket. ''; }; # TODO: perhaps options for more common stuff like cache size or forwarding @@ -72,6 +81,19 @@ in (iface: if elem ":" (stringToCharacters iface) then "[${iface}]:53" else "${iface}:53") cfg.interfaces; socketConfig.ListenDatagram = listenStreams; + socketConfig.FreeBind = true; + }; + + systemd.sockets.kresd-tls = mkIf (cfg.listenTLS != []) rec { + wantedBy = [ "sockets.target" ]; + before = wantedBy; + partOf = [ "kresd.socket" ]; + listenStreams = cfg.listenTLS; + socketConfig = { + FileDescriptorName = "tls"; + FreeBind = true; + Service = "kresd.service"; + }; }; systemd.sockets.kresd-control = rec { @@ -82,20 +104,11 @@ in socketConfig = { FileDescriptorName = "control"; Service = "kresd.service"; - SocketMode = "0660"; # only root user/group may connect + SocketMode = "0660"; # only root user/group may connect and control kresd }; }; - # Create the cacheDir; tmpfiles don't work on nixos-rebuild switch. - systemd.services.kresd-cachedir = { - serviceConfig.Type = "oneshot"; - script = '' - if [ ! -d '${cfg.cacheDir}' ]; then - mkdir -p '${cfg.cacheDir}' - chown kresd:kresd '${cfg.cacheDir}' - fi - ''; - }; + systemd.tmpfiles.rules = [ "d '${cfg.cacheDir}' 0770 kresd kresd - -" ]; systemd.services.kresd = { description = "Knot-resolver daemon"; @@ -104,16 +117,17 @@ in User = "kresd"; Type = "notify"; WorkingDirectory = cfg.cacheDir; + Restart = "on-failure"; + Sockets = [ "kresd.socket" "kresd-control.socket" ] + ++ optional (cfg.listenTLS != []) "kresd-tls.socket"; }; + # Trust anchor goes from dns-root-data by default. script = '' - exec '${package}/bin/kresd' --config '${configFile}' \ - -k '${cfg.cacheDir}/root.key' + exec '${package}/bin/kresd' --config '${configFile}' --forks=1 ''; - after = [ "kresd-cachedir.service" ]; - requires = [ "kresd.socket" "kresd-cachedir.service" ]; - wantedBy = [ "sockets.target" ]; + requires = [ "kresd.socket" ]; }; }; } diff --git a/nixos/modules/services/networking/lldpd.nix b/nixos/modules/services/networking/lldpd.nix index ba4e1b1542fe..db1534edfd7c 100644 --- a/nixos/modules/services/networking/lldpd.nix +++ b/nixos/modules/services/networking/lldpd.nix @@ -24,6 +24,7 @@ in description = "lldpd user"; group = "_lldpd"; home = "/var/run/lldpd"; + isSystemUser = true; }; users.extraGroups._lldpd = {}; diff --git a/nixos/modules/services/networking/monero.nix b/nixos/modules/services/networking/monero.nix new file mode 100644 index 000000000000..31379189f5de --- /dev/null +++ b/nixos/modules/services/networking/monero.nix @@ -0,0 +1,238 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.monero; + dataDir = "/var/lib/monero"; + + listToConf = option: list: + concatMapStrings (value: "${option}=${value}\n") list; + + login = (cfg.rpc.user != null && cfg.rpc.password != null); + + configFile = with cfg; pkgs.writeText "monero.conf" '' + log-file=/dev/stdout + data-dir=${dataDir} + + ${optionalString mining.enable '' + start-mining=${mining.address} + mining-threads=${toString mining.threads} + ''} + + rpc-bind-ip=${rpc.address} + rpc-bind-port=${toString rpc.port} + ${optionalString login '' + rpc-login=${rpc.user}:${rpc.password} + ''} + ${optionalString rpc.restricted '' + restrict-rpc=1 + ''} + + limit-rate-up=${toString limits.upload} + limit-rate-down=${toString limits.download} + max-concurrency=${toString limits.threads} + block-sync-size=${toString limits.syncSize} + + ${listToConf "add-peer" extraNodes} + ${listToConf "add-priority-node" priorityNodes} + ${listToConf "add-exclusive-node" exclusiveNodes} + + ${extraConfig} + ''; + +in + +{ + + ###### interface + + options = { + + services.monero = { + + enable = mkEnableOption "Monero node daemon."; + + mining.enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to mine moneroj. + ''; + }; + + mining.address = mkOption { + type = types.str; + default = ""; + description = '' + Monero address where to send mining rewards. + ''; + }; + + mining.threads = mkOption { + type = types.addCheck types.int (x: x>=0); + default = 0; + description = '' + Number of threads used for mining. + Set to <literal>0</literal> to use all available. + ''; + }; + + rpc.user = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + User name for RPC connections. + ''; + }; + + rpc.password = mkOption { + type = types.str; + default = null; + description = '' + Password for RPC connections. + ''; + }; + + rpc.address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = '' + IP address the RPC server will bind to. + ''; + }; + + rpc.port = mkOption { + type = types.int; + default = 18081; + description = '' + Port the RPC server will bind to. + ''; + }; + + rpc.restricted = mkOption { + type = types.bool; + default = false; + description = '' + Whether to restrict RPC to view only commands. + ''; + }; + + limits.upload = mkOption { + type = types.addCheck types.int (x: x>=-1); + default = -1; + description = '' + Limit of the upload rate in kB/s. + Set to <literal>-1</literal> to leave unlimited. + ''; + }; + + limits.download = mkOption { + type = types.addCheck types.int (x: x>=-1); + default = -1; + description = '' + Limit of the download rate in kB/s. + Set to <literal>-1</literal> to leave unlimited. + ''; + }; + + limits.threads = mkOption { + type = types.addCheck types.int (x: x>=0); + default = 0; + description = '' + Maximum number of threads used for a parallel job. + Set to <literal>0</literal> to leave unlimited. + ''; + }; + + limits.syncSize = mkOption { + type = types.addCheck types.int (x: x>=0); + default = 0; + description = '' + Maximum number of blocks to sync at once. + Set to <literal>0</literal> for adaptive. + ''; + }; + + extraNodes = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of additional peer IP addresses to add to the local list. + ''; + }; + + priorityNodes = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of peer IP addresses to connect to and + attempt to keep the connection open. + ''; + }; + + exclusiveNodes = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of peer IP addresses to connect to *only*. + If given the other peer options will be ignored. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra lines to be added verbatim to monerod configuration. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = "monero"; + uid = config.ids.uids.monero; + description = "Monero daemon user"; + home = dataDir; + createHome = true; + }; + + users.extraGroups = singleton { + name = "monero"; + gid = config.ids.gids.monero; + }; + + systemd.services.monero = { + description = "monero daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "monero"; + Group = "monero"; + ExecStart = "${pkgs.monero}/bin/monerod --config-file=${configFile} --non-interactive"; + Restart = "always"; + SuccessExitStatus = [ 0 1 ]; + }; + }; + + assertions = singleton { + assertion = cfg.mining.enable -> cfg.mining.address != ""; + message = '' + You need a Monero address to receive mining rewards: + specify one using option monero.mining.address. + ''; + }; + + }; + +} + diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 81915b5a2ef8..d8135f4d0ffa 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -12,6 +12,10 @@ let keyfile ${cfg.ssl.keyfile} ''; + passwordConf = optionalString cfg.checkPasswords '' + password_file ${cfg.dataDir}/passwd + ''; + mosquittoConf = pkgs.writeText "mosquitto.conf" '' pid_file /run/mosquitto/pid acl_file ${aclFile} @@ -19,6 +23,7 @@ let allow_anonymous ${boolToString cfg.allowAnonymous} bind_address ${cfg.host} port ${toString cfg.port} + ${passwordConf} ${listenerConf} ${cfg.extraConf} ''; @@ -153,6 +158,15 @@ in ''; }; + checkPasswords = mkOption { + default = false; + example = true; + type = types.bool; + description = '' + Refuse connection when clients provide incorrect passwords. + ''; + }; + extraConf = mkOption { default = ""; type = types.lines; @@ -198,7 +212,7 @@ in '' + concatStringsSep "\n" ( mapAttrsToList (n: c: if c.hashedPassword != null then - "echo '${n}:${c.hashedPassword}' > ${cfg.dataDir}/passwd" + "echo '${n}:${c.hashedPassword}' >> ${cfg.dataDir}/passwd" else optionalString (c.password != null) "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} ${c.password}" ) cfg.users); diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix index 366bb2ed7a80..da3827c35e63 100644 --- a/nixos/modules/services/networking/nat.nix +++ b/nixos/modules/services/networking/nat.nix @@ -19,6 +19,8 @@ let iptables -w -t nat -D POSTROUTING -j nixos-nat-post 2>/dev/null || true iptables -w -t nat -F nixos-nat-post 2>/dev/null || true iptables -w -t nat -X nixos-nat-post 2>/dev/null || true + + ${cfg.extraStopCommands} ''; setupNat = '' @@ -51,8 +53,40 @@ let -i ${cfg.externalInterface} -p ${fwd.proto} \ --dport ${builtins.toString fwd.sourcePort} \ -j DNAT --to-destination ${fwd.destination} + + ${concatMapStrings (loopbackip: + let + m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination; + destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0; + destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 1; + in '' + # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself + iptables -w -t nat -A OUTPUT \ + -d ${loopbackip} -p ${fwd.proto} \ + --dport ${builtins.toString fwd.sourcePort} \ + -j DNAT --to-destination ${fwd.destination} + + # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from other hosts behind NAT + iptables -w -t nat -A nixos-nat-pre \ + -d ${loopbackip} -p ${fwd.proto} \ + --dport ${builtins.toString fwd.sourcePort} \ + -j DNAT --to-destination ${fwd.destination} + + iptables -w -t nat -A nixos-nat-post \ + -d ${destinationIP} -p ${fwd.proto} \ + --dport ${destinationPorts} \ + -j SNAT --to-source ${loopbackip} + '') fwd.loopbackIPs} '') cfg.forwardPorts} + ${optionalString (cfg.dmzHost != null) '' + iptables -w -t nat -A nixos-nat-pre \ + -i ${cfg.externalInterface} -j DNAT \ + --to-destination ${cfg.dmzHost} + ''} + + ${cfg.extraCommands} + # Append our chains to the nat tables iptables -w -t nat -A PREROUTING -j nixos-nat-pre iptables -w -t nat -A POSTROUTING -j nixos-nat-post @@ -125,15 +159,15 @@ in type = with types; listOf (submodule { options = { sourcePort = mkOption { - type = types.int; + type = types.either types.int (types.strMatching "[[:digit:]]+:[[:digit:]]+"); example = 8080; - description = "Source port of the external interface"; + description = "Source port of the external interface; to specify a port range, use a string with a colon (e.g. \"60000:61000\")"; }; destination = mkOption { type = types.str; example = "10.0.0.1:80"; - description = "Forward connection to destination ip:port"; + description = "Forward connection to destination ip:port; to specify a port range, use ip:start-end"; }; proto = mkOption { @@ -142,6 +176,13 @@ in example = "udp"; description = "Protocol of forwarded connection"; }; + + loopbackIPs = mkOption { + type = types.listOf types.str; + default = []; + example = literalExample ''[ "55.1.2.3" ]''; + description = "Public IPs for NAT reflection; for connections to `loopbackip:sourcePort' from the host itself and from other hosts behind NAT"; + }; }; }); default = []; @@ -153,6 +194,39 @@ in ''; }; + networking.nat.dmzHost = mkOption { + type = types.nullOr types.str; + default = null; + example = "10.0.0.1"; + description = + '' + The local IP address to which all traffic that does not match any + forwarding rule is forwarded. + ''; + }; + + networking.nat.extraCommands = mkOption { + type = types.lines; + default = ""; + example = "iptables -A INPUT -p icmp -j ACCEPT"; + description = + '' + Additional shell commands executed as part of the nat + initialisation script. + ''; + }; + + networking.nat.extraStopCommands = mkOption { + type = types.lines; + default = ""; + example = "iptables -D INPUT -p icmp -j ACCEPT || true"; + description = + '' + Additional shell commands executed as part of the nat + teardown script. + ''; + }; + }; diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index 6bdae32f72bb..62afbf32c2f6 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -241,6 +241,19 @@ in { A list of scripts which will be executed in response to network events. ''; }; + + enableStrongSwan = mkOption { + type = types.bool; + default = false; + description = '' + Enable the StrongSwan plugin. + </para><para> + If you enable this option the + <literal>networkmanager_strongswan</literal> plugin will be added to + the <option>networking.networkmanager.packages</option> option + so you don't need to to that yourself. + ''; + }; }; }; @@ -333,13 +346,13 @@ in { wireless.enable = lib.mkDefault false; }; - powerManagement.resumeCommands = '' - ${config.systemd.package}/bin/systemctl restart network-manager - ''; - security.polkit.extraConfig = polkitConf; - services.dbus.packages = cfg.packages; + networking.networkmanager.packages = + mkIf cfg.enableStrongSwan [ pkgs.networkmanager_strongswan ]; + + services.dbus.packages = + optional cfg.enableStrongSwan pkgs.strongswanNM ++ cfg.packages; services.udev.packages = cfg.packages; }; diff --git a/nixos/modules/services/networking/nixops-dns.nix b/nixos/modules/services/networking/nixops-dns.nix new file mode 100644 index 000000000000..2bb1263b7fa2 --- /dev/null +++ b/nixos/modules/services/networking/nixops-dns.nix @@ -0,0 +1,79 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + pkg = pkgs.nixops-dns; + cfg = config.services.nixops-dns; +in + +{ + options = { + services.nixops-dns = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the nixops-dns resolution + of NixOps virtual machines via dnsmasq and fake domain name. + ''; + }; + + user = mkOption { + type = types.str; + description = '' + The user the nixops-dns daemon should run as. + This should be the user, which is also used for nixops and + have the .nixops directory in its home. + ''; + }; + + domain = mkOption { + type = types.str; + description = '' + Fake domain name to resolve to NixOps virtual machines. + + For example "ops" will resolve "vm.ops". + ''; + example = "ops"; + default = "ops"; + }; + + dnsmasq = mkOption { + type = types.bool; + default = true; + description = '' + Enable dnsmasq forwarding to nixops-dns. This allows to use + nixops-dns for `services.nixops-dns.domain` resolution + while forwarding the rest of the queries to original resolvers. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + systemd.services.nixops-dns = { + description = "nixops-dns: DNS server for resolving NixOps machines"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + ExecStart="${pkg}/bin/nixops-dns --domain=.${cfg.domain}"; + }; + }; + + services.dnsmasq = mkIf cfg.dnsmasq { + enable = true; + resolveLocalQueries = true; + servers = [ + "/${cfg.domain}/127.0.0.1#5300" + ]; + extraConfig = '' + bind-interfaces + listen-address=127.0.0.1 + ''; + }; + + }; +} diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix index c8b8ed547ebb..4241e6fcceab 100644 --- a/nixos/modules/services/networking/nsd.nix +++ b/nixos/modules/services/networking/nsd.nix @@ -11,6 +11,8 @@ let # build nsd with the options needed for the given config nsdPkg = pkgs.nsd.override { + configFile = "${configFile}/nsd.conf"; + bind8Stats = cfg.bind8Stats; ipv6 = cfg.ipv6; ratelimit = cfg.ratelimit.enable; @@ -788,6 +790,8 @@ in config = mkIf cfg.enable { + environment.systemPackages = [ nsdPkg ]; + users.extraGroups = singleton { name = username; gid = config.ids.gids.nsd; @@ -845,4 +849,6 @@ in }; }; + + meta.maintainers = with lib.maintainers; [ hrdinka ]; } diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix index 3fbf5a9f0227..7a96b673c51e 100644 --- a/nixos/modules/services/networking/openvpn.nix +++ b/nixos/modules/services/networking/openvpn.nix @@ -50,6 +50,11 @@ let "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"} ${optionalString (cfg.down != "" || cfg.updateResolvConf) "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"} + ${optionalString (cfg.authUserPass != null) + "auth-user-pass ${pkgs.writeText "openvpn-credentials-${name}" '' + ${cfg.authUserPass.username} + ${cfg.authUserPass.password} + ''}"} ''; in { @@ -161,6 +166,29 @@ in ''; }; + authUserPass = mkOption { + default = null; + description = '' + This option can be used to store the username / password credentials + with the "auth-user-pass" authentication method. + + WARNING: Using this option will put the credentials WORLD-READABLE in the Nix store! + ''; + type = types.nullOr (types.submodule { + + options = { + username = mkOption { + description = "The username to store inside the credentials file."; + type = types.string; + }; + + password = mkOption { + description = "The password to store inside the credentials file."; + type = types.string; + }; + }; + }); + }; }; }); diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix index fb9c9dc67f24..9d7e6d6018af 100644 --- a/nixos/modules/services/networking/prosody.nix +++ b/nixos/modules/services/networking/prosody.nix @@ -10,98 +10,126 @@ let options = { - # TODO: require attribute key = mkOption { - type = types.str; - description = "Path to the key file"; + type = types.path; + description = "Path to the key file."; }; - # TODO: require attribute cert = mkOption { - type = types.str; - description = "Path to the certificate file"; + type = types.path; + description = "Path to the certificate file."; + }; + + extraOptions = mkOption { + type = types.attrs; + default = {}; + description = "Extra SSL configuration options."; }; + }; }; moduleOpts = { roster = mkOption { + type = types.bool; default = true; description = "Allow users to have a roster"; }; saslauth = mkOption { + type = types.bool; default = true; description = "Authentication for clients and servers. Recommended if you want to log in."; }; tls = mkOption { + type = types.bool; default = true; description = "Add support for secure TLS on c2s/s2s connections"; }; dialback = mkOption { + type = types.bool; default = true; description = "s2s dialback support"; }; disco = mkOption { + type = types.bool; default = true; description = "Service discovery"; }; legacyauth = mkOption { + type = types.bool; default = true; description = "Legacy authentication. Only used by some old clients and bots"; }; version = mkOption { + type = types.bool; default = true; description = "Replies to server version requests"; }; uptime = mkOption { + type = types.bool; default = true; description = "Report how long server has been running"; }; time = mkOption { + type = types.bool; default = true; description = "Let others know the time here on this server"; }; ping = mkOption { + type = types.bool; default = true; description = "Replies to XMPP pings with pongs"; }; console = mkOption { + type = types.bool; default = false; description = "telnet to port 5582"; }; bosh = mkOption { + type = types.bool; default = false; description = "Enable BOSH clients, aka 'Jabber over HTTP'"; }; httpserver = mkOption { + type = types.bool; default = false; description = "Serve static files from a directory over HTTP"; }; websocket = mkOption { + type = types.bool; default = false; description = "Enable WebSocket support"; }; }; - createSSLOptsStr = o: - if o ? key && o ? cert then - ''ssl = { key = "${o.key}"; certificate = "${o.cert}"; };'' - else ""; + toLua = x: + if builtins.isString x then ''"${x}"'' + else if builtins.isBool x then toString x + else if builtins.isInt x then toString x + else throw "Invalid Lua value"; + + createSSLOptsStr = o: '' + ssl = { + key = "${o.key}"; + certificate = "${o.cert}"; + ${concatStringsSep "\n" (mapAttrsToList (name: value: "${name} = ${toLua value};") o.extraOptions)} + }; + ''; vHostOpts = { ... }: { @@ -114,18 +142,20 @@ let }; enabled = mkOption { + type = types.bool; default = false; description = "Whether to enable the virtual host"; }; ssl = mkOption { - description = "Paths to SSL files"; + type = types.nullOr (types.submodule sslOpts); default = null; - options = [ sslOpts ]; + description = "Paths to SSL files"; }; extraConfig = mkOption { - default = ''''; + type = types.lines; + default = ""; description = "Additional virtual host specific configuration"; }; @@ -144,11 +174,26 @@ in services.prosody = { enable = mkOption { + type = types.bool; default = false; description = "Whether to enable the prosody server"; }; + package = mkOption { + type = types.package; + description = "Prosody package to use"; + default = pkgs.prosody; + defaultText = "pkgs.prosody"; + example = literalExample '' + pkgs.prosody.override { + withExtraLibs = [ pkgs.luaPackages.lpty ]; + withCommunityModules = [ "auth_external" ]; + }; + ''; + }; + allowRegistration = mkOption { + type = types.bool; default = false; description = "Allow account creation"; }; @@ -156,8 +201,9 @@ in modules = moduleOpts; extraModules = mkOption { - description = "Enable custom modules"; + type = types.listOf types.str; default = []; + description = "Enable custom modules"; }; virtualHosts = mkOption { @@ -183,20 +229,21 @@ in }; ssl = mkOption { - description = "Paths to SSL files"; + type = types.nullOr (types.submodule sslOpts); default = null; - options = [ sslOpts ]; + description = "Paths to SSL files"; }; admins = mkOption { - description = "List of administrators of the current host"; - example = [ "admin1@example.com" "admin2@example.com" ]; + type = types.listOf types.str; default = []; + example = [ "admin1@example.com" "admin2@example.com" ]; + description = "List of administrators of the current host"; }; extraConfig = mkOption { type = types.lines; - default = ''''; + default = ""; description = "Additional prosody configuration"; }; @@ -263,17 +310,17 @@ in }; systemd.services.prosody = { - description = "Prosody XMPP server"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; + restartTriggers = [ config.environment.etc."prosody/prosody.cfg.lua".source ]; serviceConfig = { User = "prosody"; + Type = "forking"; PIDFile = "/var/lib/prosody/prosody.pid"; - ExecStart = "${pkgs.prosody}/bin/prosodyctl start"; + ExecStart = "${cfg.package}/bin/prosodyctl start"; }; - }; }; diff --git a/nixos/modules/services/networking/radvd.nix b/nixos/modules/services/networking/radvd.nix index 0199502163a3..85d7f9e4a41b 100644 --- a/nixos/modules/services/networking/radvd.nix +++ b/nixos/modules/services/networking/radvd.nix @@ -59,24 +59,11 @@ in systemd.services.radvd = { description = "IPv6 Router Advertisement Daemon"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - path = [ pkgs.radvd ]; - - preStart = '' - mkdir -m 755 -p /run/radvd - chown radvd /run/radvd - ''; - serviceConfig = - { ExecStart = "@${pkgs.radvd}/sbin/radvd radvd" - + " -p /run/radvd/radvd.pid -m syslog -u radvd -C ${confFile}"; + { ExecStart = "@${pkgs.radvd}/bin/radvd radvd -n -u radvd -C ${confFile}"; Restart = "always"; - Type = "forking"; - PIDFile = "/run/radvd/radvd.pid"; }; }; diff --git a/nixos/modules/services/networking/resilio.nix b/nixos/modules/services/networking/resilio.nix index 6d2b7bdbca1b..d1c4101f80bd 100644 --- a/nixos/modules/services/networking/resilio.nix +++ b/nixos/modules/services/networking/resilio.nix @@ -17,7 +17,7 @@ let search_lan = entry.searchLAN; use_sync_trash = entry.useSyncTrash; - known_hosts = knownHosts; + known_hosts = entry.knownHosts; }) cfg.sharedFolders; configFile = pkgs.writeText "config.json" (builtins.toJSON ({ diff --git a/nixos/modules/services/networking/rxe.nix b/nixos/modules/services/networking/rxe.nix new file mode 100644 index 000000000000..a6a069ec50c0 --- /dev/null +++ b/nixos/modules/services/networking/rxe.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.networking.rxe; + + runRxeCmd = cmd: ifcs: + concatStrings ( map (x: "${pkgs.rdma-core}/bin/rxe_cfg -n ${cmd} ${x};") ifcs); + + startScript = pkgs.writeShellScriptBin "rxe-start" '' + ${pkgs.rdma-core}/bin/rxe_cfg -n start + ${runRxeCmd "add" cfg.interfaces} + ${pkgs.rdma-core}/bin/rxe_cfg + ''; + + stopScript = pkgs.writeShellScriptBin "rxe-stop" '' + ${runRxeCmd "remove" cfg.interfaces } + ${pkgs.rdma-core}/bin/rxe_cfg -n stop + ''; + +in { + ###### interface + + options = { + networking.rxe = { + enable = mkEnableOption "RDMA over converged ethernet"; + interfaces = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "eth0" ]; + description = '' + Enable RDMA on the listed interfaces. The corresponding virtual + RDMA interfaces will be named rxe0 ... rxeN where the ordering + will be as they are named in the list. UDP port 4791 must be + open on the respective ethernet interfaces. + ''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.rxe = { + path = with pkgs; [ kmod rdma-core ]; + description = "RoCE interfaces"; + + wantedBy = [ "multi-user.target" ]; + after = [ "systemd-modules-load.service" "network-online.target" ]; + wants = [ "network-pre.target" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${startScript}/bin/rxe-start"; + ExecStop = "${stopScript}/bin/rxe-stop"; + }; + }; + }; +} + diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index f0fddcca766f..e50c4dbacf36 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -21,7 +21,7 @@ let daemon reads in addition to the the user's authorized_keys file. You can combine the <literal>keys</literal> and <literal>keyFiles</literal> options. - Warning: If you are using <literal>NixOps</literal> then don't use this + 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. ''; }; @@ -137,6 +137,14 @@ in ''; }; + openFirewall = mkOption { + type = types.bool; + default = true; + description = '' + Whether to automatically open the specified ports in the firewall. + ''; + }; + listenAddresses = mkOption { type = with types; listOf (submodule { options = { @@ -248,13 +256,10 @@ in let service = { description = "SSH Daemon"; - wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; - + after = [ "network.target" ]; stopIfChanged = false; - path = [ cfgc.package pkgs.gawk ]; - environment.LD_LIBRARY_PATH = nssModulesPath; preStart = @@ -305,7 +310,7 @@ in }; - networking.firewall.allowedTCPPorts = cfg.ports; + networking.firewall.allowedTCPPorts = if cfg.openFirewall then cfg.ports else []; security.pam.services.sshd = { startSession = true; @@ -370,9 +375,6 @@ in # LogLevel VERBOSE logs user's key fingerprint on login. # Needed to have a clear audit track of which key was used to log in. LogLevel VERBOSE - - # Use kernel sandbox mechanisms where possible in unprivileged processes. - UsePrivilegeSeparation sandbox ''; assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true; diff --git a/nixos/modules/services/networking/stunnel.nix b/nixos/modules/services/networking/stunnel.nix new file mode 100644 index 000000000000..89a14966eca7 --- /dev/null +++ b/nixos/modules/services/networking/stunnel.nix @@ -0,0 +1,221 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.stunnel; + yesNo = val: if val then "yes" else "no"; + + verifyChainPathAssert = n: c: { + assertion = c.verifyHostname == null || (c.verifyChain || c.verifyPeer); + message = "stunnel: \"${n}\" client configuration - hostname verification " + + "is not possible without either verifyChain or verifyPeer enabled"; + }; + + serverConfig = { + options = { + accept = mkOption { + type = types.int; + description = "On which port stunnel should listen for incoming TLS connections."; + }; + + connect = mkOption { + type = types.int; + description = "To which port the decrypted connection should be forwarded."; + }; + + cert = mkOption { + type = types.path; + description = "File containing both the private and public keys."; + }; + }; + }; + + clientConfig = { + options = { + accept = mkOption { + type = types.string; + description = "IP:Port on which connections should be accepted."; + }; + + connect = mkOption { + type = types.string; + description = "IP:Port destination to connect to."; + }; + + verifyChain = mkOption { + type = types.bool; + default = true; + description = "Check if the provided certificate has a valid certificate chain (against CAPath)."; + }; + + verifyPeer = mkOption { + type = types.bool; + default = false; + description = "Check if the provided certificate is contained in CAPath."; + }; + + CAPath = mkOption { + type = types.path; + default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + description = "Path to a file containing certificates to validate against."; + }; + + verifyHostname = mkOption { + type = with types; nullOr string; + default = null; + description = "If set, stunnel checks if the provided certificate is valid for the given hostname."; + }; + }; + }; + + +in + +{ + + ###### interface + + options = { + + services.stunnel = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the stunnel TLS tunneling service."; + }; + + user = mkOption { + type = with types; nullOr string; + default = "nobody"; + description = "The user under which stunnel runs."; + }; + + group = mkOption { + type = with types; nullOr string; + default = "nogroup"; + description = "The group under which stunnel runs."; + }; + + logLevel = mkOption { + type = types.enum [ "emerg" "alert" "crit" "err" "warning" "notice" "info" "debug" ]; + default = "info"; + description = "Verbosity of stunnel output."; + }; + + fipsMode = mkOption { + type = types.bool; + default = false; + description = "Enable FIPS 140-2 mode required for compliance."; + }; + + enableInsecureSSLv3 = mkOption { + type = types.bool; + default = false; + description = "Enable support for the insecure SSLv3 protocol."; + }; + + + servers = mkOption { + description = "Define the server configuations."; + type = with types; attrsOf (submodule serverConfig); + example = { + fancyWebserver = { + enable = true; + accept = 443; + connect = 8080; + cert = "/path/to/pem/file"; + }; + }; + default = { }; + }; + + clients = mkOption { + description = "Define the client configurations."; + type = with types; attrsOf (submodule clientConfig); + example = { + foobar = { + accept = "0.0.0.0:8080"; + connect = "nixos.org:443"; + verifyChain = false; + }; + }; + default = { }; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + assertions = concatLists [ + (singleton { + assertion = (length (attrValues cfg.servers) != 0) || ((length (attrValues cfg.clients)) != 0); + message = "stunnel: At least one server- or client-configuration has to be present."; + }) + + (mapAttrsToList verifyChainPathAssert cfg.clients) + ]; + + environment.systemPackages = [ pkgs.stunnel ]; + + environment.etc."stunnel.cfg".text = '' + ${ if cfg.user != null then "setuid = ${cfg.user}" else "" } + ${ if cfg.group != null then "setgid = ${cfg.group}" else "" } + + debug = ${cfg.logLevel} + + ${ optionalString cfg.fipsMode "fips = yes" } + ${ optionalString cfg.enableInsecureSSLv3 "options = -NO_SSLv3" } + + ; ----- SERVER CONFIGURATIONS ----- + ${ lib.concatStringsSep "\n" + (lib.mapAttrsToList + (n: v: '' + [${n}] + accept = ${toString v.accept} + connect = ${toString v.connect} + cert = ${v.cert} + + '') + cfg.servers) + } + + ; ----- CLIENT CONFIGURATIONS ----- + ${ lib.concatStringsSep "\n" + (lib.mapAttrsToList + (n: v: '' + [${n}] + client = yes + accept = ${v.accept} + connect = ${v.connect} + verifyChain = ${yesNo v.verifyChain} + verifyPeer = ${yesNo v.verifyPeer} + ${optionalString (v.CAPath != null) "CApath = ${v.CAPath}"} + ${optionalString (v.verifyHostname != null) "checkHost = ${v.verifyHostname}"} + OCSPaia = yes + + '') + cfg.clients) + } + ''; + + systemd.services.stunnel = { + description = "stunnel TLS tunneling service"; + after = [ "network.target" ]; + wants = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ config.environment.etc."stunnel.cfg".source ]; + serviceConfig = { + ExecStart = "${pkgs.stunnel}/bin/stunnel ${config.environment.etc."stunnel.cfg".source}"; + Type = "forking"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/scheduling/fcron.nix b/nixos/modules/services/scheduling/fcron.nix index ac589be57736..e3b6b638f5a7 100644 --- a/nixos/modules/services/scheduling/fcron.nix +++ b/nixos/modules/services/scheduling/fcron.nix @@ -90,16 +90,24 @@ in [ (allowdeny "allow" (cfg.allow)) (allowdeny "deny" cfg.deny) # see man 5 fcron.conf - { source = pkgs.writeText "fcron.conf" '' - fcrontabs = /var/spool/fcron - pidfile = /var/run/fcron.pid - fifofile = /var/run/fcron.fifo - fcronallow = /etc/fcron.allow - fcrondeny = /etc/fcron.deny - shell = /bin/sh - sendmail = /run/wrappers/bin/sendmail - editor = ${pkgs.vim}/bin/vim - ''; + { source = + let + isSendmailWrapped = + lib.hasAttr "sendmail" config.security.wrappers; + sendmailPath = + if isSendmailWrapped then "/run/wrappers/bin/sendmail" + else "${config.system.path}/bin/sendmail"; + in + pkgs.writeText "fcron.conf" '' + fcrontabs = /var/spool/fcron + pidfile = /var/run/fcron.pid + fifofile = /var/run/fcron.fifo + fcronallow = /etc/fcron.allow + fcrondeny = /etc/fcron.deny + shell = /bin/sh + sendmail = ${sendmailPath} + editor = ${pkgs.vim}/bin/vim + ''; target = "fcron.conf"; gid = config.ids.gids.fcron; mode = "0644"; diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix index c51dd5d94655..adef500b7b5c 100644 --- a/nixos/modules/services/search/elasticsearch.nix +++ b/nixos/modules/services/search/elasticsearch.nix @@ -6,6 +6,7 @@ let cfg = config.services.elasticsearch; es5 = builtins.compareVersions (builtins.parseDrvName cfg.package.name).version "5" >= 0; + es6 = builtins.compareVersions (builtins.parseDrvName cfg.package.name).version "6" >= 0; esConfig = '' network.host: ${cfg.listenAddress} @@ -92,8 +93,6 @@ in { node.name: "elasticsearch" node.master: true node.data: false - index.number_of_shards: 5 - index.number_of_replicas: 1 ''; }; @@ -165,7 +164,10 @@ in { path = [ pkgs.inetutils ]; environment = { ES_HOME = cfg.dataDir; - ES_JAVA_OPTS = toString ([ "-Des.path.conf=${configDir}" ] ++ cfg.extraJavaOptions); + ES_JAVA_OPTS = toString ( optional (!es6) [ "-Des.path.conf=${configDir}" ] + ++ cfg.extraJavaOptions); + } // optionalAttrs es6 { + ES_PATH_CONF = configDir; }; serviceConfig = { ExecStart = "${cfg.package}/bin/elasticsearch ${toString cfg.extraCmdLineOptions}"; diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix index f71f30fee97a..4161c61ed375 100644 --- a/nixos/modules/services/security/clamav.nix +++ b/nixos/modules/services/security/clamav.nix @@ -76,8 +76,9 @@ in }; }; - config = mkIf cfg.updater.enable or cfg.daemon.enable { + config = mkIf (cfg.updater.enable || cfg.daemon.enable) { environment.systemPackages = [ pkg ]; + users.extraUsers = singleton { name = clamavUser; uid = config.ids.uids.clamav; @@ -94,10 +95,10 @@ in environment.etc."clamav/freshclam.conf".source = freshclamConfigFile; environment.etc."clamav/clamd.conf".source = clamdConfigFile; - systemd.services.clamav-daemon = mkIf cfg.daemon.enable { + systemd.services.clamav-daemon = optionalAttrs cfg.daemon.enable { description = "ClamAV daemon (clamd)"; - after = mkIf cfg.updater.enable [ "clamav-freshclam.service" ]; - requires = mkIf cfg.updater.enable [ "clamav-freshclam.service" ]; + after = optional cfg.updater.enable "clamav-freshclam.service"; + requires = optional cfg.updater.enable "clamav-freshclam.service"; wantedBy = [ "multi-user.target" ]; restartTriggers = [ clamdConfigFile ]; @@ -115,7 +116,7 @@ in }; }; - systemd.timers.clamav-freshclam = mkIf cfg.updater.enable { + systemd.timers.clamav-freshclam = optionalAttrs cfg.updater.enable { description = "Timer for ClamAV virus database updater (freshclam)"; wantedBy = [ "timers.target" ]; timerConfig = { @@ -124,7 +125,7 @@ in }; }; - systemd.services.clamav-freshclam = mkIf cfg.updater.enable { + systemd.services.clamav-freshclam = optionalAttrs cfg.updater.enable { description = "ClamAV virus database updater (freshclam)"; restartTriggers = [ freshclamConfigFile ]; diff --git a/nixos/modules/services/security/hologram-agent.nix b/nixos/modules/services/security/hologram-agent.nix index 6c53a2df6306..39ed506f7617 100644 --- a/nixos/modules/services/security/hologram-agent.nix +++ b/nixos/modules/services/security/hologram-agent.nix @@ -35,10 +35,9 @@ in { config = mkIf cfg.enable { boot.kernelModules = [ "dummy" ]; - networking.interfaces.dummy0 = { - ipAddress = "169.254.169.254"; - prefixLength = 32; - }; + networking.interfaces.dummy0.ipv4.addresses = [ + { address = "169.254.169.254"; prefixLength = 32; } + ]; systemd.services.hologram-agent = { description = "Provide EC2 instance credentials to machines outside of EC2"; diff --git a/nixos/modules/services/security/physlock.nix b/nixos/modules/services/security/physlock.nix index 30224d7fc6ba..97fbd6aae6e0 100644 --- a/nixos/modules/services/security/physlock.nix +++ b/nixos/modules/services/security/physlock.nix @@ -30,6 +30,20 @@ in ''; }; + allowAnyUser = mkOption { + type = types.bool; + default = false; + description = '' + Whether to allow any user to lock the screen. This will install a + setuid wrapper to allow any user to start physlock as root, which + is a minor security risk. Call the physlock binary to use this instead + of using the systemd service. + + Note that you might need to relog to have the correct binary in your + PATH upon changing this option. + ''; + }; + disableSysRq = mkOption { type = types.bool; default = true; @@ -79,28 +93,36 @@ in ###### implementation - config = mkIf cfg.enable { - - # for physlock -l and physlock -L - environment.systemPackages = [ pkgs.physlock ]; - - systemd.services."physlock" = { - enable = true; - description = "Physlock"; - wantedBy = optional cfg.lockOn.suspend "suspend.target" - ++ optional cfg.lockOn.hibernate "hibernate.target" - ++ cfg.lockOn.extraTargets; - before = optional cfg.lockOn.suspend "systemd-suspend.service" - ++ optional cfg.lockOn.hibernate "systemd-hibernate.service" - ++ cfg.lockOn.extraTargets; - serviceConfig.Type = "forking"; - script = '' - ${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"} - ''; - }; + config = mkIf cfg.enable (mkMerge [ + { + + # for physlock -l and physlock -L + environment.systemPackages = [ pkgs.physlock ]; + + systemd.services."physlock" = { + enable = true; + description = "Physlock"; + wantedBy = optional cfg.lockOn.suspend "suspend.target" + ++ optional cfg.lockOn.hibernate "hibernate.target" + ++ cfg.lockOn.extraTargets; + before = optional cfg.lockOn.suspend "systemd-suspend.service" + ++ optional cfg.lockOn.hibernate "systemd-hibernate.service" + ++ cfg.lockOn.extraTargets; + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}"; + }; + }; - security.pam.services.physlock = {}; + security.pam.services.physlock = {}; - }; + } + + (mkIf cfg.allowAnyUser { + + security.wrappers.physlock = { source = "${pkgs.physlock}/bin/physlock"; user = "root"; }; + + }) + ]); } diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index bc79d9f2a590..fed91756e769 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -9,6 +9,26 @@ let opt = name: value: optionalString (value != null) "${name} ${value}"; optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}"; + isolationOptions = { + type = types.listOf (types.enum [ + "IsolateClientAddr" + "IsolateSOCKSAuth" + "IsolateClientProtocol" + "IsolateDestPort" + "IsolateDestAddr" + ]); + default = []; + example = [ + "IsolateClientAddr" + "IsolateSOCKSAuth" + "IsolateClientProtocol" + "IsolateDestPort" + "IsolateDestAddr" + ]; + description = "Tor isolation options"; + }; + + torRc = '' User tor DataDirectory ${torDirectory} @@ -20,10 +40,20 @@ let ${optint "ControlPort" cfg.controlPort} '' # Client connection config - + optionalString cfg.client.enable '' - SOCKSPort ${cfg.client.socksListenAddress} IsolateDestAddr + + optionalString cfg.client.enable '' + SOCKSPort ${cfg.client.socksListenAddress} ${toString cfg.client.socksIsolationOptions} SOCKSPort ${cfg.client.socksListenAddressFaster} ${opt "SocksPolicy" cfg.client.socksPolicy} + + ${optionalString cfg.client.transparentProxy.enable '' + TransPort ${cfg.client.transparentProxy.listenAddress} ${toString cfg.client.transparentProxy.isolationOptions} + ''} + + ${optionalString cfg.client.dns.enable '' + DNSPort ${cfg.client.dns.listenAddress} ${toString cfg.client.dns.isolationOptions} + AutomapHostsOnResolve 1 + AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes} + ''} '' # Relay config + optionalString cfg.relay.enable '' @@ -58,6 +88,9 @@ let ${flip concatMapStrings v.map (p: '' HiddenServicePort ${toString p.port} ${p.destination} '')} + ${optionalString (v.authorizeClient != null) '' + HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames} + ''} '')) + cfg.extraConfig; @@ -154,6 +187,55 @@ in ''; }; + socksIsolationOptions = mkOption (isolationOptions // { + default = ["IsolateDestAddr"]; + }); + + transparentProxy = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable tor transaprent proxy"; + }; + + listenAddress = mkOption { + type = types.str; + default = "127.0.0.1:9040"; + example = "192.168.0.1:9040"; + description = '' + Bind transparent proxy to this address. + ''; + }; + + isolationOptions = mkOption isolationOptions; + }; + + dns = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable tor dns resolver"; + }; + + listenAddress = mkOption { + type = types.str; + default = "127.0.0.1:9053"; + example = "192.168.0.1:9053"; + description = '' + Bind tor dns to this address. + ''; + }; + + isolationOptions = mkOption isolationOptions; + + automapHostsSuffixes = mkOption { + type = types.listOf types.str; + default = [".onion" ".exit"]; + example = [".onion"]; + description = "List of suffixes to use with automapHostsOnResolve"; + }; + }; + privoxy.enable = mkOption { type = types.bool; default = true; @@ -540,6 +622,33 @@ in })); }; + authorizeClient = mkOption { + default = null; + description = "If configured, the hidden service is accessible for authorized clients only."; + type = types.nullOr (types.submodule ({config, ...}: { + + options = { + + authType = mkOption { + type = types.enum [ "basic" "stealth" ]; + description = '' + Either <literal>"basic"</literal> for a general-purpose authorization protocol + or <literal>"stealth"</literal> for a less scalable protocol + that also hides service activity from unauthorized clients. + ''; + }; + + clientNames = mkOption { + type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+"); + description = '' + Only clients that are listed here are authorized to access the hidden service. + Generated authorization data can be found in <filename>${torDirectory}/onion/$name/hostname</filename>. + Clients need to put this authorization data in their configuration file using <literal>HidServAuth</literal>. + ''; + }; + }; + })); + }; }; config = { diff --git a/nixos/modules/services/security/usbguard.nix b/nixos/modules/services/security/usbguard.nix index 1f2c56a9efa1..4e685e633354 100644 --- a/nixos/modules/services/security/usbguard.nix +++ b/nixos/modules/services/security/usbguard.nix @@ -56,7 +56,7 @@ in { }; rules = mkOption { - type = types.nullOr types.str; + type = types.nullOr types.lines; default = null; example = '' allow with-interface equals { 08:*:* } diff --git a/nixos/modules/services/system/localtime.nix b/nixos/modules/services/system/localtime.nix new file mode 100644 index 000000000000..b9355bbb9441 --- /dev/null +++ b/nixos/modules/services/system/localtime.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.localtime; +in { + options = { + services.localtime = { + enable = mkOption { + default = false; + description = '' + Enable <literal>localtime</literal>, simple daemon for keeping the system + timezone up-to-date based on the current location. It uses geoclue2 to + determine the current location and systemd-timedated to actually set + the timezone. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + services.geoclue2.enable = true; + + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if (action.id == "org.freedesktop.timedate1.set-timezone" + && subject.user == "localtimed") { + return polkit.Result.YES; + } + }); + ''; + + users.users = [{ + name = "localtimed"; + description = "Taskserver user"; + }]; + + systemd.services.localtime = { + description = "localtime service"; + wantedBy = [ "multi-user.target" ]; + partOf = [ "geoclue.service "]; + + serviceConfig = { + Restart = "on-failure"; + # TODO: make it work with dbus + #DynamicUser = true; + Nice = 10; + User = "localtimed"; + PrivateTmp = "yes"; + PrivateDevices = true; + PrivateNetwork = "yes"; + NoNewPrivileges = "yes"; + ProtectSystem = "strict"; + ProtectHome = true; + ExecStart = "${pkgs.localtime}/bin/localtimed"; + }; + }; + }; +} diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix index 3429397d2cc2..b50de496e975 100644 --- a/nixos/modules/services/ttys/agetty.nix +++ b/nixos/modules/services/ttys/agetty.nix @@ -64,8 +64,8 @@ in config = { # Note: this is set here rather than up there so that changing - # nixosLabel would not rebuild manual pages - services.mingetty.greetingLine = mkDefault ''<<< Welcome to NixOS ${config.system.nixosLabel} (\m) - \l >>>''; + # nixos.label would not rebuild manual pages + services.mingetty.greetingLine = mkDefault ''<<< Welcome to NixOS ${config.system.nixos.label} (\m) - \l >>>''; systemd.services."getty@" = { serviceConfig.ExecStart = [ diff --git a/nixos/modules/services/web-apps/nexus.nix b/nixos/modules/services/web-apps/nexus.nix index a750aa66b27c..f6a5ce73a12b 100644 --- a/nixos/modules/services/web-apps/nexus.nix +++ b/nixos/modules/services/web-apps/nexus.nix @@ -11,7 +11,7 @@ in { options = { services.nexus = { - enable = mkEnableOption "SonarType Nexus3 OSS service"; + enable = mkEnableOption "Sonatype Nexus3 OSS service"; user = mkOption { type = types.str; @@ -54,7 +54,7 @@ in users.extraGroups."${cfg.group}" = {}; systemd.services.nexus = { - description = "SonarType Nexus3"; + description = "Sonatype Nexus3"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix index 76b0ee6da968..c784f4756d19 100644 --- a/nixos/modules/services/web-apps/tt-rss.nix +++ b/nixos/modules/services/web-apps/tt-rss.nix @@ -99,8 +99,8 @@ let user = mkOption { type = types.str; - default = "nginx"; - example = "nginx"; + default = "tt_rss"; + example = "tt_rss"; description = '' User account under which both the update daemon and the web-application run. ''; @@ -466,26 +466,28 @@ let ''; }; - services.nginx.virtualHosts = mkIf (cfg.virtualHost != null) { - "${cfg.virtualHost}" = { - root = "${cfg.root}"; - - locations."/" = { - index = "index.php"; - }; - - locations."~ \.php$" = { - extraConfig = '' - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:${phpfpmSocketName}; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME ${cfg.root}/$fastcgi_script_name; - ''; + services.nginx = { + enable = true; + # NOTE: No configuration is done if not using virtual host + virtualHosts = mkIf (cfg.virtualHost != null) { + "${cfg.virtualHost}" = { + root = "${cfg.root}"; + + locations."/" = { + index = "index.php"; + }; + + locations."~ \.php$" = { + extraConfig = '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${phpfpmSocketName}; + fastcgi_index index.php; + ''; + }; }; }; }; - systemd.services.tt-rss = let dbService = if cfg.database.type == "pgsql" then "postgresql.service" else "mysql.service"; in { @@ -496,7 +498,7 @@ let callSql = e: if cfg.database.type == "pgsql" then '' ${optionalString (cfg.database.password != null) "PGPASSWORD=${cfg.database.password}"} \ - ${pkgs.postgresql95}/bin/psql \ + ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${config.services.postgresql.package}/bin/psql \ -U ${cfg.database.user} \ ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} --port ${toString dbPort}"} \ -c '${e}' \ @@ -521,6 +523,14 @@ let '' + (optionalString (cfg.database.type == "pgsql") '' + ${optionalString (cfg.database.host == null && cfg.database.password == null) '' + if ! [ -e ${cfg.root}/.db-created ]; then + ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createuser ${cfg.database.user} + ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -O ${cfg.database.user} ${cfg.database.name} + touch ${cfg.root}/.db-created + fi + ''} + exists=$(${callSql "select count(*) > 0 from pg_tables where tableowner = user"} \ | tail -n+3 | head -n-2 | sed -e 's/[ \n\t]*//') @@ -554,5 +564,28 @@ let requires = ["${dbService}"]; after = ["network.target" "${dbService}"]; }; + + services.mysql = optionalAttrs (cfg.database.type == "mysql") { + enable = true; + package = mkDefault pkgs.mysql; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { + name = cfg.user; + ensurePermissions = { + "${cfg.database.name}.*" = "ALL PRIVILEGES"; + }; + } + ]; + }; + + services.postgresql = optionalAttrs (cfg.database.type == "pgsql") { + enable = mkDefault true; + }; + + users = optionalAttrs (cfg.user == "tt_rss") { + extraUsers.tt_rss.group = "tt_rss"; + extraGroups.tt_rss = {}; + }; }; } diff --git a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix index d689e9dd8e4c..cfddab2f5047 100644 --- a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix +++ b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix @@ -377,7 +377,7 @@ rec { ''} <Directory ${config.package}> - ${builtins.readFile "${config.package}/.htaccess"} + Include ${config.package}/.htaccess </Directory> ''; diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix index 700b4469c565..d23e810dcc62 100644 --- a/nixos/modules/services/web-servers/lighttpd/default.nix +++ b/nixos/modules/services/web-servers/lighttpd/default.nix @@ -50,11 +50,14 @@ let "mod_geoip" "mod_magnet" "mod_mysql_vhost" + "mod_openssl" # since v1.4.46 "mod_scgi" "mod_setenv" "mod_trigger_b4_dl" "mod_uploadprogress" + "mod_vhostdb" # since v1.4.46 "mod_webdav" + "mod_wstunnel" # since v1.4.46 ]; maybeModuleString = moduleName: diff --git a/nixos/modules/services/web-servers/mighttpd2.nix b/nixos/modules/services/web-servers/mighttpd2.nix new file mode 100644 index 000000000000..a888f623616e --- /dev/null +++ b/nixos/modules/services/web-servers/mighttpd2.nix @@ -0,0 +1,132 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.mighttpd2; + configFile = pkgs.writeText "mighty-config" cfg.config; + routingFile = pkgs.writeText "mighty-routing" cfg.routing; +in { + options.services.mighttpd2 = { + enable = mkEnableOption "Mighttpd2 web server"; + + config = mkOption { + default = ""; + example = '' + # Example configuration for Mighttpd 2 + Port: 80 + # IP address or "*" + Host: * + Debug_Mode: Yes # Yes or No + # If available, "nobody" is much more secure for User:. + User: root + # If available, "nobody" is much more secure for Group:. + Group: root + Pid_File: /var/run/mighty.pid + Logging: Yes # Yes or No + Log_File: /var/log/mighty # The directory must be writable by User: + Log_File_Size: 16777216 # bytes + Log_Backup_Number: 10 + Index_File: index.html + Index_Cgi: index.cgi + Status_File_Dir: /usr/local/share/mighty/status + Connection_Timeout: 30 # seconds + Fd_Cache_Duration: 10 # seconds + # Server_Name: Mighttpd/3.x.y + Tls_Port: 443 + Tls_Cert_File: cert.pem # should change this with an absolute path + # should change this with comma-separated absolute paths + Tls_Chain_Files: chain.pem + # Currently, Tls_Key_File must not be encrypted. + Tls_Key_File: privkey.pem # should change this with an absolute path + Service: 0 # 0 is HTTP only, 1 is HTTPS only, 2 is both + ''; + type = types.lines; + description = '' + Verbatim config file to use + (see http://www.mew.org/~kazu/proj/mighttpd/en/config.html) + ''; + }; + + routing = mkOption { + default = ""; + example = '' + # Example routing for Mighttpd 2 + + # Domain lists + [localhost www.example.com] + + # Entries are looked up in the specified order + # All paths must end with "/" + + # A path to CGI scripts should be specified with "=>" + /~alice/cgi-bin/ => /home/alice/public_html/cgi-bin/ + + # A path to static files should be specified with "->" + /~alice/ -> /home/alice/public_html/ + /cgi-bin/ => /export/cgi-bin/ + + # Reverse proxy rules should be specified with ">>" + # /path >> host:port/path2 + # Either "host" or ":port" can be committed, but not both. + /app/cal/ >> example.net/calendar/ + # Yesod app in the same server + /app/wiki/ >> 127.0.0.1:3000/ + + / -> /export/www/ + ''; + type = types.lines; + description = '' + Verbatim routing file to use + (see http://www.mew.org/~kazu/proj/mighttpd/en/config.html) + ''; + }; + + cores = mkOption { + default = null; + type = types.nullOr types.int; + description = '' + How many cores to use. + If null it will be determined automatically + ''; + }; + + }; + + config = mkIf cfg.enable { + assertions = + [ { assertion = cfg.routing != ""; + message = "You need at least one rule in mighttpd2.routing"; + } + ]; + systemd.services.mighttpd2 = { + description = "Mighttpd2 web server"; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = '' + ${pkgs.haskellPackages.mighttpd2}/bin/mighty \ + ${configFile} \ + ${routingFile} \ + +RTS -N${optionalString (cfg.cores != null) "${cfg.cores}"} + ''; + Type = "simple"; + User = "mighttpd2"; + Group = "mighttpd2"; + Restart = "on-failure"; + AmbientCapabilities = "cap_net_bind_service"; + CapabilityBoundingSet = "cap_net_bind_service"; + }; + }; + + users.extraUsers.mighttpd2 = { + group = "mighttpd2"; + uid = config.ids.uids.mighttpd2; + isSystemUser = true; + }; + + users.extraGroups.mighttpd2.gid = config.ids.gids.mighttpd2; + }; + + meta.maintainers = with lib.maintainers; [ fgaz ]; +} diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 97511aac9737..dee877f1c114 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -15,6 +15,9 @@ let } // (optionalAttrs vhostConfig.enableACME { sslCertificate = "/var/lib/acme/${serverName}/fullchain.pem"; sslCertificateKey = "/var/lib/acme/${serverName}/key.pem"; + }) // (optionalAttrs (vhostConfig.useACMEHost != null) { + sslCertificate = "/var/lib/acme/${vhostConfig.useACMEHost}/fullchain.pem"; + sslCertificateKey = "/var/lib/acme/${vhostConfig.useACMEHost}/key.pem"; }) ) cfg.virtualHosts; enableIPv6 = config.networking.enableIPv6; @@ -167,13 +170,14 @@ let listenString = { addr, port, ssl, ... }: "listen ${addr}:${toString port} " - + optionalString ssl "ssl http2 " + + optionalString ssl "ssl " + + optionalString (ssl && vhost.http2) "http2 " + optionalString vhost.default "default_server " + ";"; redirectListen = filter (x: !x.ssl) defaultListen; - acmeLocation = '' + acmeLocation = optionalString (vhost.enableACME || vhost.useACMEHost != null) '' location /.well-known/acme-challenge { ${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"} root ${vhost.acmeRoot}; @@ -193,7 +197,7 @@ let ${concatMapStringsSep "\n" listenString redirectListen} server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases}; - ${optionalString vhost.enableACME acmeLocation} + ${acmeLocation} location / { return 301 https://$host$request_uri; } @@ -203,7 +207,7 @@ let server { ${concatMapStringsSep "\n" listenString hostListen} server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases}; - ${optionalString vhost.enableACME acmeLocation} + ${acmeLocation} ${optionalString (vhost.root != null) "root ${vhost.root};"} ${optionalString (vhost.globalRedirect != null) '' return 301 http${optionalString hasSSL "s"}://${vhost.globalRedirect}$request_uri; @@ -554,6 +558,14 @@ in are mutually exclusive. ''; } + + { + assertion = all (conf: !(conf.enableACME && conf.useACMEHost != null)) (attrValues virtualHosts); + message = '' + Options services.nginx.service.virtualHosts.<name>.enableACME and + services.nginx.virtualHosts.<name>.useACMEHost are mutually exclusive. + ''; + } ]; systemd.services.nginx = { @@ -566,6 +578,7 @@ in mkdir -p ${cfg.stateDir}/logs chmod 700 ${cfg.stateDir} chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir} + ${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir} -t ''; serviceConfig = { ExecStart = "${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; @@ -579,7 +592,7 @@ in security.acme.certs = filterAttrs (n: v: v != {}) ( let vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts; - acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME) vhostsConfigs; + acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME && vhostConfig.useACMEHost == null) vhostsConfigs; acmePairs = map (vhostConfig: { name = vhostConfig.serverName; value = { user = cfg.user; group = lib.mkDefault cfg.group; diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 801601aafd9d..bf18108a1a3c 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -48,7 +48,21 @@ with lib; enableACME = mkOption { type = types.bool; default = false; - description = "Whether to ask Let's Encrypt to sign a certificate for this vhost."; + description = '' + Whether to ask Let's Encrypt to sign a certificate for this vhost. + Alternately, you can use an existing certificate through <option>useACMEHost</option>. + ''; + }; + + useACMEHost = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + A host of an existing Let's Encrypt certificate to use. + This is useful if you have many subdomains and want to avoid hitting the + <link xlink:href="https://letsencrypt.org/docs/rate-limits/">rate limit</link>. + Alternately, you can generate a certificate through <option>enableACME</option>. + ''; }; acmeRoot = mkOption { @@ -114,6 +128,20 @@ with lib; description = "Path to server SSL certificate key."; }; + http2 = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable HTTP 2. + Note that (as of writing) due to nginx's implementation, to disable + HTTP 2 you have to disable it on all vhosts that use a given + IP address / port. + If there is one server block configured to enable http2,then it is + enabled for all server blocks on this IP. + See https://stackoverflow.com/a/39466948/263061. + ''; + }; + root = mkOption { type = types.nullOr types.path; default = null; diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix index 943415e08c64..0b2e5c0b69d9 100644 --- a/nixos/modules/services/web-servers/tomcat.nix +++ b/nixos/modules/services/web-servers/tomcat.nix @@ -29,7 +29,7 @@ in type = types.package; default = pkgs.tomcat85; defaultText = "pkgs.tomcat85"; - example = lib.literalExample "pkgs.tomcatUnstable"; + example = lib.literalExample "pkgs.tomcat9"; description = '' Which tomcat package to use. ''; diff --git a/nixos/modules/services/web-servers/traefik.nix b/nixos/modules/services/web-servers/traefik.nix index 4ede4fc20967..b6c7fef21fb2 100644 --- a/nixos/modules/services/web-servers/traefik.nix +++ b/nixos/modules/services/web-servers/traefik.nix @@ -64,6 +64,16 @@ in { ''; }; + group = mkOption { + default = "traefik"; + type = types.string; + example = "docker"; + description = '' + Set the group that traefik runs under. + For the docker backend this needs to be set to <literal>docker</literal> instead. + ''; + }; + package = mkOption { default = pkgs.traefik; defaultText = "pkgs.traefik"; @@ -87,7 +97,7 @@ in { ]; Type = "simple"; User = "traefik"; - Group = "traefik"; + Group = cfg.group; Restart = "on-failure"; StartLimitInterval = 86400; StartLimitBurst = 5; diff --git a/nixos/modules/services/x11/compton.nix b/nixos/modules/services/x11/compton.nix index 11cbcac6fa85..8641c05de52e 100644 --- a/nixos/modules/services/x11/compton.nix +++ b/nixos/modules/services/x11/compton.nix @@ -181,10 +181,10 @@ in { }; backend = mkOption { - type = types.enum [ "glx" "xrender" ]; + type = types.enum [ "glx" "xrender" "xr_glx_hybrid" ]; default = "xrender"; description = '' - Backend to use: <literal>glx</literal> or <literal>xrender</literal>. + Backend to use: <literal>glx</literal>, <literal>xrender</literal> or <literal>xr_glx_hybrid</literal>. ''; }; diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix index 39b27d4ceb61..4622c7b760f0 100644 --- a/nixos/modules/services/x11/desktop-managers/default.nix +++ b/nixos/modules/services/x11/desktop-managers/default.nix @@ -109,9 +109,5 @@ in }; - config = { - services.xserver.displayManager.session = cfg.session.list; - environment.systemPackages = - mkIf cfg.session.needBGPackages [ pkgs.feh ]; # xsetroot via xserver.enable - }; + config.services.xserver.displayManager.session = cfg.session.list; } diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix index 8a523f0d8036..7f3dc0d7847b 100644 --- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix +++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix @@ -47,7 +47,7 @@ in export GTK_DATA_PREFIX=${config.system.path} # find theme engines export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0 - export XDG_MENU_PREFIX=enlightenment + export XDG_MENU_PREFIX=e- export GST_PLUGIN_PATH="${GST_PLUGIN_PATH}" diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index e5a79496c7a5..21d30df5b695 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -108,6 +108,7 @@ in { services.gnome3.seahorse.enable = mkDefault true; services.gnome3.sushi.enable = mkDefault true; services.gnome3.tracker.enable = mkDefault true; + services.gnome3.tracker-miners.enable = mkDefault true; hardware.pulseaudio.enable = mkDefault true; services.telepathy.enable = mkDefault true; networking.networkmanager.enable = mkDefault true; @@ -135,7 +136,7 @@ in { # find theme engines export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0 - export XDG_MENU_PREFIX=gnome + export XDG_MENU_PREFIX=gnome- ${concatMapStrings (p: '' if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then @@ -152,7 +153,7 @@ in { export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share # Override gsettings-desktop-schema - export XDG_DATA_DIRS=${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS + export NIX_GSETTINGS_OVERRIDES_DIR=${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas # Let nautilus find extensions export NAUTILUS_EXTENSION_DIR=${config.system.path}/lib/nautilus/extensions-3.0/ diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix index ab8a0a48b483..814503ab0bc4 100644 --- a/nixos/modules/services/x11/desktop-managers/mate.nix +++ b/nixos/modules/services/x11/desktop-managers/mate.nix @@ -12,6 +12,17 @@ let in filter (x: !(builtins.elem (pkgName x) ysNames)) xs; + addToXDGDirs = p: '' + if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then + export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name} + fi + + if [ -d "${p}/lib/girepository-1.0" ]; then + export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0 + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib + fi + ''; + xcfg = config.services.xserver; cfg = xcfg.desktopManager.mate; @@ -20,10 +31,14 @@ in { options = { - services.xserver.desktopManager.mate.enable = mkOption { - type = types.bool; - default = false; - description = "Enable the MATE desktop environment"; + services.xserver.desktopManager.mate = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable the MATE desktop environment"; + }; + + debug = mkEnableOption "mate-session debug messages"; }; environment.mate.excludePackages = mkOption { @@ -47,15 +62,34 @@ in # Find theme engines export GTK_PATH=${config.system.path}/lib/gtk-3.0:${config.system.path}/lib/gtk-2.0 - export XDG_MENU_PREFIX=mate + export XDG_MENU_PREFIX=mate- # Find the mouse export XCURSOR_PATH=~/.icons:${config.system.path}/share/icons + # Let caja find extensions + export CAJA_EXTENSION_DIRS=$CAJA_EXTENSION_DIRS''${CAJA_EXTENSION_DIRS:+:}${config.system.path}/lib/caja/extensions-2.0 + + # Let caja extensions find gsettings schemas + ${concatMapStrings (p: '' + if [ -d "${p}/lib/caja/extensions-2.0" ]; then + ${addToXDGDirs p} + fi + '') + config.environment.systemPackages + } + + # Let mate-panel find applets + export MATE_PANEL_APPLETS_DIR=$MATE_PANEL_APPLETS_DIR''${MATE_PANEL_APPLETS_DIR:+:}${config.system.path}/share/mate-panel/applets + export MATE_PANEL_EXTRA_MODULES=$MATE_PANEL_EXTRA_MODULES''${MATE_PANEL_EXTRA_MODULES:+:}${config.system.path}/lib/mate-panel/applets + + # Add mate-control-center paths to some XDG variables because its schemas are needed by mate-settings-daemon, and mate-settings-daemon is a dependency for mate-control-center (that is, they are mutually recursive) + ${addToXDGDirs pkgs.mate.mate-control-center} + # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update - ${pkgs.mate.mate-session-manager}/bin/mate-session & + ${pkgs.mate.mate-session-manager}/bin/mate-session ${optionalString cfg.debug "--debug"} & waitPID=$! ''; }; diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index bb4f4e868fea..b794e2b12d73 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -25,8 +25,8 @@ in type = types.bool; default = true; description = '' - Enable support for Qt 4-based applications. Particularly, install the - Qt 4 version of the Breeze theme and a default backend for Phonon. + Enable support for Qt 4-based applications. Particularly, install a + default backend for Phonon. ''; }; @@ -47,6 +47,18 @@ in ${getBin config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1" ''} + if [ -f "$HOME/.config/kdeglobals" ] + then + # Remove extraneous font style names. + # See also: https://phabricator.kde.org/D9070 + ${getBin pkgs.gnused}/bin/sed -i "$HOME/.config/kdeglobals" \ + -e '/^fixed=/ s/,Regular$//' \ + -e '/^font=/ s/,Regular$//' \ + -e '/^menuFont=/ s/,Regular$//' \ + -e '/^smallestReadableFont=/ s/,Regular$//' \ + -e '/^toolBarFont=/ s/,Regular$//' + fi + exec "${getBin plasma5.plasma-workspace}/bin/startkde" ''; }; @@ -54,6 +66,10 @@ in security.wrappers = { kcheckpass.source = "${lib.getBin plasma5.plasma-workspace}/lib/libexec/kcheckpass"; "start_kdeinit".source = "${lib.getBin pkgs.kinit}/lib/libexec/kf5/start_kdeinit"; + kwin_wayland = { + source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland"; + capabilities = "cap_sys_nice+ep"; + }; }; environment.systemPackages = with pkgs; with qt5; with libsForQt5; with plasma5; with kdeApplications; @@ -142,11 +158,13 @@ in kde-gtk-config breeze-gtk + qtvirtualkeyboard + libsForQt56.phonon-backend-gstreamer libsForQt5.phonon-backend-gstreamer ] - ++ lib.optionals cfg.enableQt4Support [ breeze-qt4 pkgs.phonon-backend-gstreamer ] + ++ lib.optionals cfg.enableQt4Support [ pkgs.phonon-backend-gstreamer ] # Optional hardware support features ++ lib.optional config.hardware.bluetooth.enable bluedevil @@ -193,16 +211,6 @@ in theme = mkDefault "breeze"; }; - boot.plymouth = { - theme = mkDefault "breeze"; - themePackages = mkDefault [ - (pkgs.breeze-plymouth.override { - nixosBranding = true; - nixosVersion = config.system.nixosRelease; - }) - ]; - }; - security.pam.services.kde = { allowNullPassword = true; }; # Doing these one by one seems silly, but we currently lack a better diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix index 9c42dc8781b9..c0c9d7ea47f7 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -3,15 +3,11 @@ with lib; let - - xcfg = config.services.xserver; - cfg = xcfg.desktopManager.xfce; - + cfg = config.services.xserver.desktopManager.xfce; in { options = { - services.xserver.desktopManager.xfce = { enable = mkOption { type = types.bool; @@ -54,81 +50,93 @@ in description = "Application used by XFCE to lock the screen."; }; }; - }; + config = mkIf cfg.enable { + environment.systemPackages = with pkgs.xfce // pkgs; [ + # Get GTK+ themes and gtk-update-icon-cache + gtk2.out + + # Supplies some abstract icons such as: + # utilities-terminal, accessories-text-editor + gnome3.defaultIconTheme + + hicolor_icon_theme + tango-icon-theme + xfce4-icon-theme + + desktop_file_utils + shared_mime_info + + # Needed by Xfce's xinitrc script + # TODO: replace with command -v + which + + exo + garcon + gtk-xfce-engine + gvfs + libxfce4ui + tumbler + xfconf + + mousepad + ristretto + xfce4-appfinder + xfce4-screenshooter + xfce4-session + xfce4-settings + xfce4-terminal + + (thunar.override { thunarPlugins = cfg.thunarPlugins; }) + thunar-volman # TODO: drop + ] ++ (if config.hardware.pulseaudio.enable + then [ xfce4-mixer-pulse xfce4-volumed-pulse ] + else [ xfce4-mixer xfce4-volumed ]) + # TODO: NetworkManager doesn't belong here + ++ optionals config.networking.networkmanager.enable [ networkmanagerapplet ] + ++ optionals config.powerManagement.enable [ xfce4-power-manager ] + ++ optionals cfg.enableXfwm [ xfwm4 ] + ++ optionals (!cfg.noDesktop) [ + xfce4-panel + xfce4-notifyd + xfdesktop + ]; + + environment.pathsToLink = [ + "/share/xfce4" + "/share/themes" + "/share/mime" + "/share/desktop-directories" + "/share/gtksourceview-2.0" + ]; + + environment.variables = { + GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; + GIO_EXTRA_MODULES = [ "${pkgs.xfce.gvfs}/lib/gio/modules" ]; + }; - config = mkIf (xcfg.enable && cfg.enable) { - - services.xserver.desktopManager.session = singleton - { name = "xfce"; - bgSupport = true; - start = - '' - ${cfg.extraSessionCommands} + services.xserver.desktopManager.session = [{ + name = "xfce"; + bgSupport = true; + start = '' + ${cfg.extraSessionCommands} - # Set GTK_PATH so that GTK+ can find the theme engines. - export GTK_PATH="${config.system.path}/lib/gtk-2.0:${config.system.path}/lib/gtk-3.0" + # Set GTK_PATH so that GTK+ can find the theme engines. + export GTK_PATH="${config.system.path}/lib/gtk-2.0:${config.system.path}/lib/gtk-3.0" - # Set GTK_DATA_PREFIX so that GTK+ can find the Xfce themes. - export GTK_DATA_PREFIX=${config.system.path} + # Set GTK_DATA_PREFIX so that GTK+ can find the Xfce themes. + export GTK_DATA_PREFIX=${config.system.path} - ${pkgs.stdenv.shell} ${pkgs.xfce.xinitrc} & - waitPID=$! - ''; - }; + ${pkgs.stdenv.shell} ${pkgs.xfce.xinitrc} & + waitPID=$! + ''; + }]; services.xserver.updateDbusEnvironment = true; - environment.systemPackages = - [ pkgs.gtk2.out # To get GTK+'s themes and gtk-update-icon-cache - pkgs.hicolor_icon_theme - pkgs.tango-icon-theme - pkgs.shared_mime_info - pkgs.which # Needed by the xfce's xinitrc script. - pkgs."${cfg.screenLock}" - pkgs.xfce.exo - pkgs.xfce.gtk_xfce_engine - pkgs.xfce.mousepad - pkgs.xfce.ristretto - pkgs.xfce.terminal - (pkgs.xfce.thunar.override { thunarPlugins = cfg.thunarPlugins; }) - pkgs.xfce.xfce4icontheme - pkgs.xfce.xfce4session - pkgs.xfce.xfce4settings - pkgs.xfce.xfce4mixer - pkgs.xfce.xfce4volumed - pkgs.xfce.xfce4-screenshooter - pkgs.xfce.xfconf - # This supplies some "abstract" icons such as - # "utilities-terminal" and "accessories-text-editor". - pkgs.gnome3.defaultIconTheme - pkgs.desktop_file_utils - pkgs.xfce.libxfce4ui - pkgs.xfce.garcon - pkgs.xfce.thunar_volman - pkgs.xfce.gvfs - pkgs.xfce.xfce4_appfinder - pkgs.xfce.tumbler # found via dbus - ] - ++ optional cfg.enableXfwm pkgs.xfce.xfwm4 - ++ optional config.powerManagement.enable pkgs.xfce.xfce4_power_manager - ++ optional config.networking.networkmanager.enable pkgs.networkmanagerapplet - ++ optionals (!cfg.noDesktop) - [ pkgs.xfce.xfce4panel - pkgs.xfce.xfdesktop - pkgs.xfce.xfce4notifyd # found via dbus - ]; - - environment.pathsToLink = - [ "/share/xfce4" "/share/themes" "/share/mime" "/share/desktop-directories" "/share/gtksourceview-2.0" ]; - - environment.variables.GIO_EXTRA_MODULES = [ "${pkgs.xfce.gvfs}/lib/gio/modules" ]; - # Enable helpful DBus services. services.udisks2.enable = true; services.upower.enable = config.powerManagement.enable; - }; - } diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index 3fa482fb6722..43ed21c95fee 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -59,12 +59,6 @@ let # Now it should be safe to assume that the script was called with the # expected parameters. - ${optionalString cfg.displayManager.logToJournal '' - if [ -z "$_DID_SYSTEMD_CAT" ]; then - _DID_SYSTEMD_CAT=1 exec ${config.systemd.package}/bin/systemd-cat -t xsession -- "$0" "$@" - fi - ''} - . /etc/profile cd "$HOME" @@ -72,16 +66,23 @@ let sessionType="$1" if [ "$sessionType" = default ]; then sessionType=""; fi - ${optionalString (!cfg.displayManager.job.logsXsession && !cfg.displayManager.logToJournal) '' - exec > ~/.xsession-errors 2>&1 - ''} - ${optionalString cfg.startDbusSession '' if test -z "$DBUS_SESSION_BUS_ADDRESS"; then exec ${pkgs.dbus.dbus-launch} --exit-with-session "$0" "$sessionType" fi ''} + ${optionalString cfg.displayManager.job.logToJournal '' + if [ -z "$_DID_SYSTEMD_CAT" ]; then + export _DID_SYSTEMD_CAT=1 + exec ${config.systemd.package}/bin/systemd-cat -t xsession "$0" "$sessionType" + fi + ''} + + ${optionalString cfg.displayManager.job.logToFile '' + exec &> >(tee ~/.xsession-errors) + ''} + # Start PulseAudio if enabled. ${optionalString (config.hardware.pulseaudio.enable) '' ${optionalString (!config.hardware.pulseaudio.systemWide) @@ -306,26 +307,24 @@ in description = "Additional environment variables needed by the display manager."; }; - logsXsession = mkOption { + logToFile = mkOption { type = types.bool; default = false; description = '' - Whether the display manager redirects the - output of the session script to - <filename>~/.xsession-errors</filename>. + Whether the display manager redirects the output of the + session script to <filename>~/.xsession-errors</filename>. ''; }; - }; + logToJournal = mkOption { + type = types.bool; + default = true; + description = '' + Whether the display manager redirects the output of the + session script to the systemd journal. + ''; + }; - logToJournal = mkOption { - type = types.bool; - default = true; - description = '' - By default, the stdout/stderr of sessions is written - to <filename>~/.xsession-errors</filename>. When this option - is enabled, it will instead be written to the journal. - ''; }; }; diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix index 1d5dcb2c7cbe..35b715b98fcd 100644 --- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix +++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix @@ -45,6 +45,8 @@ let theme-name = ${cfg.theme.name} icon-theme-name = ${cfg.iconTheme.name} background = ${ldmcfg.background} + ${optionalString (cfg.clock-format != null) "clock-format = ${cfg.clock-format}"} + ${optionalString (cfg.indicators != null) "indicators = ${concatStringsSep ";" cfg.indicators}"} ${cfg.extraConfig} ''; @@ -104,6 +106,35 @@ in }; + clock-format = mkOption { + type = types.nullOr types.str; + default = null; + example = "%F"; + description = '' + Clock format string (as expected by strftime, e.g. "%H:%M") + to use with the lightdm gtk greeter panel. + + If set to null the default clock format is used. + ''; + }; + + indicators = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + example = [ "~host" "~spacer" "~clock" "~spacer" "~session" "~language" "~a11y" "~power" ]; + description = '' + List of allowed indicator modules to use for the lightdm gtk + greeter panel. + + Built-in indicators include "~a11y", "~language", "~session", + "~power", "~clock", "~host", "~spacer". Unity indicators can be + represented by short name (e.g. "sound", "power"), service file name, + or absolute path. + + If set to null the default indicators are used. + ''; + }; + extraConfig = mkOption { type = types.lines; default = ""; diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 1733f2fd39b2..b5e936830918 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -190,7 +190,7 @@ in services.xserver.displayManager.slim.enable = false; services.xserver.displayManager.job = { - logsXsession = true; + logToFile = true; # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH execCmd = '' diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix index facaea131ae5..2d4cb8aa20a5 100644 --- a/nixos/modules/services/x11/display-managers/sddm.nix +++ b/nixos/modules/services/x11/display-managers/sddm.nix @@ -205,7 +205,7 @@ in services.xserver.displayManager.slim.enable = false; services.xserver.displayManager.job = { - logsXsession = true; + logToFile = true; environment = { # Load themes from system environment diff --git a/nixos/modules/services/x11/display-managers/xpra.nix b/nixos/modules/services/x11/display-managers/xpra.nix index 8f5ce3dccc6a..b46ede550c16 100644 --- a/nixos/modules/services/x11/display-managers/xpra.nix +++ b/nixos/modules/services/x11/display-managers/xpra.nix @@ -220,7 +220,7 @@ in ''; services.xserver.displayManager.job = { - logsXsession = true; + logToFile = true; execCmd = '' ${optionalString (cfg.pulseaudio) diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix index 5aecdef812e6..d0a87f183b6f 100644 --- a/nixos/modules/services/x11/hardware/libinput.nix +++ b/nixos/modules/services/x11/hardware/libinput.nix @@ -170,7 +170,7 @@ in { disableWhileTyping = mkOption { type = types.bool; - default = true; + default = false; description = '' Disable input method while typing. diff --git a/nixos/modules/services/x11/window-managers/2bwm.nix b/nixos/modules/services/x11/window-managers/2bwm.nix index e3f5ec7dbe67..fdbdf35b0f5a 100644 --- a/nixos/modules/services/x11/window-managers/2bwm.nix +++ b/nixos/modules/services/x11/window-managers/2bwm.nix @@ -25,12 +25,12 @@ in { name = "2bwm"; start = '' - ${pkgs."2bwm"}/bin/2bwm & + ${pkgs._2bwm}/bin/2bwm & waitPID=$! ''; }; - environment.systemPackages = [ pkgs."2bwm" ]; + environment.systemPackages = [ pkgs._2bwm ]; }; diff --git a/nixos/modules/services/x11/window-managers/awesome.nix b/nixos/modules/services/x11/window-managers/awesome.nix index eb97449c6bd9..71eb02ec5954 100644 --- a/nixos/modules/services/x11/window-managers/awesome.nix +++ b/nixos/modules/services/x11/window-managers/awesome.nix @@ -6,7 +6,11 @@ let cfg = config.services.xserver.windowManager.awesome; awesome = cfg.package; - inherit (pkgs.luaPackages) getLuaPath getLuaCPath; + getLuaPath = lib : dir : "${lib}/${dir}/lua/${pkgs.luaPackages.lua.luaversion}"; + makeSearchPath = lib.concatMapStrings (path: + " --search " + (getLuaPath path "share") + + " --search " + (getLuaPath path "lib") + ); in { @@ -46,10 +50,7 @@ in { name = "awesome"; start = '' - export LUA_CPATH="${lib.concatStringsSep ";" (map getLuaCPath cfg.luaModules)}" - export LUA_PATH="${lib.concatStringsSep ";" (map getLuaPath cfg.luaModules)}" - - ${awesome}/bin/awesome & + ${awesome}/bin/awesome ${makeSearchPath cfg.luaModules} & waitPID=$! ''; }; diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 1049f810ad2a..f96d3c5afbac 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -548,7 +548,7 @@ in knownVideoDrivers; in optional (driver != null) ({ inherit name; modules = []; driverName = name; } // driver)); - nixpkgs.config.xorg = optionalAttrs (elem "vboxvideo" cfg.videoDrivers) { abiCompat = "1.18"; }; + nixpkgs.config = optionalAttrs (elem "vboxvideo" cfg.videoDrivers) { xorg.abiCompat = "1.18"; }; assertions = [ { assertion = config.security.polkit.enable; @@ -578,6 +578,22 @@ in target = "X11/xkb"; } ]) + # localectl looks into 00-keyboard.conf + ++ [ + { + text = '' + Section "InputClass" + Identifier "Keyboard catchall" + MatchIsKeyboard "on" + Option "XkbModel" "${cfg.xkbModel}" + Option "XkbLayout" "${cfg.layout}" + Option "XkbOptions" "${cfg.xkbOptions}" + Option "XkbVariant" "${cfg.xkbVariant}" + EndSection + ''; + target = "X11/xorg.conf.d/00-keyboard.conf"; + } + ] # Needed since 1.18; see https://bugs.freedesktop.org/show_bug.cgi?id=89023#c5 ++ (let cfgPath = "/X11/xorg.conf.d/10-evdev.conf"; in [{ @@ -697,15 +713,6 @@ in ${cfg.monitorSection} EndSection - Section "InputClass" - Identifier "Keyboard catchall" - MatchIsKeyboard "on" - Option "XkbModel" "${cfg.xkbModel}" - Option "XkbLayout" "${cfg.layout}" - Option "XkbOptions" "${cfg.xkbOptions}" - Option "XkbVariant" "${cfg.xkbVariant}" - EndSection - # Additional "InputClass" sections ${flip concatMapStrings cfg.inputClassSections (inputClassSection: '' Section "InputClass" diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 0c50241f2edf..091a2e412eed 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -30,6 +30,8 @@ let let kernelPath = "${config.boot.kernelPackages.kernel}/" + "${config.system.boot.loader.kernelFile}"; + initrdPath = "${config.system.build.initialRamdisk}/" + + "${config.system.boot.loader.initrdFile}"; in '' mkdir $out @@ -50,7 +52,7 @@ let echo -n "$kernelParams" > $out/kernel-params - ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd + ln -s ${initrdPath} $out/initrd ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out @@ -106,7 +108,7 @@ let if [] == failed then pkgs.stdenvNoCC.mkDerivation { name = let hn = config.networking.hostName; nn = if (hn != "") then hn else "unnamed"; - in "nixos-system-${nn}-${config.system.nixosLabel}"; + in "nixos-system-${nn}-${config.system.nixos.label}"; preferLocalBuild = true; allowSubstitutes = false; buildCommand = systemBuilder; @@ -120,7 +122,7 @@ let config.system.build.installBootLoader or "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true"; activationScript = config.system.activationScripts.script; - nixosLabel = config.system.nixosLabel; + nixosLabel = config.system.nixos.label; configurationName = config.boot.loader.grub.configurationName; @@ -179,6 +181,15 @@ in ''; }; + system.boot.loader.initrdFile = mkOption { + internal = true; + default = "initrd"; + type = types.str; + description = '' + Name of the initrd file to be passed to the bootloader. + ''; + }; + system.copySystemConfiguration = mkOption { type = types.bool; default = false; diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix new file mode 100644 index 000000000000..15e84dc021e2 --- /dev/null +++ b/nixos/modules/system/boot/binfmt.nix @@ -0,0 +1,139 @@ +{ config, lib, ... }: +let + inherit (lib) mkOption types optionalString; + + cfg = config.boot.binfmtMiscRegistrations; + + makeBinfmtLine = name: { recognitionType, offset, magicOrExtension + , mask, preserveArgvZero, openBinary + , matchCredentials, fixBinary, ... + }: let + type = if recognitionType == "magic" then "M" else "E"; + offset' = toString offset; + mask' = toString mask; + interpreter = "/run/binfmt/${name}"; + flags = if !(matchCredentials -> openBinary) + then throw "boot.binfmtMiscRegistrations.${name}: you can't specify openBinary = false when matchCredentials = true." + else optionalString preserveArgvZero "P" + + optionalString (openBinary && !matchCredentials) "O" + + optionalString matchCredentials "C" + + optionalString fixBinary "F"; + in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}"; + + binfmtFile = builtins.toFile "binfmt_nixos.conf" + (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg)); + + activationSnippet = name: { interpreter, ... }: + "ln -sf ${interpreter} /run/binfmt/${name}"; + activationScript = '' + mkdir -p -m 0755 /run/binfmt + ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg)} + ''; +in { + options = { + boot.binfmtMiscRegistrations = mkOption { + default = {}; + + description = '' + Extra binary formats to register with the kernel. + See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details. + ''; + + type = types.attrsOf (types.submodule ({ config, ... }: { + options = { + recognitionType = mkOption { + default = "magic"; + description = "Whether to recognize executables by magic number or extension."; + type = types.enum [ "magic" "extension" ]; + }; + + offset = mkOption { + default = null; + description = "The byte offset of the magic number used for recognition."; + type = types.nullOr types.int; + }; + + magicOrExtension = mkOption { + description = "The magic number or extension to match on."; + type = types.str; + }; + + mask = mkOption { + default = null; + description = + "A mask to be ANDed with the byte sequence of the file before matching"; + type = types.nullOr types.str; + }; + + interpreter = mkOption { + description = '' + The interpreter to invoke to run the program. + + Note that the actual registration will point to + /run/binfmt/''${name}, so the kernel interpreter length + limit doesn't apply. + ''; + type = types.path; + }; + + preserveArgvZero = mkOption { + default = false; + description = '' + Whether to pass the original argv[0] to the interpreter. + + See the description of the 'P' flag in the kernel docs + for more details; + ''; + type = types.bool; + }; + + openBinary = mkOption { + default = config.matchCredentials; + description = '' + Whether to pass the binary to the interpreter as an open + file descriptor, instead of a path. + ''; + type = types.bool; + }; + + matchCredentials = mkOption { + default = false; + description = '' + Whether to launch with the credentials and security + token of the binary, not the interpreter (e.g. setuid + bit). + + See the description of the 'C' flag in the kernel docs + for more details. + + Implies/requires openBinary = true. + ''; + type = types.bool; + }; + + fixBinary = mkOption { + default = false; + description = '' + Whether to open the interpreter file as soon as the + registration is loaded, rather than waiting for a + relevant file to be invoked. + + See the description of the 'F' flag in the kernel docs + for more details. + ''; + type = types.bool; + }; + }; + })); + }; + }; + + config = lib.mkIf (cfg != {}) { + environment.etc."binfmt.d/nixos.conf".source = binfmtFile; + system.activationScripts.binfmt = activationScript; + systemd.additionalUpstreamSystemUnits = + [ "proc-sys-fs-binfmt_misc.automount" + "proc-sys-fs-binfmt_misc.mount" + ]; + }; +} diff --git a/nixos/modules/system/boot/grow-partition.nix b/nixos/modules/system/boot/grow-partition.nix new file mode 100644 index 000000000000..c4c6d82dc5c8 --- /dev/null +++ b/nixos/modules/system/boot/grow-partition.nix @@ -0,0 +1,43 @@ +# This module automatically grows the root partition. +# This allows an instance to be created with a bigger root filesystem +# than provided by the machine image. + +{ config, lib, pkgs, ... }: + +with lib; + +{ + + options = { + boot.growPartition = mkEnableOption "grow the root partition on boot"; + }; + + config = mkIf config.boot.growPartition { + + boot.initrd.extraUtilsCommands = '' + copy_bin_and_libs ${pkgs.gawk}/bin/gawk + copy_bin_and_libs ${pkgs.gnused}/bin/sed + copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk + copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk + + substitute "${pkgs.cloud-utils}/bin/.growpart-wrapped" "$out/bin/growpart" \ + --replace "${pkgs.bash}/bin/sh" "/bin/sh" \ + --replace "awk" "gawk" \ + --replace "sed" "gnused" + + ln -s sed $out/bin/gnused + ''; + + boot.initrd.postDeviceCommands = '' + rootDevice="${config.fileSystems."/".device}" + if [ -e "$rootDevice" ]; then + rootDevice="$(readlink -f "$rootDevice")" + parentDevice="$(lsblk -npo PKNAME "$rootDevice")" + TMPDIR=/run sh $(type -P growpart) "$parentDevice" "''${rootDevice#$parentDevice}" + udevadm settle + fi + ''; + + }; + +} diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index 6e226c190609..4a6e1c7e56e5 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -40,6 +40,10 @@ in kernel documentation</link>. Otherwise, if <option>networking.useDHCP</option> is enabled, an IP address is acquired using DHCP. + + You should add the module(s) required for your network card to + boot.initrd.availableKernelModules. lspci -v -s <ethernet controller> + will tell you which. ''; }; diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix index d78775c27582..cdeff4845948 100644 --- a/nixos/modules/system/boot/initrd-ssh.nix +++ b/nixos/modules/system/boot/initrd-ssh.nix @@ -89,9 +89,6 @@ in config = mkIf (config.boot.initrd.network.enable && cfg.enable) { assertions = [ - { assertion = cfg.hostRSAKey != null || cfg.hostDSSKey != null || cfg.hostECDSAKey != null; - message = "You should specify at least one host key for initrd SSH"; - } { assertion = cfg.authorizedKeys != []; message = "You should specify at least one authorized key for initrd SSH"; } @@ -121,7 +118,7 @@ in echo ${escapeShellArg key} >> /root/.ssh/authorized_keys '') cfg.authorizedKeys)} - dropbear -s -j -k -E -m -p ${toString cfg.port} + dropbear -s -j -k -E -m -p ${toString cfg.port} ${optionalString (cfg.hostRSAKey == null && cfg.hostDSSKey == null && cfg.hostECDSAKey == null) "-R"} ''; boot.initrd.secrets = diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 4db9631743e3..3bd7d3558269 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -5,7 +5,7 @@ with lib; let inherit (config.boot) kernelPatches; - + inherit (config.boot.kernel) features; inherit (config.boot.kernelPackages) kernel; kernelModulesConf = pkgs.writeText "nixos.conf" @@ -21,11 +21,25 @@ in options = { + boot.kernel.features = mkOption { + default = {}; + example = literalExample "{ debug = true; }"; + internal = true; + description = '' + This option allows to enable or disable certain kernel features. + It's not API, because it's about kernel feature sets, that + make sense for specific use cases. Mostly along with programs, + which would have separate nixos options. + `grep features pkgs/os-specific/linux/kernel/common-config.nix` + ''; + }; + boot.kernelPackages = mkOption { default = pkgs.linuxPackages; apply = kernelPackages: kernelPackages.extend (self: super: { kernel = super.kernel.override { kernelPatches = super.kernel.kernelPatches ++ kernelPatches; + features = lib.recursiveUpdate super.kernel.features features; }; }); # We don't want to evaluate all of linuxPackages for the manual @@ -170,7 +184,7 @@ in [ "loglevel=${toString config.boot.consoleLogLevel}" ] ++ optionals config.boot.vesa [ "vga=0x317" ]; - boot.kernel.sysctl."kernel.printk" = config.boot.consoleLogLevel; + boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel; boot.kernelModules = [ "loop" "atkbd" ]; @@ -197,7 +211,7 @@ in "mmc_block" # Support USB keyboards, in case the boot fails and we only have - # a USB keyboard. + # a USB keyboard, or for LUKS passphrase prompt. "uhci_hcd" "ehci_hcd" "ehci_pci" @@ -207,11 +221,13 @@ in "xhci_pci" "usbhid" "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat" + "hid_logitech_hidpp" "hid_logitech_dj" - # Misc. keyboard stuff. + ] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [ + # Misc. x86 keyboard stuff. "pcips2" "atkbd" "i8042" - # Needed by the stage 2 init script. + # x86 RTC needed by the stage 2 init script. "rtc_cmos" ]; diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index 06f004fb06ec..eefee5a479e7 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -227,6 +227,11 @@ in default = [ "aes" "aes_generic" "blowfish" "twofish" "serpent" "cbc" "xts" "lrw" "sha1" "sha256" "sha512" + + # workaround until https://marc.info/?l=linux-crypto-vger&m=148783562211457&w=4 is merged + # remove once 'modprobe --show-depends xts' shows ecb as a dependency + "ecb" + (if pkgs.stdenv.system == "x86_64-linux" then "aes_x86_64" else "aes_i586") ]; description = '' @@ -434,7 +439,9 @@ in ["firewire_ohci" "firewire_core" "firewire_sbp2"]; # Some modules that may be needed for mounting anything ciphered - boot.initrd.availableKernelModules = [ "dm_mod" "dm_crypt" "cryptd" ] ++ luks.cryptoModules; + # Also load input_leds to get caps lock light working (#12456) + boot.initrd.availableKernelModules = [ "dm_mod" "dm_crypt" "cryptd" "input_leds" ] + ++ luks.cryptoModules; # copy the cryptsetup binary and it's dependencies boot.initrd.extraUtilsCommands = '' diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 9d2cea3ad165..eea10613ea58 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -94,7 +94,7 @@ let checkNetwork = checkUnitConfig "Network" [ (assertOnlyFields [ "Description" "DHCP" "DHCPServer" "IPForward" "IPMasquerade" "IPv4LL" "IPv4LLRoute" - "LLMNR" "MulticastDNS" "Domains" "Bridge" "Bond" + "LLMNR" "MulticastDNS" "Domains" "Bridge" "Bond" "IPv6PrivacyExtensions" ]) (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"]) (assertValueOneOf "DHCPServer" boolValues) @@ -104,6 +104,7 @@ let (assertValueOneOf "IPv4LLRoute" boolValues) (assertValueOneOf "LLMNR" boolValues) (assertValueOneOf "MulticastDNS" boolValues) + (assertValueOneOf "IPv6PrivacyExtensions" ["yes" "no" "prefer-public" "kernel"]) ]; checkAddress = checkUnitConfig "Address" [ @@ -700,7 +701,6 @@ in systemd.additionalUpstreamSystemUnits = [ "systemd-networkd.service" "systemd-networkd-wait-online.service" - "org.freedesktop.network1.busname" ]; systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix index 4b0c498424b5..f8fb8a64cb9b 100644 --- a/nixos/modules/system/boot/plymouth.nix +++ b/nixos/modules/system/boot/plymouth.nix @@ -8,9 +8,14 @@ let cfg = config.boot.plymouth; + breezePlymouth = pkgs.breeze-plymouth.override { + nixosBranding = true; + nixosVersion = config.system.nixos.release; + }; + themesEnv = pkgs.buildEnv { name = "plymouth-themes"; - paths = [ plymouth ] ++ cfg.themePackages; + paths = [ plymouth breezePlymouth ] ++ cfg.themePackages; }; configFile = pkgs.writeText "plymouthd.conf" '' @@ -38,7 +43,7 @@ in }; theme = mkOption { - default = "fade-in"; + default = "breeze"; type = types.str; description = '' Splash screen theme. diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix index 2147d43c4f19..4d9de020c84e 100644 --- a/nixos/modules/system/boot/resolved.nix +++ b/nixos/modules/system/boot/resolved.nix @@ -126,7 +126,7 @@ in config = mkIf cfg.enable { systemd.additionalUpstreamSystemUnits = [ - "systemd-resolved.service" "org.freedesktop.resolve1.busname" + "systemd-resolved.service" ]; systemd.services.systemd-resolved = { diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index b442386914ad..964ec68cfe2f 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -167,6 +167,7 @@ done # Load the required kernel modules. mkdir -p /lib ln -s @modulesClosure@/lib/modules /lib/modules +ln -s @modulesClosure@/lib/firmware /lib/firmware echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe for i in @kernelModules@; do echo "loading module $(basename $i)..." diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index d6e3e3a87d01..df450be8c401 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -13,12 +13,14 @@ let kernelPackages = config.boot.kernelPackages; modulesTree = config.system.modulesTree; + firmware = config.hardware.firmware; # Determine the set of modules that we need to mount the root FS. modulesClosure = pkgs.makeModulesClosure { rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; kernel = modulesTree; + firmware = firmware; allowMissing = true; }; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index dd9ba7104485..aff46ea861a2 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -14,7 +14,6 @@ let upstreamSystemUnits = [ # Targets. "basic.target" - "busnames.target" "sysinit.target" "sockets.target" "exit.target" @@ -47,6 +46,7 @@ let # Consoles. "getty.target" + "getty-pre.target" "getty@.service" "serial-getty@.service" "console-getty.service" @@ -63,10 +63,7 @@ let "systemd-logind.service" "autovt@.service" "systemd-user-sessions.service" - "dbus-org.freedesktop.login1.service" "dbus-org.freedesktop.machine1.service" - "org.freedesktop.login1.busname" - "org.freedesktop.machine1.busname" "user@.service" # Journal. @@ -99,7 +96,6 @@ let "swap.target" "dev-hugepages.mount" "dev-mqueue.mount" - "proc-sys-fs-binfmt_misc.mount" "sys-fs-fuse-connections.mount" "sys-kernel-config.mount" "sys-kernel-debug.mount" @@ -155,19 +151,16 @@ let "systemd-tmpfiles-setup-dev.service" # Misc. - "org.freedesktop.systemd1.busname" "systemd-sysctl.service" "dbus-org.freedesktop.timedate1.service" "dbus-org.freedesktop.locale1.service" "dbus-org.freedesktop.hostname1.service" - "org.freedesktop.timedate1.busname" - "org.freedesktop.locale1.busname" - "org.freedesktop.hostname1.busname" "systemd-timedated.service" "systemd-localed.service" "systemd-hostnamed.service" "systemd-binfmt.service" "systemd-exit.service" + "systemd-update-done.service" ] ++ cfg.additionalUpstreamSystemUnits; @@ -182,7 +175,6 @@ let upstreamUserUnits = [ "basic.target" "bluetooth.target" - "busnames.target" "default.target" "exit.target" "graphical-session-pre.target" @@ -789,8 +781,7 @@ in # Keep a persistent journal. Note that systemd-tmpfiles will # set proper ownership/permissions. - # FIXME: revert to 0700 with systemd v233. - mkdir -m 0750 -p /var/log/journal + mkdir -m 0700 -p /var/log/journal ''; users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; @@ -887,7 +878,7 @@ in systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; - systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ]; + systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.mount" ]; # Don't bother with certain units in containers. systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; diff --git a/nixos/modules/tasks/filesystems/btrfs.nix b/nixos/modules/tasks/filesystems/btrfs.nix index 8cfa1b6921d3..1384873b6631 100644 --- a/nixos/modules/tasks/filesystems/btrfs.nix +++ b/nixos/modules/tasks/filesystems/btrfs.nix @@ -1,35 +1,132 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, utils, ... }: with lib; let inInitrd = any (fs: fs == "btrfs") config.boot.initrd.supportedFilesystems; + inSystem = any (fs: fs == "btrfs") config.boot.supportedFilesystems; + + cfgScrub = config.services.btrfs.autoScrub; + + enableAutoScrub = cfgScrub.enable; + enableBtrfs = inInitrd || inSystem || enableAutoScrub; in { - config = mkIf (any (fs: fs == "btrfs") config.boot.supportedFilesystems) { + options = { + # One could also do regular btrfs balances, but that shouldn't be necessary + # during normal usage and as long as the filesystems aren't filled near capacity + services.btrfs.autoScrub = { + enable = mkEnableOption "Enable regular btrfs scrub"; - system.fsPackages = [ pkgs.btrfs-progs ]; + fileSystems = mkOption { + type = types.listOf types.path; + example = [ "/" ]; + description = '' + List of paths to btrfs filesystems to regularily call <command>btrfs scrub</command> on. + Defaults to all mount points with btrfs filesystems. + If you mount a filesystem multiple times or additionally mount subvolumes, + you need to manually specify this list to avoid scrubbing multiple times. + ''; + }; - boot.initrd.kernelModules = mkIf inInitrd [ "btrfs" "crc32c" ]; + interval = mkOption { + default = "monthly"; + type = types.str; + example = "weekly"; + description = '' + Systemd calendar expression for when to scrub btrfs filesystems. + The recommended period is a month but could be less + (<citerefentry><refentrytitle>btrfs-scrub</refentrytitle> + <manvolnum>8</manvolnum></citerefentry>). + See + <citerefentry><refentrytitle>systemd.time</refentrytitle> + <manvolnum>7</manvolnum></citerefentry> + for more information on the syntax. + ''; + }; + + }; + }; - boot.initrd.extraUtilsCommands = mkIf inInitrd + config = mkMerge [ + (mkIf enableBtrfs { + system.fsPackages = [ pkgs.btrfs-progs ]; + + boot.initrd.kernelModules = mkIf inInitrd [ "btrfs" "crc32c" ]; + + boot.initrd.extraUtilsCommands = mkIf inInitrd '' copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfs ln -sv btrfs $out/bin/btrfsck ln -sv btrfsck $out/bin/fsck.btrfs ''; - boot.initrd.extraUtilsCommandsTest = mkIf inInitrd + boot.initrd.extraUtilsCommandsTest = mkIf inInitrd '' $out/bin/btrfs --version ''; - boot.initrd.postDeviceCommands = mkIf inInitrd + boot.initrd.postDeviceCommands = mkIf inInitrd '' btrfs device scan ''; - }; + }) + + (mkIf enableAutoScrub { + assertions = [ + { + assertion = cfgScrub.enable -> (cfgScrub.fileSystems != []); + message = '' + If 'services.btrfs.autoScrub' is enabled, you need to have at least one + btrfs file system mounted via 'fileSystems' or specify a list manually + in 'services.btrfs.autoScrub.fileSystems'. + ''; + } + ]; + + # This will yield duplicated units if the user mounts a filesystem multiple times + # or additionally mounts subvolumes, but going the other way around via devices would + # yield duplicated units when a filesystem spans multiple devices. + # This way around seems like the more sensible default. + services.btrfs.autoScrub.fileSystems = mkDefault (mapAttrsToList (name: fs: fs.mountPoint) + (filterAttrs (name: fs: fs.fsType == "btrfs") config.fileSystems)); + + # TODO: Did not manage to do it via the usual btrfs-scrub@.timer/.service + # template units due to problems enabling the parameterized units, + # so settled with many units and templating via nix for now. + # https://github.com/NixOS/nixpkgs/pull/32496#discussion_r156527544 + systemd.timers = let + scrubTimer = fs: let + fs' = utils.escapeSystemdPath fs; + in nameValuePair "btrfs-scrub-${fs'}" { + description = "regular btrfs scrub timer on ${fs}"; + + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfgScrub.interval; + AccuracySec = "1d"; + Persistent = true; + }; + }; + in listToAttrs (map scrubTimer cfgScrub.fileSystems); + + systemd.services = let + scrubService = fs: let + fs' = utils.escapeSystemdPath fs; + in nameValuePair "btrfs-scrub-${fs'}" { + description = "btrfs scrub on ${fs}"; + + serviceConfig = { + Type = "oneshot"; + Nice = 19; + IOSchedulingClass = "idle"; + ExecStart = "${pkgs.btrfs-progs}/bin/btrfs scrub start -B ${fs}"; + }; + }; + in listToAttrs (map scrubService cfgScrub.fileSystems); + }) + ]; } diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 7fee99115329..30c54ddd0e4e 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -24,7 +24,11 @@ let kernel = config.boot.kernelPackages; - packages = if config.boot.zfs.enableUnstable then { + packages = if config.boot.zfs.enableLegacyCrypto then { + spl = kernel.splLegacyCrypto; + zfs = kernel.zfsLegacyCrypto; + zfsUser = pkgs.zfsLegacyCrypto; + } else if config.boot.zfs.enableUnstable then { spl = kernel.splUnstable; zfs = kernel.zfsUnstable; zfsUser = pkgs.zfsUnstable; @@ -75,6 +79,27 @@ in ''; }; + enableLegacyCrypto = mkOption { + type = types.bool; + default = false; + description = '' + Enabling this option will allow you to continue to use the old format for + encrypted datasets. With the inclusion of stability patches the format of + encrypted datasets has changed. They can still be accessed and mounted but + in read-only mode mounted. It is highly recommended to convert them to + the new format. + + This option is only for convenience to people that cannot convert their + datasets to the new format yet and it will be removed in due time. + + For migration strategies from old format to this new one, check the Wiki: + https://nixos.wiki/wiki/NixOS_on_ZFS#Encrypted_Dataset_Format_Change + + See https://github.com/zfsonlinux/zfs/pull/6864 for more details about + the stability patches. + ''; + }; + extraPools = mkOption { type = types.listOf types.str; default = []; @@ -268,7 +293,7 @@ in assertions = [ { assertion = config.networking.hostId != null; - message = "ZFS requires config.networking.hostId to be set"; + message = "ZFS requires networking.hostId to be set"; } { assertion = !cfgZfs.forceImportAll || cfgZfs.forceImportRoot; diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 1f424f84c6e0..8aa5163ce229 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -20,14 +20,8 @@ let "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; interfaceIps = i: - i.ip4 ++ optionals cfg.enableIPv6 i.ip6 - ++ optional (i.ipAddress != null) { - address = i.ipAddress; - prefixLength = i.prefixLength; - } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) { - address = i.ipv6Address; - prefixLength = i.ipv6PrefixLength; - }; + i.ipv4.addresses + ++ optionals cfg.enableIPv6 i.ipv6.addresses; destroyBond = i: '' while true; do @@ -80,7 +74,7 @@ let else optional (dev != null && dev != "lo" && !config.boot.isContainer) (subsystemDevice dev); hasDefaultGatewaySet = (cfg.defaultGateway != null && cfg.defaultGateway.address != "") - || (cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); + || (cfg.enableIPv6 && cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); networkLocalCommands = { after = [ "network-setup.service" ]; @@ -185,33 +179,58 @@ let path = [ pkgs.iproute ]; script = '' - # FIXME: shouldn't this be done in network-link? - echo "bringing up interface..." - ip link set "${i.name}" up - state="/run/nixos/network/addresses/${i.name}" + mkdir -p $(dirname "$state") + ${flip concatMapStrings ips (ip: + let + cidr = "${ip.address}/${toString ip.prefixLength}"; + in + '' + echo "${cidr}" >> $state + echo -n "adding address ${cidr}... " + if out=$(ip addr add "${cidr}" dev "${i.name}" 2>&1); then + echo "done" + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed" + exit 1 + fi + '' + )} + + state="/run/nixos/network/routes/${i.name}" mkdir -p $(dirname "$state") - '' + flip concatMapStrings (ips) (ip: - let - address = "${ip.address}/${toString ip.prefixLength}"; - in - '' - echo "${address}" >> $state - if out=$(ip addr add "${address}" dev "${i.name}" 2>&1); then - echo "added ip ${address}" - elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then - echo "failed to add ${address}" - exit 1 - fi - ''); + ${flip concatMapStrings (i.ipv4.routes ++ i.ipv6.routes) (route: + let + cidr = "${route.address}/${toString route.prefixLength}"; + via = optionalString (route.via != null) ''via "${route.via}"''; + options = concatStrings (mapAttrsToList (name: val: "${name} ${val} ") route.options); + in + '' + echo "${cidr}" >> $state + echo -n "adding route ${cidr}... " + if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" 2>&1); then + echo "done" + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed" + exit 1 + fi + '' + )} + ''; preStop = '' + state="/run/nixos/network/routes/${i.name}" + while read cidr; do + echo -n "deleting route $cidr... " + ip route del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" + done < "$state" + rm -f "$state" + state="/run/nixos/network/addresses/${i.name}" - while read address; do - echo -n "deleting $address..." - ip addr del "$address" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed" - echo "" + while read cidr; do + echo -n "deleting address $cidr... " + ip addr del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" done < "$state" rm -f "$state" ''; @@ -230,9 +249,7 @@ let RemainAfterExit = true; }; script = '' - ip tuntap add dev "${i.name}" \ - ${optionalString (i.virtualType != null) "mode ${i.virtualType}"} \ - user "${i.virtualOwner}" + ip tuntap add dev "${i.name}" mode "${i.virtualType}" user "${i.virtualOwner}" ''; postStop = '' ip link del ${i.name} || true diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index a365a01bfb1e..c640e886fca8 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -9,14 +9,8 @@ let interfaces = attrValues cfg.interfaces; interfaceIps = i: - i.ip4 ++ optionals cfg.enableIPv6 i.ip6 - ++ optional (i.ipAddress != null) { - address = i.ipAddress; - prefixLength = i.prefixLength; - } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) { - address = i.ipv6Address; - prefixLength = i.ipv6PrefixLength; - }; + i.ipv4.addresses + ++ optionals cfg.enableIPv6 i.ipv6.addresses; dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "both" else "none"; @@ -74,27 +68,24 @@ in networks."99-main" = genericNetwork mkDefault; } (mkMerge (flip map interfaces (i: { - netdevs = mkIf i.virtual ( - let - devType = if i.virtualType != null then i.virtualType - else (if hasPrefix "tun" i.name then "tun" else "tap"); - in { - "40-${i.name}" = { - netdevConfig = { - Name = i.name; - Kind = devType; - }; - "${devType}Config" = optionalAttrs (i.virtualOwner != null) { - User = i.virtualOwner; - }; + netdevs = mkIf i.virtual ({ + "40-${i.name}" = { + netdevConfig = { + Name = i.name; + Kind = i.virtualType; + }; + "${i.virtualType}Config" = optionalAttrs (i.virtualOwner != null) { + User = i.virtualOwner; }; - }); + }; + }); networks."40-${i.name}" = mkMerge [ (genericNetwork mkDefault) { name = mkDefault i.name; DHCP = mkForce (dhcpStr (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ])); address = flip map (interfaceIps i) (ip: "${ip.address}/${toString ip.prefixLength}"); + networkConfig.IPv6PrivacyExtensions = "kernel"; } ]; }))) (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index b7e85e402aa9..5036b701bd86 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, utils, stdenv, ... }: +{ config, options, lib, pkgs, utils, stdenv, ... }: with lib; with utils; @@ -101,7 +101,7 @@ let address = mkOption { type = types.str; description = '' - IPv${toString v} address of the interface. Leave empty to configure the + IPv${toString v} address of the interface. Leave empty to configure the interface using DHCP. ''; }; @@ -116,6 +116,40 @@ let }; }; + routeOpts = v: + { options = { + address = mkOption { + type = types.str; + description = "IPv${toString v} address of the network."; + }; + + prefixLength = mkOption { + type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); + description = '' + Subnet mask of the network, specified as the number of + bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>). + ''; + }; + + via = mkOption { + type = types.nullOr types.str; + default = null; + description = "IPv${toString v} address of the next hop."; + }; + + options = mkOption { + type = types.attrsOf types.str; + default = { }; + example = { mtu = "1492"; window = "524288"; }; + description = '' + Other route options. See the symbol <literal>OPTION</literal> + in the <literal>ip-route(8)</literal> manual page for the details. + ''; + }; + + }; + }; + gatewayCoerce = address: { inherit address; }; gatewayOpts = { ... }: { @@ -148,13 +182,22 @@ let interfaceOpts = { name, ... }: { options = { - name = mkOption { example = "eth0"; type = types.str; description = "Name of the interface."; }; + preferTempAddress = mkOption { + type = types.bool; + default = cfg.enableIPv6; + defaultText = literalExample "config.networking.enableIpv6"; + description = '' + When using SLAAC prefer a temporary (IPv6) address over the EUI-64 + address for originating connections. This is used to reduce tracking. + ''; + }; + useDHCP = mkOption { type = types.nullOr types.bool; default = null; @@ -165,7 +208,7 @@ let ''; }; - ip4 = mkOption { + ipv4.addresses = mkOption { default = [ ]; example = [ { address = "10.0.0.1"; prefixLength = 16; } @@ -177,7 +220,7 @@ let ''; }; - ip6 = mkOption { + ipv6.addresses = mkOption { default = [ ]; example = [ { address = "fdfd:b3f0:482::1"; prefixLength = 48; } @@ -189,50 +232,27 @@ let ''; }; - ipAddress = mkOption { - default = null; - example = "10.0.0.1"; - type = types.nullOr types.str; - description = '' - IP address of the interface. Leave empty to configure the - interface using DHCP. - ''; - }; - - prefixLength = mkOption { - default = null; - example = 24; - type = types.nullOr types.int; - description = '' - Subnet mask of the interface, specified as the number of - bits in the prefix (<literal>24</literal>). - ''; - }; - - subnetMask = mkOption { - default = null; - description = '' - Defunct, supply the prefix length instead. - ''; - }; - - ipv6Address = mkOption { - default = null; - example = "2001:1470:fffd:2098::e006"; - type = types.nullOr types.str; + ipv4.routes = mkOption { + default = []; + example = [ + { address = "10.0.0.0"; prefixLength = 16; } + { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } + ]; + type = with types; listOf (submodule (routeOpts 4)); description = '' - IPv6 address of the interface. Leave empty to configure the - interface using NDP. + List of extra IPv4 static routes that will be assigned to the interface. ''; }; - ipv6PrefixLength = mkOption { - default = 64; - example = 64; - type = types.int; + ipv6.routes = mkOption { + default = []; + example = [ + { address = "fdfd:b3f0::"; prefixLength = 48; } + { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } + ]; + type = with types; listOf (submodule (routeOpts 6)); description = '' - Subnet mask of the interface, specified as the number of - bits in the prefix (<literal>64</literal>). + List of extra IPv6 static routes that will be assigned to the interface. ''; }; @@ -273,11 +293,13 @@ let }; virtualType = mkOption { - default = null; - type = with types; nullOr (enum [ "tun" "tap" ]); + default = if hasPrefix "tun" name then "tun" else "tap"; + defaultText = literalExample ''if hasPrefix "tun" name then "tun" else "tap"''; + type = with types; enum [ "tun" "tap" ]; description = '' - The explicit type of interface to create. Accepts tun or tap strings. - Also accepts null to implicitly detect the type of device. + The type of interface to create. + The default is TUN for an interface name starting + with "tun", otherwise TAP. ''; }; @@ -305,6 +327,32 @@ let name = mkDefault name; }; + # Renamed or removed options + imports = + let + defined = x: x != "_mkMergedOptionModule"; + in [ + (mkRenamedOptionModule [ "ip4" ] [ "ipv4" "addresses"]) + (mkRenamedOptionModule [ "ip6" ] [ "ipv6" "addresses"]) + (mkRemovedOptionModule [ "subnetMask" ] '' + Supply a prefix length instead; use option + networking.interfaces.<name>.ipv{4,6}.addresses'') + (mkMergedOptionModule + [ [ "ipAddress" ] [ "prefixLength" ] ] + [ "ipv4" "addresses" ] + (cfg: with cfg; + optional (defined ipAddress && defined prefixLength) + { address = ipAddress; prefixLength = prefixLength; })) + (mkMergedOptionModule + [ [ "ipv6Address" ] [ "ipv6PrefixLength" ] ] + [ "ipv6" "addresses" ] + (cfg: with cfg; + optional (defined ipv6Address && defined ipv6PrefixLength) + { address = ipv6Address; prefixLength = ipv6PrefixLength; })) + + ({ options.warnings = options.warnings; }) + ]; + }; hexChars = stringToCharacters "0123456789abcdef"; @@ -441,7 +489,7 @@ in networking.interfaces = mkOption { default = {}; example = - { eth0.ip4 = [ { + { eth0.ipv4 = [ { address = "131.211.84.78"; prefixLength = 25; } ]; @@ -920,13 +968,10 @@ in config = { + warnings = concatMap (i: i.warnings) interfaces; + assertions = (flip map interfaces (i: { - assertion = i.subnetMask == null; - message = '' - The networking.interfaces."${i.name}".subnetMask option is defunct. Use prefixLength instead. - ''; - })) ++ (flip map interfaces (i: { # With the linux kernel, interface name length is limited by IFNAMSIZ # to 16 bytes, including the trailing null byte. # See include/linux/if.h in the kernel sources @@ -935,10 +980,15 @@ in The name of networking.interfaces."${i.name}" is too long, it needs to be less than 16 characters. ''; })) ++ (flip map slaveIfs (i: { - assertion = i.ip4 == [ ] && i.ipAddress == null && i.ip6 == [ ] && i.ipv6Address == null; + assertion = i.ipv4.addresses == [ ] && i.ipv6.addresses == [ ]; message = '' The networking.interfaces."${i.name}" must not have any defined ips when it is a slave. ''; + })) ++ (flip map interfaces (i: { + assertion = i.preferTempAddress -> cfg.enableIPv6; + message = '' + Temporary addresses are only needed when IPv6 is enabled. + ''; })) ++ [ { assertion = cfg.hostId == null || (stringLength cfg.hostId == 8 && isHexString cfg.hostId); @@ -961,9 +1011,10 @@ in "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); - } // listToAttrs (concatLists (flip map (filter (i: i.proxyARP) interfaces) - (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true)) - )); + } // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces) + (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true))) + // listToAttrs (flip map (filter (i: i.preferTempAddress) interfaces) + (i: nameValuePair "net.ipv6.conf.${i.name}.use_tempaddr" 2)); # Capabilities won't work unless we have at-least a 4.3 Linux # kernel because we need the ambient capability @@ -1071,6 +1122,9 @@ in '' + optionalString (i.mtu != null) '' echo "setting MTU to ${toString i.mtu}..." ip link set "${i.name}" mtu "${toString i.mtu}" + '' + '' + echo -n "bringing up interface... " + ip link set "${i.name}" up && echo "done" || (echo "failed"; exit 1) ''; }))); diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix index 7f5b55d5cca0..41dec2af9ed4 100644 --- a/nixos/modules/testing/test-instrumentation.nix +++ b/nixos/modules/testing/test-instrumentation.nix @@ -4,8 +4,11 @@ { config, lib, pkgs, ... }: with lib; +with import ../../lib/qemu-flags.nix { inherit pkgs; }; -let kernel = config.boot.kernelPackages.kernel; in +let + kernel = config.boot.kernelPackages.kernel; +in { @@ -22,8 +25,8 @@ let kernel = config.boot.kernelPackages.kernel; in systemd.services.backdoor = { wantedBy = [ "multi-user.target" ]; - requires = [ "dev-hvc0.device" "dev-ttyS0.device" ]; - after = [ "dev-hvc0.device" "dev-ttyS0.device" ]; + requires = [ "dev-hvc0.device" "dev-${qemuSerialDevice}.device" ]; + after = [ "dev-hvc0.device" "dev-${qemuSerialDevice}.device" ]; script = '' export USER=root @@ -40,7 +43,7 @@ let kernel = config.boot.kernelPackages.kernel; in cd /tmp exec < /dev/hvc0 > /dev/hvc0 - while ! exec 2> /dev/ttyS0; do sleep 0.1; done + while ! exec 2> /dev/${qemuSerialDevice}; do sleep 0.1; done echo "connecting to host..." >&2 stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion echo @@ -49,10 +52,10 @@ let kernel = config.boot.kernelPackages.kernel; in serviceConfig.KillSignal = "SIGHUP"; }; - # Prevent agetty from being instantiated on ttyS0, since it - # interferes with the backdoor (writes to ttyS0 will randomly fail + # Prevent agetty from being instantiated on the serial device, since it + # interferes with the backdoor (writes to it will randomly fail # with EIO). Likewise for hvc0. - systemd.services."serial-getty@ttyS0".enable = false; + systemd.services."serial-getty@${qemuSerialDevice}".enable = false; systemd.services."serial-getty@hvc0".enable = false; boot.initrd.preDeviceCommands = @@ -88,7 +91,7 @@ let kernel = config.boot.kernelPackages.kernel; in # Panic if an error occurs in stage 1 (rather than waiting for # user intervention). boot.kernelParams = - [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ]; + [ "console=${qemuSerialDevice}" "panic=1" "boot.panic_on_fail" ]; # `xwininfo' is used by the test driver to query open windows. environment.systemPackages = [ pkgs.xorg.xwininfo ]; @@ -122,7 +125,7 @@ let kernel = config.boot.kernelPackages.kernel; in # Make it easy to log in as root when running the test interactively. users.extraUsers.root.initialHashedPassword = mkOverride 150 ""; - services.xserver.displayManager.logToJournal = true; + services.xserver.displayManager.job.logToJournal = true; }; } diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix index 1eb3ca707afd..f74c42a777f5 100644 --- a/nixos/modules/virtualisation/amazon-image.nix +++ b/nixos/modules/virtualisation/amazon-image.nix @@ -11,7 +11,7 @@ with lib; let cfg = config.ec2; in { - imports = [ ../profiles/headless.nix ./ec2-data.nix ./grow-partition.nix ./amazon-init.nix ]; + imports = [ ../profiles/headless.nix ./ec2-data.nix ./amazon-init.nix ]; config = { @@ -21,7 +21,7 @@ let cfg = config.ec2; in } ]; - virtualisation.growPartition = cfg.hvm; + boot.growPartition = cfg.hvm; fileSystems."/" = { device = "/dev/disk/by-label/nixos"; @@ -152,5 +152,8 @@ let cfg = config.ec2; in environment.systemPackages = [ pkgs.cryptsetup ]; boot.initrd.supportedFilesystems = [ "unionfs-fuse" ]; + + # EC2 has its own NTP server provided by the hypervisor + networking.timeServers = [ "169.254.169.123" ]; }; } diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix index 08bbcfd9d7c2..39a655b4c104 100644 --- a/nixos/modules/virtualisation/brightbox-image.nix +++ b/nixos/modules/virtualisation/brightbox-image.nix @@ -26,7 +26,7 @@ in rm $diskImageBase popd ''; - diskImageBase = "nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw"; + diskImageBase = "nixos-image-${config.system.nixos.label}-${pkgs.stdenv.system}.raw"; buildInputs = [ pkgs.utillinux pkgs.perl ]; exportReferencesGraph = [ "closure" config.system.build.toplevel ]; diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index b4f9d8b6fc17..5e368acd6d8b 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -11,7 +11,7 @@ with lib; services.udisks2.enable = mkDefault false; powerManagement.enable = mkDefault false; - networking.useHostResolvConf = true; + networking.useHostResolvConf = mkDefault true; # Containers should be light-weight, so start sshd on demand. services.openssh.startWhenNeeded = mkDefault true; diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index e68bfd860601..4038454b2d2f 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -726,6 +726,11 @@ in networking.dhcpcd.denyInterfaces = [ "ve-*" "vb-*" ]; + services.udev.extraRules = optionalString config.networking.networkmanager.enable '' + # Don't manage interfaces created by nixos-container. + ENV{INTERFACE}=="v[eb]-*", ENV{NM_UNMANAGED}="1" + ''; + environment.systemPackages = [ pkgs.nixos-container ]; }); } diff --git a/nixos/modules/virtualisation/ec2-amis.nix b/nixos/modules/virtualisation/ec2-amis.nix index 14826b6272f7..01512911a057 100644 --- a/nixos/modules/virtualisation/ec2-amis.nix +++ b/nixos/modules/virtualisation/ec2-amis.nix @@ -223,21 +223,22 @@ let self = { "17.03".us-west-2.hvm-ebs = "ami-a93daac9"; "17.03".us-west-2.hvm-s3 = "ami-5139ae31"; - # 17.09.1483.d0f0657ca0 - "17.09".eu-west-1.hvm-ebs = "ami-cf33e7b6"; - "17.09".eu-west-2.hvm-ebs = "ami-7d061419"; - "17.09".eu-central-1.hvm-ebs = "ami-7548fa1a"; - "17.09".us-east-1.hvm-ebs = "ami-6f669d15"; - "17.09".us-east-2.hvm-ebs = "ami-cbe1ccae"; - "17.09".us-west-1.hvm-ebs = "ami-9d95a5fd"; - "17.09".us-west-2.hvm-ebs = "ami-d3956fab"; - "17.09".ca-central-1.hvm-ebs = "ami-ee4ef78a"; - "17.09".ap-southeast-1.hvm-ebs = "ami-1dfc807e"; - "17.09".ap-southeast-2.hvm-ebs = "ami-dcb350be"; - "17.09".ap-northeast-1.hvm-ebs = "ami-00ec3d66"; - "17.09".ap-northeast-2.hvm-ebs = "ami-1107dd7f"; - "17.09".sa-east-1.hvm-ebs = "ami-0377086f"; - "17.09".ap-south-1.hvm-ebs = "ami-4a064625"; + # 17.09.2681.59661f21be6 + "17.09".eu-west-1.hvm-ebs = "ami-a30192da"; + "17.09".eu-west-2.hvm-ebs = "ami-295a414d"; + "17.09".eu-west-3.hvm-ebs = "ami-8c0eb9f1"; + "17.09".eu-central-1.hvm-ebs = "ami-266cfe49"; + "17.09".us-east-1.hvm-ebs = "ami-40bee63a"; + "17.09".us-east-2.hvm-ebs = "ami-9d84aff8"; + "17.09".us-west-1.hvm-ebs = "ami-d14142b1"; + "17.09".us-west-2.hvm-ebs = "ami-3eb40346"; + "17.09".ca-central-1.hvm-ebs = "ami-ca8207ae"; + "17.09".ap-southeast-1.hvm-ebs = "ami-84bccff8"; + "17.09".ap-southeast-2.hvm-ebs = "ami-0dc5386f"; + "17.09".ap-northeast-1.hvm-ebs = "ami-89b921ef"; + "17.09".ap-northeast-2.hvm-ebs = "ami-179b3b79"; + "17.09".sa-east-1.hvm-ebs = "ami-4762202b"; + "17.09".ap-south-1.hvm-ebs = "ami-4e376021"; latest = self."17.09"; }; in self diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index e3b3e6a5f4ab..155a33b3bb37 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -6,7 +6,7 @@ let gce = pkgs.google-compute-engine; in { - imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ./grow-partition.nix ]; + imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ]; system.build.googleComputeImage = import ../../lib/make-disk-image.nix { name = "google-compute-image"; @@ -14,7 +14,7 @@ in PATH=$PATH:${pkgs.stdenv.lib.makeBinPath [ pkgs.gnutar pkgs.gzip ]} pushd $out mv $diskImage disk.raw - tar -Szcf nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw.tar.gz disk.raw + tar -Szcf nixos-image-${config.system.nixos.label}-${pkgs.stdenv.system}.raw.tar.gz disk.raw rm $out/disk.raw popd ''; @@ -29,6 +29,7 @@ in autoResize = true; }; + boot.growPartition = true; boot.kernelParams = [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ]; boot.initrd.kernelModules = [ "virtio_scsi" ]; boot.kernelModules = [ "virtio_pci" "virtio_net" ]; @@ -211,7 +212,7 @@ in echo "Obtaining SSH keys..." mkdir -m 0700 -p /root/.ssh AUTH_KEYS=$(${mktemp}) - ${wget} -O $AUTH_KEYS http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys + ${wget} -O $AUTH_KEYS --header="Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/attributes/sshKeys if [ -s $AUTH_KEYS ]; then # Read in key one by one, split in case Google decided diff --git a/nixos/modules/virtualisation/grow-partition.nix b/nixos/modules/virtualisation/grow-partition.nix index 2cb932d208f0..444c0bc1630e 100644 --- a/nixos/modules/virtualisation/grow-partition.nix +++ b/nixos/modules/virtualisation/grow-partition.nix @@ -1,48 +1,3 @@ -# This module automatically grows the root partition on virtual machines. -# This allows an instance to be created with a bigger root filesystem -# than provided by the machine image. - -{ config, lib, pkgs, ... }: - -with lib; - -{ - - options = { - - virtualisation.growPartition = mkOption { - type = types.bool; - default = true; - }; - - }; - - config = mkIf config.virtualisation.growPartition { - - boot.initrd.extraUtilsCommands = '' - copy_bin_and_libs ${pkgs.gawk}/bin/gawk - copy_bin_and_libs ${pkgs.gnused}/bin/sed - copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk - copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk - - substitute "${pkgs.cloud-utils}/bin/.growpart-wrapped" "$out/bin/growpart" \ - --replace "${pkgs.bash}/bin/sh" "/bin/sh" \ - --replace "awk" "gawk" \ - --replace "sed" "gnused" - - ln -s sed $out/bin/gnused - ''; - - boot.initrd.postDeviceCommands = '' - rootDevice="${config.fileSystems."/".device}" - if [ -e "$rootDevice" ]; then - rootDevice="$(readlink -f "$rootDevice")" - parentDevice="$(lsblk -npo PKNAME "$rootDevice")" - TMPDIR=/run sh $(type -P growpart) "$parentDevice" "''${rootDevice#$parentDevice}" - udevadm settle - fi - ''; - - }; - -} +# This profile is deprecated, use boot.growPartition directly. +builtins.trace "the profile <nixos/modules/virtualisation/grow-partition.nix> is deprecated, use boot.growPartition instead" +{ } diff --git a/nixos/modules/virtualisation/hyperv-guest.nix b/nixos/modules/virtualisation/hyperv-guest.nix new file mode 100644 index 000000000000..ecd2a8117710 --- /dev/null +++ b/nixos/modules/virtualisation/hyperv-guest.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.virtualisation.hypervGuest; + +in { + options = { + virtualisation.hypervGuest = { + enable = mkEnableOption "Hyper-V Guest Support"; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ config.boot.kernelPackages.hyperv-daemons.bin ]; + + security.rngd.enable = false; + + # enable hotadding memory + services.udev.packages = lib.singleton (pkgs.writeTextFile { + name = "hyperv-memory-hotadd-udev-rules"; + destination = "/etc/udev/rules.d/99-hyperv-memory-hotadd.rules"; + text = '' + ACTION="add", SUBSYSTEM=="memory", ATTR{state}="online" + ''; + }); + + systemd = { + packages = [ config.boot.kernelPackages.hyperv-daemons.lib ]; + + targets.hyperv-daemons = { + wantedBy = [ "multi-user.target" ]; + }; + }; + }; +} diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index 8aa7ad8e3911..a369b7ddbe1d 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -37,11 +37,13 @@ in { ''; }; - virtualisation.libvirtd.enableKVM = mkOption { - type = types.bool; - default = true; + virtualisation.libvirtd.qemuPackage = mkOption { + type = types.package; + default = pkgs.qemu; description = '' - This option enables support for QEMU/KVM in libvirtd. + Qemu package to use with libvirt. + `pkgs.qemu` can emulate alien architectures (e.g. aarch64 on x86) + `pkgs.qemu_kvm` saves disk space allowing to emulate only host architectures. ''; }; @@ -102,7 +104,7 @@ in { config = mkIf cfg.enable { - environment.systemPackages = with pkgs; [ libvirt netcat-openbsd qemu_kvm ]; + environment.systemPackages = with pkgs; [ libvirt netcat-openbsd cfg.qemuPackage ]; boot.kernelModules = [ "tun" ]; @@ -126,6 +128,7 @@ in { dmidecode dnsmasq ebtables + cfg.qemuPackage # libvirtd requires qemu-img to manage disk images ] ++ optional vswitch.enable vswitch.package; @@ -154,9 +157,9 @@ in { # stable (not GC'able as in /nix/store) paths for using in <emulator> section of xml configs mkdir -p /run/libvirt/nix-emulators - ln -s --force ${pkgs.libvirt}/libexec/libvirt_lxc /run/libvirt/nix-emulators/ - ${optionalString pkgs.stdenv.isAarch64 "ln -s --force ${pkgs.qemu}/bin/qemu-system-aarch64 /run/libvirt/nix-emulators/"} - ${optionalString cfg.enableKVM "ln -s --force ${pkgs.qemu_kvm}/bin/qemu-kvm /run/libvirt/nix-emulators/"} + for emulator in ${pkgs.libvirt}/libexec/libvirt_lxc ${cfg.qemuPackage}/bin/qemu-kvm ${cfg.qemuPackage}/bin/qemu-system-*; do + ln -s --force "$emulator" /run/libvirt/nix-emulators/ + done ${optionalString cfg.qemuOvmf '' mkdir -p /run/libvirt/nix-ovmf diff --git a/nixos/modules/virtualisation/lxcfs.nix b/nixos/modules/virtualisation/lxcfs.nix index 48462dc66da8..b2457403463a 100644 --- a/nixos/modules/virtualisation/lxcfs.nix +++ b/nixos/modules/virtualisation/lxcfs.nix @@ -28,13 +28,9 @@ in { ###### implementation config = mkIf cfg.enable { - services.cgmanager.enable = true; - systemd.services.lxcfs = { description = "FUSE filesystem for LXC"; wantedBy = [ "multi-user.target" ]; - requires = [ "cgmanager.service" ]; - after = [ "cgmanager.service" ]; before = [ "lxc.service" ]; restartIfChanged = false; serviceConfig = { diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix index b1ff0337994e..4988886baf60 100644 --- a/nixos/modules/virtualisation/lxd.nix +++ b/nixos/modules/virtualisation/lxd.nix @@ -38,6 +38,15 @@ in environment.systemPackages = [ pkgs.lxd ]; + security.apparmor = { + enable = true; + profiles = [ + "${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start" + "${pkgs.lxc}/etc/apparmor.d/lxc-containers" + ]; + packages = [ pkgs.lxc ]; + }; + systemd.services.lxd = { description = "LXD Container Management Daemon"; @@ -47,6 +56,10 @@ in # TODO(wkennington): Add lvm2 and thin-provisioning-tools path = with pkgs; [ acl rsync gnutar xz btrfs-progs gzip dnsmasq squashfsTools iproute iptables ]; + preStart = '' + mkdir -m 0755 -p /var/lib/lxc/rootfs + ''; + serviceConfig.ExecStart = "@${pkgs.lxd.bin}/bin/lxd lxd --syslog --group lxd"; serviceConfig.Type = "simple"; serviceConfig.KillMode = "process"; # when stopping, leave the containers alone diff --git a/nixos/modules/virtualisation/nova-config.nix b/nixos/modules/virtualisation/nova-config.nix index c865cf451e40..c1d2a314daf2 100644 --- a/nixos/modules/virtualisation/nova-config.nix +++ b/nixos/modules/virtualisation/nova-config.nix @@ -6,7 +6,6 @@ with lib; imports = [ ../profiles/qemu-guest.nix ../profiles/headless.nix - ./grow-partition.nix ]; config = { @@ -15,8 +14,7 @@ with lib; autoResize = true; }; - virtualisation.growPartition = true; - + boot.growPartition = true; boot.kernelParams = [ "console=ttyS0" ]; boot.loader.grub.device = "/dev/vda"; boot.loader.timeout = 0; diff --git a/nixos/modules/virtualisation/nova.nix b/nixos/modules/virtualisation/nova.nix deleted file mode 100644 index c2837d0e2e24..000000000000 --- a/nixos/modules/virtualisation/nova.nix +++ /dev/null @@ -1,174 +0,0 @@ -# Module for Nova, a.k.a. OpenStack Compute. - -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.virtualisation.nova; - - nova = pkgs.nova; - - novaConf = pkgs.writeText "nova.conf" - '' - --nodaemon - --verbose - ${cfg.extraConfig} - ''; - -in - -{ - - ###### interface - - options = { - - virtualisation.nova.enableSingleNode = - mkOption { - default = false; - description = - '' - This option enables Nova, also known as OpenStack Compute, - a cloud computing system, as a single-machine - installation. That is, all of Nova's components are - enabled on this machine, using SQLite as Nova's database. - This is useful for evaluating and experimenting with Nova. - However, for a real cloud computing environment, you'll - want to enable some of Nova's services on other machines, - and use a database such as MySQL. - ''; - }; - - virtualisation.nova.extraConfig = - mkOption { - default = ""; - description = - '' - Additional text appended to <filename>nova.conf</filename>, - the main Nova configuration file. - ''; - }; - - }; - - - ###### implementation - - config = mkIf cfg.enableSingleNode { - - environment.systemPackages = [ nova pkgs.euca2ools pkgs.novaclient ]; - - environment.etc = - [ { source = novaConf; - target = "nova/nova.conf"; - } - ]; - - # Nova requires libvirtd and RabbitMQ. - virtualisation.libvirtd.enable = true; - services.rabbitmq.enable = true; - - # `qemu-nbd' required the `nbd' kernel module. - boot.kernelModules = [ "nbd" ]; - - system.activationScripts.nova = - '' - mkdir -m 755 -p /var/lib/nova - mkdir -m 755 -p /var/lib/nova/networks - mkdir -m 700 -p /var/lib/nova/instances - mkdir -m 700 -p /var/lib/nova/keys - - # Allow the CA certificate generation script (called by - # nova-api) to work. - mkdir -m 700 -p /var/lib/nova/CA /var/lib/nova/CA/private - - # Initialise the SQLite database. - ${nova}/bin/nova-manage db sync - ''; - - # `nova-api' receives and executes external client requests from - # tools such as euca2ools. It listens on port 8773 (XML) and 8774 - # (JSON). - jobs.nova_api = - { name = "nova-api"; - - description = "Nova API service"; - - startOn = "ip-up"; - - # `openssl' is required to generate the CA. `openssh' is - # required to generate key pairs. - path = [ pkgs.openssl config.programs.ssh.package pkgs.bash ]; - - respawn = false; - - exec = "${nova}/bin/nova-api --flagfile=${novaConf} --api_paste_config=${nova}/etc/nova/api-paste.ini"; - }; - - # `nova-objectstore' is a simple image server. Useful if you're - # not running the OpenStack Imaging Service (Swift). It serves - # images placed in /var/lib/nova/images/. - jobs.nova_objectstore = - { name = "nova-objectstore"; - - description = "Nova Simple Object Store Service"; - - startOn = "ip-up"; - - preStart = - '' - mkdir -m 700 -p /var/lib/nova/images - ''; - - exec = "${nova}/bin/nova-objectstore --flagfile=${novaConf}"; - }; - - # `nova-scheduler' schedules VM execution requests. - jobs.nova_scheduler = - { name = "nova-scheduler"; - - description = "Nova Scheduler Service"; - - startOn = "ip-up"; - - exec = "${nova}/bin/nova-scheduler --flagfile=${novaConf}"; - }; - - # `nova-compute' starts and manages virtual machines. - jobs.nova_compute = - { name = "nova-compute"; - - description = "Nova Compute Service"; - - startOn = "ip-up"; - - path = - [ pkgs.sudo pkgs.vlan pkgs.nettools pkgs.iptables pkgs.qemu_kvm - pkgs.e2fsprogs pkgs.utillinux pkgs.multipath-tools pkgs.iproute - pkgs.bridge-utils - ]; - - exec = "${nova}/bin/nova-compute --flagfile=${novaConf}"; - }; - - # `nova-network' manages networks and allocates IP addresses. - jobs.nova_network = - { name = "nova-network"; - - description = "Nova Network Service"; - - startOn = "ip-up"; - - path = - [ pkgs.sudo pkgs.vlan pkgs.dnsmasq pkgs.nettools pkgs.iptables - pkgs.iproute pkgs.bridge-utils pkgs.radvd - ]; - - exec = "${nova}/bin/nova-network --flagfile=${novaConf}"; - }; - - }; - -} diff --git a/nixos/modules/virtualisation/openstack/common.nix b/nixos/modules/virtualisation/openstack/common.nix deleted file mode 100644 index 2feb0a873951..000000000000 --- a/nixos/modules/virtualisation/openstack/common.nix +++ /dev/null @@ -1,84 +0,0 @@ -{ lib }: - -with lib; - -rec { - # A shell script string helper to get the value of a secret at - # runtime. - getSecret = secretOption: - if secretOption.storage == "fromFile" - then ''$(cat ${secretOption.value})'' - else ''${secretOption.value}''; - - - # A shell script string help to replace at runtime in a file the - # pattern of a secret by its value. - replaceSecret = secretOption: filename: '' - sed -i "s/${secretOption.pattern}/${getSecret secretOption}/g" ${filename} - ''; - - # This generates an option that can be used to declare secrets which - # can be stored in the nix store, or not. A pattern is written in - # the nix store to represent the secret. The pattern can - # then be overwritten with the value of the secret at runtime. - mkSecretOption = {name, description ? ""}: - mkOption { - description = description; - type = types.submodule ({ - options = { - pattern = mkOption { - type = types.str; - default = "##${name}##"; - description = "The pattern that represent the secret."; - }; - storage = mkOption { - type = types.enum [ "fromNixStore" "fromFile" ]; - description = '' - Choose the way the password is provisionned. If - fromNixStore is used, the value is the password and it is - written in the nix store. If fromFile is used, the value - is a path from where the password will be read at - runtime. This is generally used with <link - xlink:href="https://nixos.org/nixops/manual/#opt-deployment.keys"> - deployment keys</link> of Nixops. - '';}; - value = mkOption { - type = types.str; - description = '' - If the storage is fromNixStore, the value is the password itself, - otherwise it is a path to the file that contains the password. - ''; - }; - };}); - }; - - databaseOption = name: { - host = mkOption { - type = types.str; - default = "localhost"; - description = '' - Host of the database. - ''; - }; - - name = mkOption { - type = types.str; - default = name; - description = '' - Name of the existing database. - ''; - }; - - user = mkOption { - type = types.str; - default = name; - description = '' - The database user. The user must exist and has access to - the specified database. - ''; - }; - password = mkSecretOption { - name = name + "MysqlPassword"; - description = "The database user's password";}; - }; -} diff --git a/nixos/modules/virtualisation/openstack/glance.nix b/nixos/modules/virtualisation/openstack/glance.nix deleted file mode 100644 index 7862409a65ec..000000000000 --- a/nixos/modules/virtualisation/openstack/glance.nix +++ /dev/null @@ -1,245 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; with import ./common.nix {inherit lib;}; - -let - cfg = config.virtualisation.openstack.glance; - commonConf = '' - [database] - connection = "mysql://${cfg.database.user}:${cfg.database.password.pattern}@${cfg.database.host}/${cfg.database.name}" - notification_driver = noop - - [keystone_authtoken] - auth_url = ${cfg.authUrl} - auth_plugin = password - project_name = service - project_domain_id = default - user_domain_id = default - username = ${cfg.serviceUsername} - password = ${cfg.servicePassword.pattern} - - [glance_store] - default_store = file - filesystem_store_datadir = /var/lib/glance/images/ - ''; - glanceApiConfTpl = pkgs.writeText "glance-api.conf" '' - ${commonConf} - - [paste_deploy] - flavor = keystone - config_file = ${cfg.package}/etc/glance-api-paste.ini - ''; - glanceRegistryConfTpl = pkgs.writeText "glance-registry.conf" '' - ${commonConf} - - [paste_deploy] - config_file = ${cfg.package}/etc/glance-registry-paste.ini - ''; - glanceApiConf = "/var/lib/glance/glance-api.conf"; - glanceRegistryConf = "/var/lib/glance/glance-registry.conf"; - -in { - options.virtualisation.openstack.glance = { - package = mkOption { - type = types.package; - default = pkgs.glance; - defaultText = "pkgs.glance"; - description = '' - Glance package to use. - ''; - }; - - enable = mkOption { - default = false; - type = types.bool; - description = '' - This option enables Glance as a single-machine - installation. That is, all of Glance's components are - enabled on this machine. This is useful for evaluating and - experimenting with Glance. Note we are currently not - providing any configurations for a multi-node setup. - ''; - }; - - authUrl = mkOption { - type = types.str; - default = http://localhost:5000; - description = '' - Complete public Identity (Keystone) API endpoint. Note this is - unversionned. - ''; - }; - - serviceUsername = mkOption { - type = types.str; - default = "glance"; - description = '' - The Glance service username. This user is created if bootstrap - is enable, otherwise it has to be manually created before - starting this service. - ''; - }; - - servicePassword = mkSecretOption { - name = "glanceAdminPassword"; - description = '' - The Glance service user's password. - ''; - }; - - database = databaseOption "glance"; - - bootstrap = { - enable = mkOption { - default = false; - type = types.bool; - description = '' - Bootstrap the Glance service by creating the service tenant, - an admin account and a public endpoint. This option provides - a ready-to-use glance service. This is only done at the - first Glance execution by the systemd post start section. - The keystone admin account is used to create required - Keystone resource for the Glance service. - - <note><para> This option is a helper for setting up - development or testing environments.</para></note> - ''; - }; - - endpointPublic = mkOption { - type = types.str; - default = "http://localhost:9292"; - description = '' - The public image endpoint. The link <link - xlink:href="http://docs.openstack.org/liberty/install-guide-rdo/keystone-services.html"> - create endpoint</link> provides more informations - about that. - ''; - }; - - keystoneAdminUsername = mkOption { - type = types.str; - default = "admin"; - description = '' - The keystone admin user name used to create the Glance account. - ''; - }; - - keystoneAdminPassword = mkSecretOption { - name = "keystoneAdminPassword"; - description = '' - The keystone admin user's password. - ''; - }; - - keystoneAdminTenant = mkOption { - type = types.str; - default = "admin"; - description = '' - The keystone admin tenant used to create the Glance account. - ''; - }; - keystoneAuthUrl = mkOption { - type = types.str; - default = "http://localhost:5000/v2.0"; - description = '' - The keystone auth url used to create the Glance account. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - users.extraUsers = [{ - name = "glance"; - group = "glance"; - uid = config.ids.gids.glance; - - }]; - users.extraGroups = [{ - name = "glance"; - gid = config.ids.gids.glance; - }]; - - systemd.services.glance-registry = { - description = "OpenStack Glance Registry Daemon"; - after = [ "network.target"]; - path = [ pkgs.curl pkgs.pythonPackages.keystoneclient pkgs.gawk ]; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 775 -p /var/lib/glance/{images,scrubber,image_cache} - chown glance:glance /var/lib/glance/{images,scrubber,image_cache} - - # Secret file managment - cp ${glanceRegistryConfTpl} ${glanceRegistryConf}; - chown glance:glance ${glanceRegistryConf}; - chmod 640 ${glanceRegistryConf} - ${replaceSecret cfg.database.password glanceRegistryConf} - ${replaceSecret cfg.servicePassword glanceRegistryConf} - - cp ${glanceApiConfTpl} ${glanceApiConf}; - chown glance:glance ${glanceApiConf}; - chmod 640 ${glanceApiConf} - ${replaceSecret cfg.database.password glanceApiConf} - ${replaceSecret cfg.servicePassword glanceApiConf} - - # Initialise the database - ${cfg.package}/bin/glance-manage --config-file=${glanceApiConf} --config-file=${glanceRegistryConf} db_sync - ''; - postStart = '' - set -eu - export OS_AUTH_URL=${cfg.bootstrap.keystoneAuthUrl} - export OS_USERNAME=${cfg.bootstrap.keystoneAdminUsername} - export OS_PASSWORD=${getSecret cfg.bootstrap.keystoneAdminPassword} - export OS_TENANT_NAME=${cfg.bootstrap.keystoneAdminTenant} - - # Wait until the keystone is available for use - count=0 - while ! keystone user-get ${cfg.bootstrap.keystoneAdminUsername} > /dev/null - do - if [ $count -eq 30 ] - then - echo "Tried 30 times, giving up..." - exit 1 - fi - - echo "Keystone not yet started. Waiting for 1 second..." - count=$((count++)) - sleep 1 - done - - # If the service glance doesn't exist, we consider glance is - # not initialized - if ! keystone service-get glance - then - keystone service-create --type image --name glance - ID=$(keystone service-get glance | awk '/ id / { print $4 }') - keystone endpoint-create --region RegionOne --service $ID --internalurl http://localhost:9292 --adminurl http://localhost:9292 --publicurl ${cfg.bootstrap.endpointPublic} - - keystone user-create --name ${cfg.serviceUsername} --tenant service --pass ${getSecret cfg.servicePassword} - keystone user-role-add --tenant service --user ${cfg.serviceUsername} --role admin - fi - ''; - serviceConfig = { - PermissionsStartOnly = true; # preStart must be run as root - TimeoutStartSec = "600"; # 10min for initial db migrations - User = "glance"; - Group = "glance"; - ExecStart = "${cfg.package}/bin/glance-registry --config-file=${glanceRegistryConf}"; - }; - }; - systemd.services.glance-api = { - description = "OpenStack Glance API Daemon"; - after = [ "glance-registry.service" "network.target"]; - requires = [ "glance-registry.service" "network.target"]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - PermissionsStartOnly = true; # preStart must be run as root - User = "glance"; - Group = "glance"; - ExecStart = "${cfg.package}/bin/glance-api --config-file=${glanceApiConf}"; - }; - }; - }; - -} diff --git a/nixos/modules/virtualisation/openstack/keystone.nix b/nixos/modules/virtualisation/openstack/keystone.nix deleted file mode 100644 index e32c5a4cae1b..000000000000 --- a/nixos/modules/virtualisation/openstack/keystone.nix +++ /dev/null @@ -1,220 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; with import ./common.nix {inherit lib;}; - -let - cfg = config.virtualisation.openstack.keystone; - keystoneConfTpl = pkgs.writeText "keystone.conf" '' - [DEFAULT] - admin_token = ${cfg.adminToken.pattern} - policy_file=${cfg.package}/etc/policy.json - - [database] - - connection = "mysql://${cfg.database.user}:${cfg.database.password.pattern}@${cfg.database.host}/${cfg.database.name}" - - [paste_deploy] - config_file = ${cfg.package}/etc/keystone-paste.ini - - ${cfg.extraConfig} - ''; - keystoneConf = "/var/lib/keystone/keystone.conf"; - -in { - options.virtualisation.openstack.keystone = { - package = mkOption { - type = types.package; - example = literalExample "pkgs.keystone"; - description = '' - Keystone package to use. - ''; - }; - - enable = mkOption { - default = false; - type = types.bool; - description = '' - Enable Keystone, the OpenStack Identity Service - ''; - }; - - extraConfig = mkOption { - default = ""; - type = types.lines; - description = '' - Additional text appended to <filename>keystone.conf</filename>, - the main Keystone configuration file. - ''; - }; - - adminToken = mkSecretOption { - name = "adminToken"; - description = '' - This is the admin token used to boostrap keystone, - ie. to provision first resources. - ''; - }; - - bootstrap = { - enable = mkOption { - default = false; - type = types.bool; - description = '' - Bootstrap the Keystone service by creating the service - tenant, an admin account and a public endpoint. This options - provides a ready-to-use admin account. This is only done at - the first Keystone execution by the systemd post start. - - Note this option is a helper for setting up development or - testing environments. - ''; - }; - - endpointPublic = mkOption { - type = types.str; - default = "http://localhost:5000/v2.0"; - description = '' - The public identity endpoint. The link <link - xlink:href="http://docs.openstack.org/liberty/install-guide-rdo/keystone-services.html"> - create keystone endpoint</link> provides more informations - about that. - ''; - }; - - adminUsername = mkOption { - type = types.str; - default = "admin"; - description = '' - A keystone admin username. - ''; - }; - - adminPassword = mkSecretOption { - name = "keystoneAdminPassword"; - description = '' - The keystone admin user's password. - ''; - }; - - adminTenant = mkOption { - type = types.str; - default = "admin"; - description = '' - A keystone admin tenant name. - ''; - }; - }; - - database = { - host = mkOption { - type = types.str; - default = "localhost"; - description = '' - Host of the database. - ''; - }; - - name = mkOption { - type = types.str; - default = "keystone"; - description = '' - Name of the existing database. - ''; - }; - - user = mkOption { - type = types.str; - default = "keystone"; - description = '' - The database user. The user must exist and has access to - the specified database. - ''; - }; - password = mkSecretOption { - name = "mysqlPassword"; - description = "The database user's password";}; - }; - }; - - config = mkIf cfg.enable { - # Note: when changing the default, make it conditional on - # ‘system.stateVersion’ to maintain compatibility with existing - # systems! - virtualisation.openstack.keystone.package = mkDefault pkgs.keystone; - - users.extraUsers = [{ - name = "keystone"; - group = "keystone"; - uid = config.ids.uids.keystone; - }]; - users.extraGroups = [{ - name = "keystone"; - gid = config.ids.gids.keystone; - }]; - - systemd.services.keystone-all = { - description = "OpenStack Keystone Daemon"; - after = [ "network.target"]; - path = [ cfg.package pkgs.mysql pkgs.curl pkgs.pythonPackages.keystoneclient pkgs.gawk ]; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 755 -p /var/lib/keystone - - cp ${keystoneConfTpl} ${keystoneConf}; - chown keystone:keystone ${keystoneConf}; - chmod 640 ${keystoneConf} - - ${replaceSecret cfg.database.password keystoneConf} - ${replaceSecret cfg.adminToken keystoneConf} - - # Initialise the database - ${cfg.package}/bin/keystone-manage --config-file=${keystoneConf} db_sync - # Set up the keystone's PKI infrastructure - ${cfg.package}/bin/keystone-manage --config-file=${keystoneConf} pki_setup --keystone-user keystone --keystone-group keystone - ''; - postStart = optionalString cfg.bootstrap.enable '' - set -eu - # Wait until the keystone is available for use - count=0 - while ! curl --fail -s http://localhost:35357/v2.0 > /dev/null - do - if [ $count -eq 30 ] - then - echo "Tried 30 times, giving up..." - exit 1 - fi - - echo "Keystone not yet started. Waiting for 1 second..." - count=$((count++)) - sleep 1 - done - - # We use the service token to create a first admin user - export OS_SERVICE_ENDPOINT=http://localhost:35357/v2.0 - export OS_SERVICE_TOKEN=${getSecret cfg.adminToken} - - # If the tenant service doesn't exist, we consider - # keystone is not initialized - if ! keystone tenant-get service - then - keystone tenant-create --name service - keystone tenant-create --name ${cfg.bootstrap.adminTenant} - keystone user-create --name ${cfg.bootstrap.adminUsername} --tenant ${cfg.bootstrap.adminTenant} --pass ${getSecret cfg.bootstrap.adminPassword} - keystone role-create --name admin - keystone role-create --name Member - keystone user-role-add --tenant ${cfg.bootstrap.adminTenant} --user ${cfg.bootstrap.adminUsername} --role admin - keystone service-create --type identity --name keystone - ID=$(keystone service-get keystone | awk '/ id / { print $4 }') - keystone endpoint-create --region RegionOne --service $ID --publicurl ${cfg.bootstrap.endpointPublic} --adminurl http://localhost:35357/v2.0 --internalurl http://localhost:5000/v2.0 - fi - ''; - serviceConfig = { - PermissionsStartOnly = true; # preStart must be run as root - TimeoutStartSec = "600"; # 10min for initial db migrations - User = "keystone"; - Group = "keystone"; - ExecStart = "${cfg.package}/bin/keystone-all --config-file=${keystoneConf}"; - }; - }; - }; -} diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 3c89ca68113b..13d0eb7de5c2 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -10,6 +10,7 @@ { config, lib, pkgs, ... }: with lib; +with import ../../lib/qemu-flags.nix { inherit pkgs; }; let @@ -23,7 +24,7 @@ let cfg = config.virtualisation; qemuGraphics = if cfg.graphics then "" else "-nographic"; - kernelConsole = if cfg.graphics then "" else "console=ttyS0"; + kernelConsole = if cfg.graphics then "" else "console=${qemuSerialDevice}"; ttys = [ "tty1" "tty2" "tty3" "tty4" "tty5" "tty6" ]; # Shell script to start the VM. @@ -72,11 +73,10 @@ let '')} # Start QEMU. - exec ${qemu}/bin/qemu-kvm \ + exec ${qemuBinary qemu} \ -name ${vmName} \ -m ${toString config.virtualisation.memorySize} \ -smp ${toString config.virtualisation.cores} \ - ${optionalString (pkgs.stdenv.system == "x86_64-linux") "-cpu kvm64"} \ ${concatStringsSep " " config.virtualisation.qemu.networkingOptions} \ -virtfs local,path=/nix/store,security_model=none,mount_tag=store \ -virtfs local,path=$TMPDIR/xchg,security_model=none,mount_tag=xchg \ @@ -434,7 +434,9 @@ in virtualisation.pathsInNixDB = [ config.system.build.toplevel ]; - virtualisation.qemu.options = [ "-vga std" "-usbdevice tablet" ]; + # FIXME: Figure out how to make this work on non-x86 + virtualisation.qemu.options = + mkIf (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [ "-vga std" "-usbdevice tablet" ]; # Mount the host filesystem via 9P, and bind-mount the Nix store # of the host into our own filesystem. We use mkVMOverride to diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix index bb0c38bd4eb8..7413e12c8f3d 100644 --- a/nixos/modules/virtualisation/virtualbox-host.nix +++ b/nixos/modules/virtualisation/virtualbox-host.nix @@ -124,7 +124,7 @@ in ''; }; - networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ]; + networking.interfaces.vboxnet0.ipv4.addresses = [{ address = "192.168.56.1"; prefixLength = 24; }]; # Make sure NetworkManager won't assume this interface being up # means we have internet access. networking.networkmanager.unmanaged = ["vboxnet0"]; diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index d68b3bb73904..64f145f77ca3 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -8,8 +8,6 @@ let in { - imports = [ ./grow-partition.nix ]; - options = { virtualbox = { baseImageSize = mkOption { @@ -23,12 +21,11 @@ in { }; config = { - system.build.virtualBoxOVA = import ../../lib/make-disk-image.nix { - name = "nixos-ova-${config.system.nixosLabel}-${pkgs.stdenv.system}"; + name = "nixos-ova-${config.system.nixos.label}-${pkgs.stdenv.system}"; inherit pkgs lib config; - partitioned = true; + partitionTableType = "legacy"; diskSize = cfg.baseImageSize; postVM = @@ -40,7 +37,7 @@ in { VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage echo "creating VirtualBox VM..." - vmName="NixOS ${config.system.nixosLabel} (${pkgs.stdenv.system})" + vmName="NixOS ${config.system.nixos.label} (${pkgs.stdenv.system})" VBoxManage createvm --name "$vmName" --register \ --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"} VBoxManage modifyvm "$vmName" \ @@ -56,7 +53,7 @@ in { echo "exporting VirtualBox VM..." mkdir -p $out - fn="$out/nixos-${config.system.nixosLabel}-${pkgs.stdenv.system}.ova" + fn="$out/nixos-${config.system.nixos.label}-${pkgs.stdenv.system}.ova" VBoxManage export "$vmName" --output "$fn" rm -v $diskImage @@ -71,6 +68,7 @@ in { autoResize = true; }; + boot.growPartition = true; boot.loader.grub.device = "/dev/sda"; virtualisation.virtualbox.guest.enable = true; diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index c7656bc309c0..afc5a42f8b4e 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -35,24 +35,19 @@ in description = '' The package used for Xen binary. ''; + relatedPackages = [ "xen" "xen-light" ]; }; - virtualisation.xen.qemu = mkOption { - type = types.path; - defaultText = "\${pkgs.xen}/lib/xen/bin/qemu-system-i386"; - example = literalExample "''${pkgs.qemu_xen-light}/bin/qemu-system-i386"; - description = '' - The qemu binary to use for Dom-0 backend. - ''; - }; - - virtualisation.xen.qemu-package = mkOption { + virtualisation.xen.package-qemu = mkOption { type = types.package; defaultText = "pkgs.xen"; example = literalExample "pkgs.qemu_xen-light"; description = '' - The package with qemu binaries for xendomains. + The package with qemu binaries for dom0 qemu and xendomains. ''; + relatedPackages = [ "xen" + { name = "qemu_xen-light"; comment = "For use with pkgs.xen-light."; } + ]; }; virtualisation.xen.bootParams = @@ -158,8 +153,7 @@ in } ]; virtualisation.xen.package = mkDefault pkgs.xen; - virtualisation.xen.qemu = mkDefault "${pkgs.xen}/lib/xen/bin/qemu-system-i386"; - virtualisation.xen.qemu-package = mkDefault pkgs.xen; + virtualisation.xen.package-qemu = mkDefault pkgs.xen; virtualisation.xen.stored = mkDefault "${cfg.package}/bin/oxenstored"; environment.systemPackages = [ cfg.package ]; @@ -339,7 +333,8 @@ in after = [ "xen-console.service" ]; requires = [ "xen-store.service" ]; serviceConfig.ExecStart = '' - ${cfg.qemu} -xen-attach -xen-domid 0 -name dom0 -M xenpv \ + ${cfg.package-qemu}/${cfg.package-qemu.qemu-system-i386} \ + -xen-attach -xen-domid 0 -name dom0 -M xenpv \ -nographic -monitor /dev/null -serial /dev/null -parallel /dev/null ''; }; @@ -448,7 +443,7 @@ in before = [ "dhcpd.service" ]; restartIfChanged = false; serviceConfig.RemainAfterExit = "yes"; - path = [ cfg.package cfg.qemu-package ]; + path = [ cfg.package cfg.package-qemu ]; environment.XENDOM_CONFIG = "${cfg.package}/etc/sysconfig/xendomains"; preStart = "mkdir -p /var/lock/subsys -m 755"; serviceConfig.ExecStart = "${cfg.package}/etc/init.d/xendomains start"; |